1 /* $NetBSD: system.c,v 1.20 2006/05/11 00:27:27 mrg Exp $ */
4 * Copyright (c) 1988 The Regents of the University of California.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
32 #include <sys/cdefs.h>
35 static char sccsid
[] = "@(#)system.c 4.5 (Berkeley) 4/26/91";
37 __RCSID("$NetBSD: system.c,v 1.20 2006/05/11 00:27:27 mrg Exp $");
41 #include <sys/types.h>
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?
55 #include <sys/socket.h>
57 #include <netinet/in.h>
69 #include "../general/general.h"
70 #include "../ctlr/api.h"
71 #include "../api/api_exch.h"
75 #include "../general/globals.h"
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)
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 */
98 sock
= -1, /* Connected socket */
99 serversock
; /* Server (listening) socket */
101 static enum { DEAD
, UNCONNECTED
, CONNECTED
} state
;
104 storage_location
; /* Address we have */
106 storage_length
= 0; /* Length we have */
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
;
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);
140 struct storage_descriptor sd
;
142 if (api_exch_intype(EXCH_TYPE_STORE_DESC
, sizeof sd
, (char *)&sd
) == -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",
154 if (api_exch_intype(EXCH_TYPE_BYTES
, storage_length
, (char *)storage
)
167 struct storage_descriptor sd
;
168 int length
= strlen(message
);
170 if (api_exch_outcommand(EXCH_CMD_REJECTED
) == -1) {
174 if (api_exch_outtype(EXCH_TYPE_STORE_DESC
, sizeof sd
, (char *)&sd
) == -1) {
177 if (api_exch_outtype(EXCH_TYPE_BYTES
, length
, message
) == -1) {
187 * Negotiate with the other side and try to do something.
191 * -1: Error in processing
192 * 0: Invalid password entered
199 struct passwd
*pwent
;
203 struct storage_descriptor sd
;
205 if (api_exch_intype(EXCH_TYPE_STORE_DESC
, sizeof sd
, (char *)&sd
) == -1) {
208 if (sd
.length
>= sizeof buffer
) {
209 doreject("(internal error) Authentication key too long");
212 if (api_exch_intype(EXCH_TYPE_BYTES
, sd
.length
, buffer
) == -1) {
215 buffer
[sd
.length
] = 0;
217 if (strcmp(buffer
, key
) != 0) {
218 if ((pwent
= getpwuid((int)geteuid())) == 0) {
221 sprintf(promptbuf
, "Enter password for user %s:", pwent
->pw_name
);
222 if (api_exch_outcommand(EXCH_CMD_SEND_AUTH
) == -1) {
225 sd
.length
= strlen(promptbuf
);
226 if (api_exch_outtype(EXCH_TYPE_STORE_DESC
, sizeof sd
, (char *)&sd
)
230 if (api_exch_outtype(EXCH_TYPE_BYTES
, strlen(promptbuf
), promptbuf
)
234 sd
.length
= strlen(pwent
->pw_name
);
235 if (api_exch_outtype(EXCH_TYPE_STORE_DESC
, sizeof sd
, (char *)&sd
)
239 if (api_exch_outtype(EXCH_TYPE_BYTES
,
240 strlen(pwent
->pw_name
), pwent
->pw_name
) == -1) {
243 if (api_exch_incommand(EXCH_CMD_AUTH
) == -1) {
246 if (api_exch_intype(EXCH_TYPE_STORE_DESC
, sizeof sd
, (char *)&sd
)
250 sd
.length
= sd
.length
;
251 if (sd
.length
> sizeof buffer
) {
252 doreject("Password entered was too long");
255 if (api_exch_intype(EXCH_TYPE_BYTES
, sd
.length
, buffer
) == -1) {
258 buffer
[sd
.length
] = 0;
260 /* Is this the correct password? */
261 if (strlen(pwent
->pw_name
)) {
265 ptr
= pwent
->pw_name
;
267 while (i
< sd
.length
) {
268 buffer
[i
++] ^= *ptr
++;
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 */
280 if (api_exch_outcommand(EXCH_CMD_ASSOCIATED
) == -1) {
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",
299 if (storage_must_send
== 0) {
302 storage_must_send
= 0;
303 if (api_exch_outcommand(EXCH_CMD_HEREIS
) == -1) {
307 sd
.length
= storage_length
;
308 sd
.location
= storage_location
;
309 if (api_exch_outtype(EXCH_TYPE_STORE_DESC
, sizeof sd
, (char *)&sd
) == -1) {
313 if (api_exch_outtype(EXCH_TYPE_BYTES
, storage_length
, (char *)storage
)
322 getstorage(address
, length
, copyin
)
329 struct storage_descriptor sd
;
332 if (storage_accessed
) {
334 "Internal error - attempt to get while storage accessed.\n");
335 fprintf(stderr
, "(Encountered in file %s at line %d.)\n",
339 storage_must_send
= 0;
340 if (api_exch_outcommand(EXCH_CMD_GIMME
) == -1) {
344 storage_location
= address
;
345 storage_length
= length
;
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) {
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__
);
359 if (nextstore() == -1) {
369 movetous(local
, es
, di
, 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__
);
384 } else if (length
== 0) {
387 getstorage(where
, length
, 1);
388 memcpy(local
, (char *)(storage
+((where
-storage_location
))), length
);
390 Dump('(', local
, length
);
396 movetothem(es
, di
, local
, 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__
);
411 } else if (length
== 0) {
415 memcpy((char *)storage
, local
, length
);
417 Dump(')', local
, length
);
419 storage_length
= length
;
420 storage_location
= where
;
421 storage_must_send
= 1;
426 access_api(location
, length
, copyin
)
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",
438 } else if (length
!= 0) {
440 getstorage((long)location
, length
, copyin
);
441 storage_accessed
= 1;
443 return (char *) storage
;
448 unaccess_api(location
, local
, length
, 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",
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.
471 struct pollfd set
[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
) {
482 perror("in poll waiting for API connection");
486 i
= accept(serversock
, (struct sockaddr
*)0, (socklen_t
*)0);
488 perror("accepting API connection");
494 /* If the process has already exited, we may need to close */
495 if ((shell_active
== 0) && (sock
!= -1)) {
499 setcommandmode(); /* In case child_died sneaked in */
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.
518 pause(); /* Nothing to do */
521 if (doconnect() == -1) {
525 /* At this point, it is possible that we've gone away */
526 if (shell_active
== 0) {
530 if (api_exch_init(sock
, "server") == -1) {
533 while (state
== UNCONNECTED
) {
534 if (api_exch_incommand(EXCH_CMD_ASSOCIATE
) == -1) {
538 switch (doassociate()) {
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) {
556 } else if (api_exch_intype(EXCH_TYPE_SREGS
, sizeof inputSregs
,
557 (char *)&inputSregs
) == -1) {
559 } else if (nextstore() == -1) {
562 handle_api(&inputRegs
, &inputSregs
);
563 freestorage(); /* Send any storage back */
564 if (api_exch_outcommand(EXCH_CMD_REPLY
) == -1) {
566 } else if (api_exch_outtype(EXCH_TYPE_REGS
, sizeof inputRegs
,
567 (char *)&inputRegs
) == -1) {
569 } else if (api_exch_outtype(EXCH_TYPE_SREGS
, sizeof inputSregs
,
570 (char *)&inputSregs
) == -1) {
573 /* Done, and it all worked! */
576 case EXCH_CMD_DISASSOCIATE
:
582 "Looking for a REQUEST or DISASSOCIATE command\n");
583 fprintf(stderr
, "\treceived 0x%02x.\n", i
);
599 while ((pid
= waitpid((pid_t
) -1, &status
, WNOHANG
)) > 0) {
600 if (pid
== shell_pid
) {
601 char inputbuffer
[100];
608 printf("[Hit return to continue]");
610 (void) fgets(inputbuffer
, sizeof(inputbuffer
), stdin
);
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.
634 struct sockaddr_in server
;
636 static char **whereAPI
= 0;
641 /* First, create verification file. */
645 keyname
= strdup("/tmp/apiXXXXXX");
646 fd
= mkstemp(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) */
661 /* Now, get seed for random */
663 if (gettimeofday(&tv
, (struct timezone
*)0) == -1) {
664 perror("gettimeofday");
667 srandom(tv
.tv_usec
); /* seed random number generator */
671 sprintf(key
, "%lu\n", (unsigned long) ikey
);
672 if (write(fd
, key
, strlen(key
)) != strlen(key
)) {
676 key
[strlen(key
)-1] = 0; /* Get rid of newline */
678 if (close(fd
) == -1) {
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");
689 server
.sin_family
= AF_INET
;
690 server
.sin_addr
.s_addr
= INADDR_ANY
;
692 if (bind(serversock
, (struct sockaddr
*)&server
, sizeof server
) < 0) {
693 perror("binding API socket");
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
);
714 char **ptr
, **nextenv
;
715 extern char **environ
;
718 nextenv
= ourENVlist
;
720 if (nextenv
>= &ourENVlist
[highestof(ourENVlist
)-1]) {
721 fprintf(stderr
, "Too many environmental variables\n");
726 whereAPI
= nextenv
++;
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) {
737 (void) close(serversock
);
741 } else { /* New process */
744 for (i
= 3; i
< 30; i
++) {
747 if (argc
== 1) { /* Just get a shell */
750 cmdname
= getenv("SHELL");
751 execlp(cmdname
, cmdname
, NULL
);
752 perror("Exec'ing new shell");
755 execvp(argv
[1], &argv
[1]);
756 perror("Exec'ing command");
761 return shell_active
; /* Go back to main loop */