131457Sminshall #include <sys/types.h>
231457Sminshall #include <sys/socket.h>
331457Sminshall #include <netinet/in.h>
431455Sminshall #include <sys/wait.h>
531455Sminshall 
631457Sminshall #include <errno.h>
731457Sminshall extern int errno;
831457Sminshall 
931457Sminshall #include <netdb.h>
1031457Sminshall #include <signal.h>
1131455Sminshall #include <stdio.h>
1231457Sminshall #include <pwd.h>
1331455Sminshall 
1431455Sminshall #include "../general/general.h"
1531455Sminshall #include "../api/api.h"
16*31463Sminshall #include "../apilib/api_exch.h"
1731455Sminshall 
1831455Sminshall #include "../general/globals.h"
1931455Sminshall 
2031455Sminshall 
2131455Sminshall static int shell_pid = 0;
2231455Sminshall 
2331457Sminshall static char *ourENVlist[200];		/* Lots of room */
2431457Sminshall 
2531457Sminshall static int sock = -1;
2631457Sminshall 
2731457Sminshall static enum { DEAD, UNCONNECTED, CONNECTED } state;
2831457Sminshall 
2931455Sminshall static int
30*31463Sminshall     storage_location,		/* Address we have */
3131457Sminshall     storage_length = 0,		/* Length we have */
3231457Sminshall     storage_must_send = 0,	/* Storage belongs on other side of wire */
3331457Sminshall     storage_accessed = 0;	/* The storage is accessed (so leave alone)! */
3431457Sminshall 
3531457Sminshall static long storage[250];
3631457Sminshall 
37*31463Sminshall static union REGS inputRegs;
38*31463Sminshall static struct SREGS inputSregs;
3931457Sminshall 
40*31463Sminshall 
41*31463Sminshall static void
4231457Sminshall kill_connection()
4331457Sminshall {
4431457Sminshall     state = DEAD;
4531457Sminshall     (void) close(sock);
4631457Sminshall     sock = -1;
4731457Sminshall }
4831457Sminshall 
4931457Sminshall 
5031457Sminshall static int
51*31463Sminshall nextstore()
5231455Sminshall {
53*31463Sminshall     struct storage_descriptor sd;
5431455Sminshall 
55*31463Sminshall     if (api_exch_incommand(EXCH_HEREIS) == -1) {
5631457Sminshall 	fprintf(stderr, "Bad data from other side.\n");
5731457Sminshall 	fprintf(stderr, "(Encountered at %s, %s.)\n", __FILE__, __LINE__);
5831457Sminshall 	return -1;
5931457Sminshall     }
60*31463Sminshall     if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
6131457Sminshall 	storage_length = 0;
6231457Sminshall 	return -1;
6331457Sminshall     }
64*31463Sminshall     storage_length = ntohs(sd.length);
65*31463Sminshall     storage_location = ntohl(sd.location);
66*31463Sminshall     if (storage_length > sizeof storage) {
6731457Sminshall 	fprintf(stderr, "API client tried to send too much storage (%d).\n",
6831457Sminshall 		storage_length);
69*31463Sminshall 	storage_length = 0;
7031457Sminshall 	return -1;
7131457Sminshall     }
72*31463Sminshall     if (api_exch_intype(EXCH_TYPE_BYTES, storage_length, (char *)storage) == -1) {
73*31463Sminshall 	storage_length = 0;
74*31463Sminshall 	return -1;
75*31463Sminshall     }
7631457Sminshall }
7731457Sminshall 
7831457Sminshall 
7931457Sminshall static int
8031457Sminshall doreject(message)
8131457Sminshall char	*message;
8231457Sminshall {
83*31463Sminshall     struct storage_descriptor sd;
8431457Sminshall     int length = strlen(message);
8531457Sminshall 
86*31463Sminshall     if (api_exch_outcommand(EXCH_REJECTED) == -1) {
8731457Sminshall 	return -1;
8831457Sminshall     }
89*31463Sminshall     sd.length = htons(length);
90*31463Sminshall     if (api_exch_outtype(EXCH_TYPE_BYTES, sizeof sd, (char *)&sd) == -1) {
91*31463Sminshall 	return -1;
92*31463Sminshall     }
93*31463Sminshall     if (api_exch_outtype(EXCH_TYPE_BYTES, length, message) == -1) {
94*31463Sminshall 	return -1;
95*31463Sminshall     }
9631457Sminshall     return 0;
9731457Sminshall }
9831457Sminshall 
9931457Sminshall 
10031455Sminshall /*
10131457Sminshall  * doconnect()
10231457Sminshall  *
10331457Sminshall  * Negotiate with the other side and try to do something.
10431457Sminshall  */
10531457Sminshall 
10631457Sminshall static int
10731457Sminshall doconnect()
10831457Sminshall {
10931457Sminshall     struct passwd *pwent;
11031457Sminshall     char
11131457Sminshall 	promptbuf[100],
11231457Sminshall 	buffer[200];
11331457Sminshall     int length;
11431457Sminshall     int was;
115*31463Sminshall     struct storage_descriptor sd;
11631457Sminshall 
11731457Sminshall     if ((pwent = getpwuid(geteuid())) == 0) {
11831457Sminshall 	return -1;
11931457Sminshall     }
12031457Sminshall     sprintf(promptbuf, "Enter password for user %s:", pwent->pw_name);
121*31463Sminshall     api_exch_outcommand(EXCH_SEND_AUTH);
122*31463Sminshall     api_exch_outtype(EXCH_TYPE_BYTES, strlen(promptbuf), promptbuf);
123*31463Sminshall     api_exch_outtype(EXCH_TYPE_BYTES, strlen(pwent->pw_name), pwent->pw_name);
124*31463Sminshall     if (api_exch_incommand(EXCH_AUTH) == -1) {
12531457Sminshall 	return -1;
12631457Sminshall     }
127*31463Sminshall     if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
128*31463Sminshall 	return -1;
12931457Sminshall     }
130*31463Sminshall     sd.length = ntohs(sd.length);
131*31463Sminshall     if (sd.length > sizeof buffer) {
13231457Sminshall 	doreject("Password entered was too long");
13331457Sminshall 	return 0;
13431457Sminshall     }
135*31463Sminshall     if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) {
13631457Sminshall 	return -1;
13731457Sminshall     }
138*31463Sminshall     buffer[sd.length] = 0;
13931457Sminshall 
14031457Sminshall     /* Is this the correct password? */
14131457Sminshall     if (strcmp(crypt(buffer, pwent->pw_passwd), pwent->pw_passwd) == 0) {
142*31463Sminshall 	api_exch_outcommand(EXCH_CONNECTED);
14331457Sminshall     } else {
14431457Sminshall 	doreject("Invalid password");
14531457Sminshall 	sleep(10);		/* Don't let us do too many of these */
14631457Sminshall     }
14731457Sminshall     return 0;
14831457Sminshall }
14931457Sminshall 
15031457Sminshall 
15131457Sminshall void
15231457Sminshall freestorage()
15331457Sminshall {
15431457Sminshall     char buffer[40];
155*31463Sminshall     struct storage_descriptor sd;
15631457Sminshall 
15731457Sminshall     if (storage_accessed) {
15831457Sminshall 	fprintf(stderr, "Internal error - attempt to free accessed storage.\n");
15931457Sminshall 	fprintf(stderr, "(Enountered in file %s at line %s.)\n",
16031457Sminshall 			__FILE__, __LINE__);
16131457Sminshall 	quit();
16231457Sminshall     }
16331457Sminshall     if (storage_must_send == 0) {
16431457Sminshall 	return;
16531457Sminshall     }
16631457Sminshall     storage_must_send = 0;
167*31463Sminshall     if (api_exch_outcommand(EXCH_HEREIS) == -1) {
16831457Sminshall 	kill_connection();
16931457Sminshall 	return;
17031457Sminshall     }
171*31463Sminshall     sd.length = htons(storage_length);
172*31463Sminshall     sd.location = htonl(storage_location);
173*31463Sminshall     if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
17431457Sminshall 	kill_connection();
17531457Sminshall 	return;
17631457Sminshall     }
177*31463Sminshall     if (api_exch_outtype(EXCH_TYPE_BYTES, storage_length, (char *)storage) == -1) {
178*31463Sminshall 	kill_connection();
179*31463Sminshall 	return;
180*31463Sminshall     }
18131457Sminshall }
18231457Sminshall 
18331457Sminshall 
184*31463Sminshall static int
18531457Sminshall getstorage(address, length)
18631457Sminshall {
187*31463Sminshall     struct storage_descriptor sd;
18831457Sminshall     char buffer[40];
18931457Sminshall 
19031457Sminshall     freestorage();
19131457Sminshall     if (storage_accessed) {
19231457Sminshall 	fprintf(stderr,
19331457Sminshall 		"Internal error - attempt to get while storage accessed.\n");
19431457Sminshall 	fprintf(stderr, "(Enountered in file %s at line %s.)\n",
19531457Sminshall 			__FILE__, __LINE__);
19631457Sminshall 	quit();
19731457Sminshall     }
19831457Sminshall     if (storage_must_send == 0) {
19931457Sminshall 	return;
20031457Sminshall     }
20131457Sminshall     storage_must_send = 0;
202*31463Sminshall     if (api_exch_outcommand(EXCH_GIMME) == -1) {
20331457Sminshall 	kill_connection();
204*31463Sminshall 	return -1;
20531457Sminshall     }
206*31463Sminshall     sd.location = htonl(storage_location);
207*31463Sminshall     sd.length = htons(storage_length);
208*31463Sminshall     if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
209*31463Sminshall 	kill_connection();
210*31463Sminshall 	return -1;
211*31463Sminshall     }
21231457Sminshall     if (nextstore() == -1) {
21331457Sminshall 	kill_connection();
214*31463Sminshall 	return -1;
21531457Sminshall     }
216*31463Sminshall     return 0;
21731457Sminshall }
21831457Sminshall 
21931457Sminshall void
22031457Sminshall movetous(local, es, di, length)
22131457Sminshall char
22231457Sminshall     *local;
22331457Sminshall int
22431457Sminshall     es,
22531457Sminshall     di;
22631457Sminshall int
22731457Sminshall     length;
22831457Sminshall {
22931457Sminshall     if (length > sizeof storage) {
23031457Sminshall 	fprintf(stderr, "Internal API error - movetous() length too long.\n");
23131457Sminshall 	fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__);
23231457Sminshall 	quit();
23331457Sminshall     } else if (length == 0) {
23431457Sminshall 	return;
23531457Sminshall     }
23631457Sminshall     getstorage(di, length);
237*31463Sminshall     memcpy(local, storage+(di-storage_location), length);
23831457Sminshall }
23931457Sminshall 
24031457Sminshall void
24131457Sminshall movetothem(es, di, local, length)
24231457Sminshall int
24331457Sminshall     es,
24431457Sminshall     di;
24531457Sminshall char
24631457Sminshall     *local;
24731457Sminshall int
24831457Sminshall     length;
24931457Sminshall {
25031457Sminshall     if (length > sizeof storage) {
25131457Sminshall 	fprintf(stderr, "Internal API error - movetothem() length too long.\n");
25231457Sminshall 	fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__);
25331457Sminshall 	quit();
25431457Sminshall     } else if (length == 0) {
25531457Sminshall 	return;
25631457Sminshall     }
25731457Sminshall     freestorage();
25831457Sminshall     memcpy((char *)storage, local, length);
25931457Sminshall     storage_length = length;
260*31463Sminshall     storage_location = di;
26131457Sminshall     storage_must_send = 1;
26231457Sminshall }
26331457Sminshall 
26431457Sminshall 
26531457Sminshall char *
26631457Sminshall access_api(location, length)
26731457Sminshall int
26831457Sminshall     location,
26931457Sminshall     length;
27031457Sminshall {
27131457Sminshall     if (storage_accessed) {
27231457Sminshall 	fprintf(stderr, "Internal error - storage accessed twice\n");
27331457Sminshall 	fprintf(stderr, "(Encountered in file %s, line %s.)\n",
27431457Sminshall 				__FILE__, __LINE__);
27531457Sminshall 	quit();
27631457Sminshall     } else if (length != 0) {
27731457Sminshall 	storage_accessed = 1;
27831457Sminshall 	freestorage();
27931457Sminshall 	getstorage(location, length);
28031457Sminshall     }
28131457Sminshall     return (char *) storage;
28231457Sminshall }
28331457Sminshall 
28431457Sminshall unaccess_api(location, local, length)
28531457Sminshall int	location;
28631457Sminshall char	*local;
28731457Sminshall int	length;
28831457Sminshall {
28931457Sminshall     if (storage_accessed == 0) {
29031457Sminshall 	fprintf(stderr, "Internal error - unnecessary unaccess_api call.\n");
29131457Sminshall 	fprintf(stderr, "(Encountered in file %s, line %s.)\n",
29231457Sminshall 			__FILE__, __LINE__);
29331457Sminshall 	quit();
29431457Sminshall     }
29531457Sminshall     storage_accessed = 0;
29631457Sminshall     storage_must_send = 1;	/* Needs to go back */
29731457Sminshall }
29831457Sminshall 
29931457Sminshall 
30031457Sminshall /*
30131455Sminshall  * shell_continue() actually runs the command, and looks for API
30231455Sminshall  * requests coming back in.
30331455Sminshall  *
30431455Sminshall  * We are called from the main loop in telnet.c.
30531455Sminshall  */
30631455Sminshall 
30731455Sminshall int
30831455Sminshall shell_continue()
30931455Sminshall {
31031457Sminshall     switch (state) {
31131457Sminshall     case DEAD:
31231457Sminshall 	pause();			/* Nothing to do */
31331457Sminshall 	break;
31431457Sminshall     case UNCONNECTED:
315*31463Sminshall 	if (api_exch_incommand(EXCH_CONNECT) == -1) {
31631457Sminshall 	    kill_connection();
31731457Sminshall 	} else {
31831457Sminshall 	    switch (doconnect()) {
31931457Sminshall 	    case -1:
32031457Sminshall 		kill_connection();
32131457Sminshall 		break;
32231457Sminshall 	    case 0:
32331457Sminshall 		break;
32431457Sminshall 	    case 1:
32531457Sminshall 		state = CONNECTED;
32631457Sminshall 	    }
32731457Sminshall 	}
32831457Sminshall 	break;
32931457Sminshall     case CONNECTED:
330*31463Sminshall 	if (api_exch_incommand(EXCH_REQUEST) == -1) {
331*31463Sminshall 	    kill_connection();
332*31463Sminshall 	} else if (api_exch_intype(EXCH_TYPE_BYTES, sizeof inputRegs,
333*31463Sminshall 				(char *)&inputRegs) == -1) {
334*31463Sminshall 	    kill_connection();
335*31463Sminshall 	} else if (api_exch_intype(EXCH_TYPE_BYTES, sizeof inputSregs,
336*31463Sminshall 				(char *)&inputSregs) == -1) {
337*31463Sminshall 	    kill_connection();
338*31463Sminshall 	} else if (nextstore() == -1) {
339*31463Sminshall 	    kill_connection();
340*31463Sminshall 	} else {
34131457Sminshall 	    handle_api(&inputRegs, &inputSregs);
342*31463Sminshall 	    freestorage();			/* Send any storage back */
343*31463Sminshall 	    if (api_exch_outcommand(EXCH_REPLY) == -1) {
344*31463Sminshall 		kill_connection();
345*31463Sminshall 	    } else if (api_exch_outtype(EXCH_TYPE_BYTES, sizeof inputRegs,
346*31463Sminshall 				(char *)&inputRegs) == -1) {
347*31463Sminshall 		kill_connection();
348*31463Sminshall 	    } else if (api_exch_outtype(EXCH_TYPE_BYTES, sizeof inputSregs,
349*31463Sminshall 				(char *)&inputSregs) == -1) {
350*31463Sminshall 		kill_connection();
351*31463Sminshall 	    }
352*31463Sminshall 	    /* Done, and it all worked! */
35331457Sminshall 	}
35431457Sminshall     }
35531455Sminshall     return shell_active;
35631455Sminshall }
35731455Sminshall 
35831455Sminshall 
359*31463Sminshall static int
360*31463Sminshall child_died()
361*31463Sminshall {
362*31463Sminshall     union wait *status;
363*31463Sminshall     register int pid;
364*31463Sminshall 
365*31463Sminshall     while ((pid = wait3(&status, WNOHANG, 0)) > 0) {
366*31463Sminshall 	if (pid == shell_pid) {
367*31463Sminshall 	    char inputbuffer[100];
368*31463Sminshall 
369*31463Sminshall 	    shell_active = 0;
370*31463Sminshall 	    if (sock != -1) {
371*31463Sminshall 		(void) close(sock);
372*31463Sminshall 		sock = -1;
373*31463Sminshall 		printf("[Hit return to continue]");
374*31463Sminshall 		fflush(stdout);
375*31463Sminshall 		(void) gets(inputbuffer);
376*31463Sminshall 		setconnmode();
377*31463Sminshall 		ConnectScreen();	/* Turn screen on (if need be) */
378*31463Sminshall 	    }
379*31463Sminshall 	}
380*31463Sminshall     }
381*31463Sminshall     signal(SIGCHLD, child_died);
382*31463Sminshall }
383*31463Sminshall 
384*31463Sminshall 
38531455Sminshall /*
38631455Sminshall  * Called from telnet.c to fork a lower command.com.  We
38731455Sminshall  * use the spint... routines so that we can pick up
38831455Sminshall  * interrupts generated by application programs.
38931455Sminshall  */
39031455Sminshall 
39131455Sminshall 
39231455Sminshall int
39331455Sminshall shell(argc,argv)
39431455Sminshall int	argc;
39531455Sminshall char	*argv[];
39631455Sminshall {
39731457Sminshall     int serversock, length;
39831457Sminshall     struct sockaddr_in server;
39931457Sminshall     char sockNAME[100];
40031457Sminshall     static char **whereAPI = 0;
40131457Sminshall 
40231457Sminshall     /* First, create the socket which will be connected to */
40331457Sminshall     serversock = socket(AF_INET, SOCK_STREAM, 0);
40431457Sminshall     if (serversock < 0) {
40531457Sminshall 	perror("opening API socket");
40631457Sminshall 	return 0;
40731457Sminshall     }
40831457Sminshall     server.sin_family = AF_INET;
40931457Sminshall     server.sin_addr.s_addr = INADDR_ANY;
41031457Sminshall     server.sin_port = 0;
41131457Sminshall     if (bind(serversock, &server, sizeof server) < 0) {
41231457Sminshall 	perror("binding API socket");
41331457Sminshall 	return 0;
41431457Sminshall     }
41531457Sminshall     length = sizeof server;
41631457Sminshall     if (getsockname(serversock, &server, &length) < 0) {
41731457Sminshall 	perror("getting API socket name");
41831457Sminshall 	(void) close(serversock);
41931457Sminshall     }
42031457Sminshall     listen(serversock, 1);
42131457Sminshall     /* Get name to advertise in address list */
42231457Sminshall     strcpy(sockNAME, "API3270=");
42331457Sminshall     gethostname(sockNAME+strlen(sockNAME), sizeof sockNAME-strlen(sockNAME));
42431457Sminshall     if (strlen(sockNAME) > (sizeof sockNAME-10)) {
42531457Sminshall 	fprintf(stderr, "Local hostname too large; using 'localhost'.\n");
42631457Sminshall 	strcpy(sockNAME, "localhost");
42731457Sminshall     }
42831457Sminshall     sprintf(sockNAME+strlen(sockNAME), ":%d", ntohs(server.sin_port));
42931457Sminshall 
43031457Sminshall     if (whereAPI == 0) {
43131457Sminshall 	char **ptr, **nextenv;
43231457Sminshall 	extern char **environ;
43331457Sminshall 
43431457Sminshall 	ptr = environ;
43531457Sminshall 	nextenv = ourENVlist;
43631457Sminshall 	while (*ptr) {
43731457Sminshall 	    if (nextenv >= &ourENVlist[highestof(ourENVlist)-1]) {
43831457Sminshall 		fprintf(stderr, "Too many environmental variables\n");
43931457Sminshall 		break;
44031457Sminshall 	    }
44131457Sminshall 	    *nextenv++ = *ptr++;
44231457Sminshall 	}
44331457Sminshall 	whereAPI = nextenv++;
44431457Sminshall 	*nextenv++ = 0;
44531457Sminshall 	environ = ourENVlist;		/* New environment */
44631457Sminshall     }
44731457Sminshall     *whereAPI = sockNAME;
44831457Sminshall 
44931457Sminshall     child_died();			/* Start up signal handler */
45031457Sminshall     shell_active = 1;			/* We are running down below */
45131457Sminshall     if (shell_pid = vfork()) {
45231457Sminshall 	if (shell_pid == -1) {
45331457Sminshall 	    perror("vfork");
45431457Sminshall 	    (void) close(serversock);
45531457Sminshall 	} else {
45631457Sminshall 	    fd_set fdset;
45731457Sminshall 	    int i;
45831457Sminshall 
45931457Sminshall 	    FD_ZERO(&fdset);
46031457Sminshall 	    FD_SET(serversock, &fdset);
46131457Sminshall 	    while (shell_active) {
46231457Sminshall 		if ((i = select(serversock+1, &fdset, 0, 0, 0)) < 0) {
46331457Sminshall 		    if (errno = EINTR) {
46431457Sminshall 			continue;
46531457Sminshall 		    } else {
46631457Sminshall 			perror("in select waiting for API connection");
46731457Sminshall 			break;
46831457Sminshall 		    }
46931457Sminshall 		} else {
47031457Sminshall 		    i = accept(serversock, 0, 0);
47131457Sminshall 		    if (i == -1) {
47231457Sminshall 			perror("accepting API connection");
47331457Sminshall 		    }
47431457Sminshall 		    sock = i;
475*31463Sminshall 		    api_exch_init(sock);
476*31463Sminshall 		    state = UNCONNECTED;
47731457Sminshall 		    break;
47831457Sminshall 		}
47931457Sminshall 	    }
48031457Sminshall 	    (void) close(serversock);
48131457Sminshall 	    /* If the process has already exited, we may need to close */
48231457Sminshall 	    if ((shell_active == 0) && (sock != -1)) {
48331457Sminshall 		(void) close(sock);
48431457Sminshall 		sock = -1;
48531457Sminshall 		setcommandmode();	/* In case child_died sneaked in */
48631457Sminshall 	    }
48731457Sminshall 	}
48831455Sminshall     } else {				/* New process */
48931455Sminshall 	register int i;
49031455Sminshall 
49131455Sminshall 	for (i = 3; i < 30; i++) {
49231455Sminshall 	    (void) close(i);
49331455Sminshall 	}
49431455Sminshall 	if (argc == 1) {		/* Just get a shell */
49531455Sminshall 	    char *cmdname;
49631457Sminshall 	    extern char *getenv();
49731455Sminshall 
49831455Sminshall 	    cmdname = getenv("SHELL");
49931455Sminshall 	    execlp(cmdname, cmdname, 0);
50031455Sminshall 	    perror("Exec'ing new shell...\n");
50131455Sminshall 	    exit(1);
50231455Sminshall 	} else {
50331455Sminshall 	    execvp(argv[1], &argv[1]);
50431455Sminshall 	    perror("Exec'ing command.\n");
50531455Sminshall 	    exit(1);
50631455Sminshall 	}
50731455Sminshall 	/*NOTREACHED*/
50831455Sminshall     }
50931457Sminshall     return shell_active;		/* Go back to main loop */
51031455Sminshall }
511