Expand PMF_FN_* macros.
[netbsd-mini2440.git] / usr.bin / tn3270 / sys_curses / system.c
blobde433c897c16b1c15b8a832adb3a2c0b3302424c
1 /* $NetBSD: system.c,v 1.20 2006/05/11 00:27:27 mrg Exp $ */
3 /*-
4 * Copyright (c) 1988 The Regents of the University of California.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)system.c 4.5 (Berkeley) 4/26/91";
36 #else
37 __RCSID("$NetBSD: system.c,v 1.20 2006/05/11 00:27:27 mrg Exp $");
38 #endif
39 #endif /* not lint */
41 #include <sys/types.h>
43 #if defined(pyr)
44 #define fd_set fdset_t
45 #endif /* defined(pyr) */
48 * Wouldn't it be nice if these REALLY were in <sys/inode.h>? Or,
49 * equivalently, if <sys/inode.h> REALLY existed?
51 #define IREAD 00400
52 #define IWRITE 00200
54 #include <sys/time.h>
55 #include <sys/socket.h>
56 #include <sys/poll.h>
57 #include <netinet/in.h>
58 #include <sys/wait.h>
59 #include <errno.h>
60 #include <fcntl.h>
61 #include <netdb.h>
62 #include <pwd.h>
63 #include <signal.h>
64 #include <stdio.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <unistd.h>
69 #include "../general/general.h"
70 #include "../ctlr/api.h"
71 #include "../api/api_exch.h"
72 #include "telextrn.h"
73 #include "externs.h"
75 #include "../general/globals.h"
77 #ifndef FD_SETSIZE
79 * The following is defined just in case someone should want to run
80 * this telnet on a 4.2 system.
84 #define FD_SET(n, p) ((p)->fds_bits[0] |= (1<<(n)))
85 #define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1<<(n)))
86 #define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n)))
87 #define FD_ZERO(p) ((p)->fds_bits[0] = 0)
89 #endif
91 static int shell_pid = 0;
92 static char key[50]; /* Actual key */
93 static char *keyname; /* Name of file with key in it */
95 static char *ourENVlist[200]; /* Lots of room */
97 static int
98 sock = -1, /* Connected socket */
99 serversock; /* Server (listening) socket */
101 static enum { DEAD, UNCONNECTED, CONNECTED } state;
103 static long
104 storage_location; /* Address we have */
105 static short
106 storage_length = 0; /* Length we have */
107 static int
108 storage_must_send = 0, /* Storage belongs on other side of wire */
109 storage_accessed = 0; /* The storage is accessed (so leave alone)! */
111 static long storage[1000];
113 static union REGS inputRegs;
114 static struct SREGS inputSregs;
116 extern int apitrace;
118 static void kill_connection(void);
119 static int nextstore(void);
120 static int doreject(char *);
121 static int doassociate(void);
122 static int getstorage(long, int, int);
123 static int doconnect(void);
124 static void child_died(int);
126 static void
127 kill_connection()
129 state = UNCONNECTED;
130 if (sock != -1) {
131 (void) close(sock);
132 sock = -1;
137 static int
138 nextstore()
140 struct storage_descriptor sd;
142 if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
143 storage_length = 0;
144 return -1;
146 storage_length = sd.length;
147 storage_location = sd.location;
148 if (storage_length > sizeof storage) {
149 fprintf(stderr, "API client tried to send too much storage (%d).\n",
150 storage_length);
151 storage_length = 0;
152 return -1;
154 if (api_exch_intype(EXCH_TYPE_BYTES, storage_length, (char *)storage)
155 == -1) {
156 storage_length = 0;
157 return -1;
159 return 0;
163 static int
164 doreject(message)
165 char *message;
167 struct storage_descriptor sd;
168 int length = strlen(message);
170 if (api_exch_outcommand(EXCH_CMD_REJECTED) == -1) {
171 return -1;
173 sd.length = length;
174 if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
175 return -1;
177 if (api_exch_outtype(EXCH_TYPE_BYTES, length, message) == -1) {
178 return -1;
180 return 0;
185 * doassociate()
187 * Negotiate with the other side and try to do something.
189 * Returns:
191 * -1: Error in processing
192 * 0: Invalid password entered
193 * 1: Association OK
196 static int
197 doassociate()
199 struct passwd *pwent;
200 char
201 promptbuf[100],
202 buffer[200];
203 struct storage_descriptor sd;
205 if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
206 return -1;
208 if (sd.length >= sizeof buffer) {
209 doreject("(internal error) Authentication key too long");
210 return -1;
212 if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) {
213 return -1;
215 buffer[sd.length] = 0;
217 if (strcmp(buffer, key) != 0) {
218 if ((pwent = getpwuid((int)geteuid())) == 0) {
219 return -1;
221 sprintf(promptbuf, "Enter password for user %s:", pwent->pw_name);
222 if (api_exch_outcommand(EXCH_CMD_SEND_AUTH) == -1) {
223 return -1;
225 sd.length = strlen(promptbuf);
226 if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd)
227 == -1) {
228 return -1;
230 if (api_exch_outtype(EXCH_TYPE_BYTES, strlen(promptbuf), promptbuf)
231 == -1) {
232 return -1;
234 sd.length = strlen(pwent->pw_name);
235 if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd)
236 == -1) {
237 return -1;
239 if (api_exch_outtype(EXCH_TYPE_BYTES,
240 strlen(pwent->pw_name), pwent->pw_name) == -1) {
241 return -1;
243 if (api_exch_incommand(EXCH_CMD_AUTH) == -1) {
244 return -1;
246 if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd)
247 == -1) {
248 return -1;
250 sd.length = sd.length;
251 if (sd.length > sizeof buffer) {
252 doreject("Password entered was too long");
253 return -1;
255 if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) {
256 return -1;
258 buffer[sd.length] = 0;
260 /* Is this the correct password? */
261 if (strlen(pwent->pw_name)) {
262 const char *ptr;
263 int i;
265 ptr = pwent->pw_name;
266 i = 0;
267 while (i < sd.length) {
268 buffer[i++] ^= *ptr++;
269 if (*ptr == 0) {
270 ptr = pwent->pw_name;
274 if (strcmp(crypt(buffer, pwent->pw_passwd), pwent->pw_passwd) != 0) {
275 doreject("Invalid password");
276 sleep(10); /* Don't let us do too many of these */
277 return 0;
280 if (api_exch_outcommand(EXCH_CMD_ASSOCIATED) == -1) {
281 return -1;
282 } else {
283 return 1;
288 void
289 freestorage()
291 struct storage_descriptor sd;
293 if (storage_accessed) {
294 fprintf(stderr, "Internal error - attempt to free accessed storage.\n");
295 fprintf(stderr, "(Encountered in file %s at line %d.)\n",
296 __FILE__, __LINE__);
297 quit(0, NULL);
299 if (storage_must_send == 0) {
300 return;
302 storage_must_send = 0;
303 if (api_exch_outcommand(EXCH_CMD_HEREIS) == -1) {
304 kill_connection();
305 return;
307 sd.length = storage_length;
308 sd.location = storage_location;
309 if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
310 kill_connection();
311 return;
313 if (api_exch_outtype(EXCH_TYPE_BYTES, storage_length, (char *)storage)
314 == -1) {
315 kill_connection();
316 return;
321 static int
322 getstorage(address, length, copyin)
323 long
324 address;
326 length,
327 copyin;
329 struct storage_descriptor sd;
331 freestorage();
332 if (storage_accessed) {
333 fprintf(stderr,
334 "Internal error - attempt to get while storage accessed.\n");
335 fprintf(stderr, "(Encountered in file %s at line %d.)\n",
336 __FILE__, __LINE__);
337 quit(0, NULL);
339 storage_must_send = 0;
340 if (api_exch_outcommand(EXCH_CMD_GIMME) == -1) {
341 kill_connection();
342 return -1;
344 storage_location = address;
345 storage_length = length;
346 if (copyin) {
347 sd.location = (long)storage_location;
348 sd.length = storage_length;
349 if (api_exch_outtype(EXCH_TYPE_STORE_DESC,
350 sizeof sd, (char *)&sd) == -1) {
351 kill_connection();
352 return -1;
354 if (api_exch_incommand(EXCH_CMD_HEREIS) == -1) {
355 fprintf(stderr, "Bad data from other side.\n");
356 fprintf(stderr, "(Encountered at %s, %d.)\n", __FILE__, __LINE__);
357 return -1;
359 if (nextstore() == -1) {
360 kill_connection();
361 return -1;
364 return 0;
367 /*ARGSUSED*/
368 void
369 movetous(local, es, di, length)
370 char
371 *local;
372 unsigned int
376 length;
378 long where = SEG_OFF_BACK(es, di);
380 if (length > sizeof storage) {
381 fprintf(stderr, "Internal API error - movetous() length too long.\n");
382 fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__);
383 quit(0, NULL);
384 } else if (length == 0) {
385 return;
387 getstorage(where, length, 1);
388 memcpy(local, (char *)(storage+((where-storage_location))), length);
389 if (apitrace) {
390 Dump('(', local, length);
394 /*ARGSUSED*/
395 void
396 movetothem(es, di, local, length)
397 unsigned int
400 char
401 *local;
403 length;
405 long where = SEG_OFF_BACK(es, di);
407 if (length > sizeof storage) {
408 fprintf(stderr, "Internal API error - movetothem() length too long.\n");
409 fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__);
410 quit(0, NULL);
411 } else if (length == 0) {
412 return;
414 freestorage();
415 memcpy((char *)storage, local, length);
416 if (apitrace) {
417 Dump(')', local, length);
419 storage_length = length;
420 storage_location = where;
421 storage_must_send = 1;
425 char *
426 access_api(location, length, copyin)
427 char *
428 location;
430 length,
431 copyin; /* Do we need to copy in initially? */
433 if (storage_accessed) {
434 fprintf(stderr, "Internal error - storage accessed twice\n");
435 fprintf(stderr, "(Encountered in file %s, line %d.)\n",
436 __FILE__, __LINE__);
437 quit(0, NULL);
438 } else if (length != 0) {
439 freestorage();
440 getstorage((long)location, length, copyin);
441 storage_accessed = 1;
443 return (char *) storage;
446 /*ARGSUSED*/
447 void
448 unaccess_api(location, local, length, copyout)
449 char *location;
450 char *local;
451 int length;
452 int copyout;
454 if (storage_accessed == 0) {
455 fprintf(stderr, "Internal error - unnecessary unaccess_api call.\n");
456 fprintf(stderr, "(Encountered in file %s, line %d.)\n",
457 __FILE__, __LINE__);
458 quit(0, NULL);
460 storage_accessed = 0;
461 storage_must_send = copyout; /* if needs to go back */
465 * Accept a connection from an API client, aborting if the child dies.
468 static int
469 doconnect()
471 struct pollfd set[1];
472 int i;
474 sock = -1;
475 set[0].fd = serversock;
476 set[0].events = POLLIN;
477 while (shell_active && (sock == -1)) {
478 if ((i = poll(set, 1, INFTIM)) < 0) {
479 if (errno == EINTR) {
480 continue;
481 } else {
482 perror("in poll waiting for API connection");
483 return -1;
485 } else {
486 i = accept(serversock, (struct sockaddr *)0, (socklen_t *)0);
487 if (i == -1) {
488 perror("accepting API connection");
489 return -1;
491 sock = i;
494 /* If the process has already exited, we may need to close */
495 if ((shell_active == 0) && (sock != -1)) {
497 (void) close(sock);
498 sock = -1;
499 setcommandmode(); /* In case child_died sneaked in */
501 return 0;
505 * shell_continue() actually runs the command, and looks for API
506 * requests coming back in.
508 * We are called from the main loop in telnet.c.
512 shell_continue()
514 int i;
516 switch (state) {
517 case DEAD:
518 pause(); /* Nothing to do */
519 break;
520 case UNCONNECTED:
521 if (doconnect() == -1) {
522 kill_connection();
523 return -1;
525 /* At this point, it is possible that we've gone away */
526 if (shell_active == 0) {
527 kill_connection();
528 return -1;
530 if (api_exch_init(sock, "server") == -1) {
531 return -1;
533 while (state == UNCONNECTED) {
534 if (api_exch_incommand(EXCH_CMD_ASSOCIATE) == -1) {
535 kill_connection();
536 return -1;
537 } else {
538 switch (doassociate()) {
539 case -1:
540 kill_connection();
541 return -1;
542 case 0:
543 break;
544 case 1:
545 state = CONNECTED;
549 break;
550 case CONNECTED:
551 switch (i = api_exch_nextcommand()) {
552 case EXCH_CMD_REQUEST:
553 if (api_exch_intype(EXCH_TYPE_REGS, sizeof inputRegs,
554 (char *)&inputRegs) == -1) {
555 kill_connection();
556 } else if (api_exch_intype(EXCH_TYPE_SREGS, sizeof inputSregs,
557 (char *)&inputSregs) == -1) {
558 kill_connection();
559 } else if (nextstore() == -1) {
560 kill_connection();
561 } else {
562 handle_api(&inputRegs, &inputSregs);
563 freestorage(); /* Send any storage back */
564 if (api_exch_outcommand(EXCH_CMD_REPLY) == -1) {
565 kill_connection();
566 } else if (api_exch_outtype(EXCH_TYPE_REGS, sizeof inputRegs,
567 (char *)&inputRegs) == -1) {
568 kill_connection();
569 } else if (api_exch_outtype(EXCH_TYPE_SREGS, sizeof inputSregs,
570 (char *)&inputSregs) == -1) {
571 kill_connection();
573 /* Done, and it all worked! */
575 break;
576 case EXCH_CMD_DISASSOCIATE:
577 kill_connection();
578 break;
579 default:
580 if (i != -1) {
581 fprintf(stderr,
582 "Looking for a REQUEST or DISASSOCIATE command\n");
583 fprintf(stderr, "\treceived 0x%02x.\n", i);
585 kill_connection();
586 break;
589 return shell_active;
593 static void
594 child_died(code)
595 int code;
597 int pid, status;
599 while ((pid = waitpid((pid_t) -1, &status, WNOHANG)) > 0) {
600 if (pid == shell_pid) {
601 char inputbuffer[100];
603 shell_active = 0;
604 if (sock != -1) {
605 (void) close(sock);
606 sock = -1;
608 printf("[Hit return to continue]");
609 fflush(stdout);
610 (void) fgets(inputbuffer, sizeof(inputbuffer), stdin);
611 setconnmode(0);
612 ConnectScreen(); /* Turn screen on (if need be) */
613 (void) close(serversock);
614 (void) unlink(keyname);
617 signal(SIGCHLD, child_died);
622 * Called from telnet.c to fork a lower command.com. We
623 * use the sprint... routines so that we can pick up
624 * interrupts generated by application programs.
629 shell(argc,argv)
630 int argc;
631 char *argv[];
633 socklen_t length;
634 struct sockaddr_in server;
635 char sockNAME[128];
636 static char **whereAPI = 0;
637 int fd;
638 struct timeval tv;
639 long ikey;
641 /* First, create verification file. */
642 #if defined(BSD4_4)
643 if (keyname != NULL)
644 free(keyname);
645 keyname = strdup("/tmp/apiXXXXXX");
646 fd = mkstemp(keyname);
647 #else
648 do {
649 if (keyname != NULL)
650 free(keyname);
651 keyname = mktemp(strdup("/tmp/apiXXXXXX")); /* NetBSD: NOT USED */
652 fd = open(keyname, O_RDWR|O_CREAT|O_EXCL, IREAD|IWRITE);
653 } while ((fd == -1) && (errno == EEXIST));
654 #endif /* defined(BSD4_4) */
656 if (fd == -1) {
657 perror("open");
658 return 0;
661 /* Now, get seed for random */
663 if (gettimeofday(&tv, (struct timezone *)0) == -1) {
664 perror("gettimeofday");
665 return 0;
667 srandom(tv.tv_usec); /* seed random number generator */
668 do {
669 ikey = random();
670 } while (ikey == 0);
671 sprintf(key, "%lu\n", (unsigned long) ikey);
672 if (write(fd, key, strlen(key)) != strlen(key)) {
673 perror("write");
674 return 0;
676 key[strlen(key)-1] = 0; /* Get rid of newline */
678 if (close(fd) == -1) {
679 perror("close");
680 return 0;
683 /* Next, create the socket which will be connected to */
684 serversock = socket(AF_INET, SOCK_STREAM, 0);
685 if (serversock < 0) {
686 perror("opening API socket");
687 return 0;
689 server.sin_family = AF_INET;
690 server.sin_addr.s_addr = INADDR_ANY;
691 server.sin_port = 0;
692 if (bind(serversock, (struct sockaddr *)&server, sizeof server) < 0) {
693 perror("binding API socket");
694 return 0;
696 length = sizeof server;
697 if (getsockname(serversock, (struct sockaddr *)&server, &length) < 0) {
698 perror("getting API socket name");
699 (void) close(serversock);
701 listen(serversock, 1);
702 /* Get name to advertise in address list */
703 strcpy(sockNAME, "API3270=");
704 gethostname(sockNAME+strlen(sockNAME), sizeof sockNAME-strlen(sockNAME));
705 sockNAME[sizeof(sockNAME) - 1] = '\0';
706 if (strlen(sockNAME) > (sizeof sockNAME-(10+strlen(keyname)))) {
707 fprintf(stderr, "Local hostname too large; using 'localhost'.\n");
708 strcpy(sockNAME, "localhost");
710 sprintf(sockNAME+strlen(sockNAME), ":%u", ntohs(server.sin_port));
711 sprintf(sockNAME+strlen(sockNAME), ":%s", keyname);
713 if (whereAPI == 0) {
714 char **ptr, **nextenv;
715 extern char **environ;
717 ptr = environ;
718 nextenv = ourENVlist;
719 while (*ptr) {
720 if (nextenv >= &ourENVlist[highestof(ourENVlist)-1]) {
721 fprintf(stderr, "Too many environmental variables\n");
722 break;
724 *nextenv++ = *ptr++;
726 whereAPI = nextenv++;
727 *nextenv++ = 0;
728 environ = ourENVlist; /* New environment */
730 *whereAPI = sockNAME;
732 child_died(0); /* Start up signal handler */
733 shell_active = 1; /* We are running down below */
734 if ((shell_pid = vfork()) != 0) {
735 if (shell_pid == -1) {
736 perror("vfork");
737 (void) close(serversock);
738 } else {
739 state = UNCONNECTED;
741 } else { /* New process */
742 int i;
744 for (i = 3; i < 30; i++) {
745 (void) close(i);
747 if (argc == 1) { /* Just get a shell */
748 char *cmdname;
750 cmdname = getenv("SHELL");
751 execlp(cmdname, cmdname, NULL);
752 perror("Exec'ing new shell");
753 _exit(1);
754 } else {
755 execvp(argv[1], &argv[1]);
756 perror("Exec'ing command");
757 _exit(1);
759 /*NOTREACHED*/
761 return shell_active; /* Go back to main loop */