131457Sminshall #include <sys/types.h>
2*31798Sminshall #include <sys/inode.h>
3*31798Sminshall #include <sys/file.h>
4*31798Sminshall #include <sys/time.h>
531457Sminshall #include <sys/socket.h>
631457Sminshall #include <netinet/in.h>
731455Sminshall #include <sys/wait.h>
831455Sminshall 
931457Sminshall #include <errno.h>
1031457Sminshall extern int errno;
1131457Sminshall 
1231457Sminshall #include <netdb.h>
1331457Sminshall #include <signal.h>
1431455Sminshall #include <stdio.h>
1531457Sminshall #include <pwd.h>
1631455Sminshall 
1731455Sminshall #include "../general/general.h"
1831455Sminshall #include "../api/api.h"
1931463Sminshall #include "../apilib/api_exch.h"
2031455Sminshall 
2131455Sminshall #include "../general/globals.h"
2231455Sminshall 
2331795Sminshall #ifndef	FD_SETSIZE
2431795Sminshall /*
2531795Sminshall  * The following is defined just in case someone should want to run
2631795Sminshall  * this telnet on a 4.2 system.
2731795Sminshall  *
2831795Sminshall  */
2931455Sminshall 
3031795Sminshall #define	FD_SET(n, p)	((p)->fds_bits[0] |= (1<<(n)))
3131795Sminshall #define	FD_CLR(n, p)	((p)->fds_bits[0] &= ~(1<<(n)))
3231795Sminshall #define	FD_ISSET(n, p)	((p)->fds_bits[0] & (1<<(n)))
3331795Sminshall #define FD_ZERO(p)	((p)->fds_bits[0] = 0)
3431795Sminshall 
3531795Sminshall #endif
3631795Sminshall 
3731455Sminshall static int shell_pid = 0;
38*31798Sminshall static char key[50];			/* Actual key */
39*31798Sminshall static char *keyname;			/* Name of file with key in it */
4031455Sminshall 
4131457Sminshall static char *ourENVlist[200];		/* Lots of room */
4231457Sminshall 
4331465Sminshall static int
4431465Sminshall     sock = -1,				/* Connected socket */
4531465Sminshall     serversock;				/* Server (listening) socket */
4631457Sminshall 
4731457Sminshall static enum { DEAD, UNCONNECTED, CONNECTED } state;
4831457Sminshall 
4931455Sminshall static int
5031463Sminshall     storage_location,		/* Address we have */
5131457Sminshall     storage_length = 0,		/* Length we have */
5231457Sminshall     storage_must_send = 0,	/* Storage belongs on other side of wire */
5331457Sminshall     storage_accessed = 0;	/* The storage is accessed (so leave alone)! */
5431457Sminshall 
5531503Sminshall static long storage[1000];
5631457Sminshall 
5731463Sminshall static union REGS inputRegs;
5831463Sminshall static struct SREGS inputSregs;
5931457Sminshall 
6031463Sminshall 
6131463Sminshall static void
6231457Sminshall kill_connection()
6331457Sminshall {
6431465Sminshall     state = UNCONNECTED;
6531465Sminshall     if (sock != -1) {
6631465Sminshall 	(void) close(sock);
6731465Sminshall 	sock = -1;
6831465Sminshall     }
6931457Sminshall }
7031457Sminshall 
7131457Sminshall 
7231457Sminshall static int
7331463Sminshall nextstore()
7431455Sminshall {
7531463Sminshall     struct storage_descriptor sd;
7631455Sminshall 
7731463Sminshall     if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
7831457Sminshall 	storage_length = 0;
7931457Sminshall 	return -1;
8031457Sminshall     }
81*31798Sminshall     storage_length = sd.length;
82*31798Sminshall     storage_location = sd.location;
8331463Sminshall     if (storage_length > sizeof storage) {
8431457Sminshall 	fprintf(stderr, "API client tried to send too much storage (%d).\n",
8531457Sminshall 		storage_length);
8631463Sminshall 	storage_length = 0;
8731457Sminshall 	return -1;
8831457Sminshall     }
8931511Sminshall     if (api_exch_intype(EXCH_TYPE_BYTES, storage_length, (char *)storage)
9031511Sminshall 							== -1) {
9131511Sminshall 	storage_length = 0;
9231511Sminshall 	return -1;
9331463Sminshall     }
9431471Sminshall     return 0;
9531457Sminshall }
9631457Sminshall 
9731457Sminshall 
9831457Sminshall static int
9931457Sminshall doreject(message)
10031457Sminshall char	*message;
10131457Sminshall {
10231463Sminshall     struct storage_descriptor sd;
10331457Sminshall     int length = strlen(message);
10431457Sminshall 
10531492Sminshall     if (api_exch_outcommand(EXCH_CMD_REJECTED) == -1) {
10631457Sminshall 	return -1;
10731457Sminshall     }
108*31798Sminshall     sd.length = length;
10931465Sminshall     if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
11031463Sminshall 	return -1;
11131463Sminshall     }
11231463Sminshall     if (api_exch_outtype(EXCH_TYPE_BYTES, length, message) == -1) {
11331463Sminshall 	return -1;
11431463Sminshall     }
11531457Sminshall     return 0;
11631457Sminshall }
11731457Sminshall 
11831457Sminshall 
11931455Sminshall /*
12031465Sminshall  * doassociate()
12131457Sminshall  *
12231457Sminshall  * Negotiate with the other side and try to do something.
123*31798Sminshall  *
124*31798Sminshall  * Returns:
125*31798Sminshall  *
126*31798Sminshall  *	-1:	Error in processing
127*31798Sminshall  *	 0:	Invalid password entered
128*31798Sminshall  *	 1:	Association OK
12931457Sminshall  */
13031457Sminshall 
13131457Sminshall static int
13231465Sminshall doassociate()
13331457Sminshall {
13431457Sminshall     struct passwd *pwent;
13531457Sminshall     char
13631457Sminshall 	promptbuf[100],
13731457Sminshall 	buffer[200];
13831457Sminshall     int length;
13931457Sminshall     int was;
14031463Sminshall     struct storage_descriptor sd;
14131457Sminshall 
14231463Sminshall     if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
14331463Sminshall 	return -1;
14431457Sminshall     }
145*31798Sminshall     sd.length = sd.length;
14631463Sminshall     if (sd.length > sizeof buffer) {
147*31798Sminshall 	doreject("(internal error) Authentication key too long");
14831465Sminshall 	return -1;
14931457Sminshall     }
15031463Sminshall     if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) {
15131457Sminshall 	return -1;
15231457Sminshall     }
15331463Sminshall     buffer[sd.length] = 0;
15431457Sminshall 
155*31798Sminshall     if (strcmp(buffer, key) != 0) {
156*31798Sminshall 	if ((pwent = getpwuid(geteuid())) == 0) {
157*31798Sminshall 	    return -1;
158*31798Sminshall 	}
159*31798Sminshall 	sprintf(promptbuf, "Enter password for user %s:", pwent->pw_name);
160*31798Sminshall 	if (api_exch_outcommand(EXCH_CMD_SEND_AUTH) == -1) {
161*31798Sminshall 	    return -1;
162*31798Sminshall 	}
163*31798Sminshall 	sd.length = strlen(promptbuf);
164*31798Sminshall 	if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd)
165*31798Sminshall 									== -1) {
166*31798Sminshall 	    return -1;
167*31798Sminshall 	}
168*31798Sminshall 	if (api_exch_outtype(EXCH_TYPE_BYTES, strlen(promptbuf), promptbuf)
169*31798Sminshall 									== -1) {
170*31798Sminshall 	    return -1;
171*31798Sminshall 	}
172*31798Sminshall 	sd.length = strlen(pwent->pw_name);
173*31798Sminshall 	if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd)
174*31798Sminshall 									== -1) {
175*31798Sminshall 	    return -1;
176*31798Sminshall 	}
177*31798Sminshall 	if (api_exch_outtype(EXCH_TYPE_BYTES,
178*31798Sminshall 			    strlen(pwent->pw_name), pwent->pw_name) == -1) {
179*31798Sminshall 	    return -1;
180*31798Sminshall 	}
181*31798Sminshall 	if (api_exch_incommand(EXCH_CMD_AUTH) == -1) {
182*31798Sminshall 	    return -1;
183*31798Sminshall 	}
184*31798Sminshall 	if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd)
185*31798Sminshall 									== -1) {
186*31798Sminshall 	    return -1;
187*31798Sminshall 	}
188*31798Sminshall 	sd.length = sd.length;
189*31798Sminshall 	if (sd.length > sizeof buffer) {
190*31798Sminshall 	    doreject("Password entered was too long");
191*31798Sminshall 	    return -1;
192*31798Sminshall 	}
193*31798Sminshall 	if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) {
194*31798Sminshall 	    return -1;
195*31798Sminshall 	}
196*31798Sminshall 	buffer[sd.length] = 0;
19731465Sminshall 
198*31798Sminshall 	/* Is this the correct password? */
199*31798Sminshall 	if (strlen(pwent->pw_name)) {
200*31798Sminshall 	    char *ptr;
201*31798Sminshall 	    int i;
202*31798Sminshall 
203*31798Sminshall 	    ptr = pwent->pw_name;
204*31798Sminshall 	    i = 0;
205*31798Sminshall 	    while (i < sd.length) {
206*31798Sminshall 		buffer[i++] ^= *ptr++;
207*31798Sminshall 		if (*ptr == 0) {
208*31798Sminshall 		    ptr = pwent->pw_name;
209*31798Sminshall 		}
21031465Sminshall 	    }
21131465Sminshall 	}
212*31798Sminshall 	if (strcmp(crypt(buffer, pwent->pw_passwd), pwent->pw_passwd) != 0) {
213*31798Sminshall 	    doreject("Invalid password");
214*31798Sminshall 	    sleep(10);		/* Don't let us do too many of these */
215*31798Sminshall 	    return 0;
216*31798Sminshall 	}
21731465Sminshall     }
218*31798Sminshall     if (api_exch_outcommand(EXCH_CMD_ASSOCIATED) == -1) {
219*31798Sminshall 	return -1;
22031457Sminshall     } else {
221*31798Sminshall 	return 1;
22231457Sminshall     }
22331457Sminshall }
22431457Sminshall 
22531457Sminshall 
22631457Sminshall void
22731457Sminshall freestorage()
22831457Sminshall {
22931457Sminshall     char buffer[40];
23031463Sminshall     struct storage_descriptor sd;
23131457Sminshall 
23231457Sminshall     if (storage_accessed) {
23331457Sminshall 	fprintf(stderr, "Internal error - attempt to free accessed storage.\n");
23431503Sminshall 	fprintf(stderr, "(Encountered in file %s at line %d.)\n",
23531457Sminshall 			__FILE__, __LINE__);
23631457Sminshall 	quit();
23731457Sminshall     }
23831457Sminshall     if (storage_must_send == 0) {
23931457Sminshall 	return;
24031457Sminshall     }
24131457Sminshall     storage_must_send = 0;
24231492Sminshall     if (api_exch_outcommand(EXCH_CMD_HEREIS) == -1) {
24331457Sminshall 	kill_connection();
24431457Sminshall 	return;
24531457Sminshall     }
246*31798Sminshall     sd.length = storage_length;
247*31798Sminshall     sd.location = storage_location;
24831463Sminshall     if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
24931457Sminshall 	kill_connection();
25031457Sminshall 	return;
25131457Sminshall     }
25231511Sminshall     if (api_exch_outtype(EXCH_TYPE_BYTES, storage_length, (char *)storage)
25331511Sminshall 							    == -1) {
25431511Sminshall 	kill_connection();
25531511Sminshall 	return;
25631463Sminshall     }
25731457Sminshall }
25831457Sminshall 
25931457Sminshall 
26031463Sminshall static int
26131508Sminshall getstorage(address, length, copyin)
26231508Sminshall int
26331508Sminshall     address,
26431508Sminshall     length,
26531508Sminshall     copyin;
26631457Sminshall {
26731463Sminshall     struct storage_descriptor sd;
26831457Sminshall     char buffer[40];
26931457Sminshall 
27031457Sminshall     freestorage();
27131457Sminshall     if (storage_accessed) {
27231457Sminshall 	fprintf(stderr,
27331457Sminshall 		"Internal error - attempt to get while storage accessed.\n");
27431503Sminshall 	fprintf(stderr, "(Encountered in file %s at line %d.)\n",
27531457Sminshall 			__FILE__, __LINE__);
27631457Sminshall 	quit();
27731457Sminshall     }
27831457Sminshall     storage_must_send = 0;
27931492Sminshall     if (api_exch_outcommand(EXCH_CMD_GIMME) == -1) {
28031457Sminshall 	kill_connection();
28131463Sminshall 	return -1;
28231457Sminshall     }
28331471Sminshall     storage_location = address;
28431471Sminshall     storage_length = length;
28531508Sminshall     if (copyin) {
286*31798Sminshall 	sd.location = storage_location;
287*31798Sminshall 	sd.length = storage_length;
28831508Sminshall 	if (api_exch_outtype(EXCH_TYPE_STORE_DESC,
28931508Sminshall 					sizeof sd, (char *)&sd) == -1) {
29031508Sminshall 	    kill_connection();
29131508Sminshall 	    return -1;
29231508Sminshall 	}
29331508Sminshall 	if (api_exch_incommand(EXCH_CMD_HEREIS) == -1) {
29431508Sminshall 	    fprintf(stderr, "Bad data from other side.\n");
29531508Sminshall 	    fprintf(stderr, "(Encountered at %s, %d.)\n", __FILE__, __LINE__);
29631508Sminshall 	    return -1;
29731508Sminshall 	}
29831508Sminshall 	if (nextstore() == -1) {
29931508Sminshall 	    kill_connection();
30031508Sminshall 	    return -1;
30131508Sminshall 	}
30231463Sminshall     }
30331463Sminshall     return 0;
30431457Sminshall }
30531457Sminshall 
30631457Sminshall void
30731457Sminshall movetous(local, es, di, length)
30831457Sminshall char
30931457Sminshall     *local;
31031457Sminshall int
31131457Sminshall     es,
31231457Sminshall     di;
31331457Sminshall int
31431457Sminshall     length;
31531457Sminshall {
31631457Sminshall     if (length > sizeof storage) {
31731457Sminshall 	fprintf(stderr, "Internal API error - movetous() length too long.\n");
31831457Sminshall 	fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__);
31931457Sminshall 	quit();
32031457Sminshall     } else if (length == 0) {
32131457Sminshall 	return;
32231457Sminshall     }
32331508Sminshall     getstorage(di, length, 1);
32431463Sminshall     memcpy(local, storage+(di-storage_location), length);
32531457Sminshall }
32631457Sminshall 
32731457Sminshall void
32831457Sminshall movetothem(es, di, local, length)
32931457Sminshall int
33031457Sminshall     es,
33131457Sminshall     di;
33231457Sminshall char
33331457Sminshall     *local;
33431457Sminshall int
33531457Sminshall     length;
33631457Sminshall {
33731457Sminshall     if (length > sizeof storage) {
33831457Sminshall 	fprintf(stderr, "Internal API error - movetothem() length too long.\n");
33931457Sminshall 	fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__);
34031457Sminshall 	quit();
34131457Sminshall     } else if (length == 0) {
34231457Sminshall 	return;
34331457Sminshall     }
34431457Sminshall     freestorage();
34531457Sminshall     memcpy((char *)storage, local, length);
34631457Sminshall     storage_length = length;
34731463Sminshall     storage_location = di;
34831457Sminshall     storage_must_send = 1;
34931457Sminshall }
35031457Sminshall 
35131457Sminshall 
35231457Sminshall char *
35331508Sminshall access_api(location, length, copyin)
35431457Sminshall int
35531457Sminshall     location,
35631508Sminshall     length,
35731508Sminshall     copyin;			/* Do we need to copy in initially? */
35831457Sminshall {
35931457Sminshall     if (storage_accessed) {
36031457Sminshall 	fprintf(stderr, "Internal error - storage accessed twice\n");
36131503Sminshall 	fprintf(stderr, "(Encountered in file %s, line %d.)\n",
36231457Sminshall 				__FILE__, __LINE__);
36331457Sminshall 	quit();
36431457Sminshall     } else if (length != 0) {
36531457Sminshall 	freestorage();
36631508Sminshall 	getstorage(location, length, copyin);
36731503Sminshall 	storage_accessed = 1;
36831457Sminshall     }
36931457Sminshall     return (char *) storage;
37031457Sminshall }
37131457Sminshall 
37231508Sminshall unaccess_api(location, local, length, copyout)
37331457Sminshall int	location;
37431457Sminshall char	*local;
37531457Sminshall int	length;
37631457Sminshall {
37731457Sminshall     if (storage_accessed == 0) {
37831457Sminshall 	fprintf(stderr, "Internal error - unnecessary unaccess_api call.\n");
37931503Sminshall 	fprintf(stderr, "(Encountered in file %s, line %d.)\n",
38031457Sminshall 			__FILE__, __LINE__);
38131457Sminshall 	quit();
38231457Sminshall     }
38331457Sminshall     storage_accessed = 0;
38431508Sminshall     storage_must_send = copyout;	/* if needs to go back */
38531457Sminshall }
38631457Sminshall 
38731465Sminshall /*
38831465Sminshall  * Accept a connection from an API client, aborting if the child dies.
38931465Sminshall  */
39031457Sminshall 
39131465Sminshall static int
39231465Sminshall doconnect()
39331465Sminshall {
39431465Sminshall     fd_set fdset;
39531465Sminshall     int i;
39631465Sminshall 
39731465Sminshall     sock = -1;
39831465Sminshall     FD_ZERO(&fdset);
39931465Sminshall     while (shell_active && (sock == -1)) {
40031465Sminshall 	FD_SET(serversock, &fdset);
40131465Sminshall 	if ((i = select(serversock+1, &fdset, 0, 0, 0)) < 0) {
40231465Sminshall 	    if (errno = EINTR) {
40331465Sminshall 		continue;
40431465Sminshall 	    } else {
40531465Sminshall 		perror("in select waiting for API connection");
40631465Sminshall 		return -1;
40731465Sminshall 	    }
40831465Sminshall 	} else {
40931465Sminshall 	    i = accept(serversock, 0, 0);
41031465Sminshall 	    if (i == -1) {
41131465Sminshall 		perror("accepting API connection");
41231465Sminshall 		return -1;
41331465Sminshall 	    }
41431465Sminshall 	    sock = i;
41531465Sminshall 	}
41631465Sminshall     }
41731465Sminshall     /* If the process has already exited, we may need to close */
41831465Sminshall     if ((shell_active == 0) && (sock != -1)) {
41931465Sminshall 	(void) close(sock);
42031465Sminshall 	sock = -1;
42131465Sminshall 	setcommandmode();	/* In case child_died sneaked in */
42231465Sminshall     }
42331465Sminshall }
42431465Sminshall 
42531457Sminshall /*
42631455Sminshall  * shell_continue() actually runs the command, and looks for API
42731455Sminshall  * requests coming back in.
42831455Sminshall  *
42931455Sminshall  * We are called from the main loop in telnet.c.
43031455Sminshall  */
43131455Sminshall 
43231455Sminshall int
43331455Sminshall shell_continue()
43431455Sminshall {
43531492Sminshall     int i;
43631492Sminshall 
43731457Sminshall     switch (state) {
43831457Sminshall     case DEAD:
43931457Sminshall 	pause();			/* Nothing to do */
44031457Sminshall 	break;
44131457Sminshall     case UNCONNECTED:
44231465Sminshall 	if (doconnect() == -1) {
44331457Sminshall 	    kill_connection();
44431465Sminshall 	    return -1;
44531465Sminshall 	}
44631492Sminshall 	if (api_exch_init(sock, "server") == -1) {
44731465Sminshall 	    return -1;
44831465Sminshall 	}
44931465Sminshall 	while (state == UNCONNECTED) {
45031492Sminshall 	    if (api_exch_incommand(EXCH_CMD_ASSOCIATE) == -1) {
45131457Sminshall 		kill_connection();
45231465Sminshall 		return -1;
45331465Sminshall 	    } else {
45431465Sminshall 		switch (doassociate()) {
45531465Sminshall 		case -1:
45631465Sminshall 		    kill_connection();
45731465Sminshall 		    return -1;
45831465Sminshall 		case 0:
45931465Sminshall 		    break;
46031465Sminshall 		case 1:
46131465Sminshall 		    state = CONNECTED;
46231465Sminshall 		}
46331457Sminshall 	    }
46431457Sminshall 	}
46531457Sminshall 	break;
46631457Sminshall     case CONNECTED:
46731492Sminshall 	switch (i = api_exch_nextcommand()) {
46831492Sminshall 	case EXCH_CMD_REQUEST:
46931492Sminshall 	    if (api_exch_intype(EXCH_TYPE_REGS, sizeof inputRegs,
47031492Sminshall 				    (char *)&inputRegs) == -1) {
47131463Sminshall 		kill_connection();
47231492Sminshall 	    } else if (api_exch_intype(EXCH_TYPE_SREGS, sizeof inputSregs,
47331492Sminshall 				    (char *)&inputSregs) == -1) {
47431463Sminshall 		kill_connection();
47531492Sminshall 	    } else if (nextstore() == -1) {
47631463Sminshall 		kill_connection();
47731492Sminshall 	    } else {
47831492Sminshall 		handle_api(&inputRegs, &inputSregs);
47931492Sminshall 		freestorage();			/* Send any storage back */
48031492Sminshall 		if (api_exch_outcommand(EXCH_CMD_REPLY) == -1) {
48131492Sminshall 		    kill_connection();
48231492Sminshall 		} else if (api_exch_outtype(EXCH_TYPE_REGS, sizeof inputRegs,
48331492Sminshall 				    (char *)&inputRegs) == -1) {
48431492Sminshall 		    kill_connection();
48531492Sminshall 		} else if (api_exch_outtype(EXCH_TYPE_SREGS, sizeof inputSregs,
48631492Sminshall 				    (char *)&inputSregs) == -1) {
48731492Sminshall 		    kill_connection();
48831492Sminshall 		}
48931492Sminshall 		/* Done, and it all worked! */
49031463Sminshall 	    }
49131492Sminshall 	    break;
49231492Sminshall 	case EXCH_CMD_DISASSOCIATE:
49331492Sminshall 	    kill_connection();
49431492Sminshall 	    break;
49531492Sminshall 	default:
49631503Sminshall 	    if (i != -1) {
49731503Sminshall 		fprintf(stderr,
49831503Sminshall 			"Looking for a REQUEST or DISASSOCIATE command\n");
49931503Sminshall 		fprintf(stderr, "\treceived 0x%02x.\n", i);
50031503Sminshall 	    }
50131492Sminshall 	    kill_connection();
50231503Sminshall 	    break;
50331457Sminshall 	}
50431457Sminshall     }
50531455Sminshall     return shell_active;
50631455Sminshall }
50731455Sminshall 
50831455Sminshall 
50931463Sminshall static int
51031463Sminshall child_died()
51131463Sminshall {
51231463Sminshall     union wait *status;
51331463Sminshall     register int pid;
51431463Sminshall 
51531463Sminshall     while ((pid = wait3(&status, WNOHANG, 0)) > 0) {
51631463Sminshall 	if (pid == shell_pid) {
51731463Sminshall 	    char inputbuffer[100];
51831463Sminshall 
51931463Sminshall 	    shell_active = 0;
52031463Sminshall 	    if (sock != -1) {
52131463Sminshall 		(void) close(sock);
52231463Sminshall 		sock = -1;
52331463Sminshall 	    }
52431471Sminshall 	    printf("[Hit return to continue]");
52531471Sminshall 	    fflush(stdout);
52631471Sminshall 	    (void) gets(inputbuffer);
52731465Sminshall 	    setconnmode();
52831465Sminshall 	    ConnectScreen();	/* Turn screen on (if need be) */
52931465Sminshall 	    (void) close(serversock);
530*31798Sminshall 	    (void) unlink(keyname);
53131463Sminshall 	}
53231463Sminshall     }
53331463Sminshall     signal(SIGCHLD, child_died);
53431463Sminshall }
53531463Sminshall 
53631463Sminshall 
53731455Sminshall /*
53831455Sminshall  * Called from telnet.c to fork a lower command.com.  We
53931455Sminshall  * use the spint... routines so that we can pick up
54031455Sminshall  * interrupts generated by application programs.
54131455Sminshall  */
54231455Sminshall 
54331455Sminshall 
54431455Sminshall int
54531455Sminshall shell(argc,argv)
54631455Sminshall int	argc;
54731455Sminshall char	*argv[];
54831455Sminshall {
54931465Sminshall     int length;
55031457Sminshall     struct sockaddr_in server;
55131457Sminshall     char sockNAME[100];
55231457Sminshall     static char **whereAPI = 0;
553*31798Sminshall     int fd;
554*31798Sminshall     struct timeval tv;
555*31798Sminshall     long ikey;
556*31798Sminshall     extern long random();
557*31798Sminshall     extern char *mktemp();
55831457Sminshall 
559*31798Sminshall     /* First, create verification file. */
560*31798Sminshall     do {
561*31798Sminshall 	keyname = mktemp("/tmp/apiXXXXXX");
562*31798Sminshall 	fd = open(keyname, O_RDWR|O_CREAT|O_EXCL, IREAD|IWRITE);
563*31798Sminshall     } while ((fd == -1) && (errno == EEXIST));
564*31798Sminshall 
565*31798Sminshall     if (fd == -1) {
566*31798Sminshall 	perror("open");
567*31798Sminshall 	return 0;
568*31798Sminshall     }
569*31798Sminshall 
570*31798Sminshall     /* Now, get seed for random */
571*31798Sminshall 
572*31798Sminshall     if (gettimeofday(&tv, 0) == -1) {
573*31798Sminshall 	perror("gettimeofday");
574*31798Sminshall 	return 0;
575*31798Sminshall     }
576*31798Sminshall     srandom(tv.tv_usec);		/* seed random number generator */
577*31798Sminshall     do {
578*31798Sminshall 	ikey = random();
579*31798Sminshall     } while (ikey == 0);
580*31798Sminshall     sprintf(key, "%lu\n", ikey);
581*31798Sminshall     if (write(fd, key, strlen(key)) != strlen(key)) {
582*31798Sminshall 	perror("write");
583*31798Sminshall 	return 0;
584*31798Sminshall     }
585*31798Sminshall     key[strlen(key)-1] = 0;		/* Get rid of newline */
586*31798Sminshall 
587*31798Sminshall     if (close(fd) == -1) {
588*31798Sminshall 	perror("close");
589*31798Sminshall 	return 0;
590*31798Sminshall     }
591*31798Sminshall 
592*31798Sminshall     /* Next, create the socket which will be connected to */
59331457Sminshall     serversock = socket(AF_INET, SOCK_STREAM, 0);
59431457Sminshall     if (serversock < 0) {
59531457Sminshall 	perror("opening API socket");
59631457Sminshall 	return 0;
59731457Sminshall     }
59831457Sminshall     server.sin_family = AF_INET;
59931457Sminshall     server.sin_addr.s_addr = INADDR_ANY;
60031457Sminshall     server.sin_port = 0;
60131457Sminshall     if (bind(serversock, &server, sizeof server) < 0) {
60231457Sminshall 	perror("binding API socket");
60331457Sminshall 	return 0;
60431457Sminshall     }
60531457Sminshall     length = sizeof server;
60631457Sminshall     if (getsockname(serversock, &server, &length) < 0) {
60731457Sminshall 	perror("getting API socket name");
60831457Sminshall 	(void) close(serversock);
60931457Sminshall     }
61031457Sminshall     listen(serversock, 1);
61131457Sminshall     /* Get name to advertise in address list */
61231457Sminshall     strcpy(sockNAME, "API3270=");
61331457Sminshall     gethostname(sockNAME+strlen(sockNAME), sizeof sockNAME-strlen(sockNAME));
614*31798Sminshall     if (strlen(sockNAME) > (sizeof sockNAME-(10+strlen(keyname)))) {
61531457Sminshall 	fprintf(stderr, "Local hostname too large; using 'localhost'.\n");
61631457Sminshall 	strcpy(sockNAME, "localhost");
61731457Sminshall     }
61831457Sminshall     sprintf(sockNAME+strlen(sockNAME), ":%d", ntohs(server.sin_port));
619*31798Sminshall     sprintf(sockNAME+strlen(sockNAME), ":%s", keyname);
62031457Sminshall 
62131457Sminshall     if (whereAPI == 0) {
62231457Sminshall 	char **ptr, **nextenv;
62331457Sminshall 	extern char **environ;
62431457Sminshall 
62531457Sminshall 	ptr = environ;
62631457Sminshall 	nextenv = ourENVlist;
62731457Sminshall 	while (*ptr) {
62831457Sminshall 	    if (nextenv >= &ourENVlist[highestof(ourENVlist)-1]) {
62931457Sminshall 		fprintf(stderr, "Too many environmental variables\n");
63031457Sminshall 		break;
63131457Sminshall 	    }
63231457Sminshall 	    *nextenv++ = *ptr++;
63331457Sminshall 	}
63431457Sminshall 	whereAPI = nextenv++;
63531457Sminshall 	*nextenv++ = 0;
63631457Sminshall 	environ = ourENVlist;		/* New environment */
63731457Sminshall     }
63831457Sminshall     *whereAPI = sockNAME;
63931457Sminshall 
64031457Sminshall     child_died();			/* Start up signal handler */
64131457Sminshall     shell_active = 1;			/* We are running down below */
64231457Sminshall     if (shell_pid = vfork()) {
64331457Sminshall 	if (shell_pid == -1) {
64431457Sminshall 	    perror("vfork");
64531457Sminshall 	    (void) close(serversock);
64631457Sminshall 	} else {
64731465Sminshall 	    state = UNCONNECTED;
64831457Sminshall 	}
64931455Sminshall     } else {				/* New process */
65031455Sminshall 	register int i;
65131455Sminshall 
65231455Sminshall 	for (i = 3; i < 30; i++) {
65331455Sminshall 	    (void) close(i);
65431455Sminshall 	}
65531455Sminshall 	if (argc == 1) {		/* Just get a shell */
65631455Sminshall 	    char *cmdname;
65731457Sminshall 	    extern char *getenv();
65831455Sminshall 
65931455Sminshall 	    cmdname = getenv("SHELL");
66031455Sminshall 	    execlp(cmdname, cmdname, 0);
66131455Sminshall 	    perror("Exec'ing new shell...\n");
66231455Sminshall 	    exit(1);
66331455Sminshall 	} else {
66431455Sminshall 	    execvp(argv[1], &argv[1]);
66531455Sminshall 	    perror("Exec'ing command.\n");
66631455Sminshall 	    exit(1);
66731455Sminshall 	}
66831455Sminshall 	/*NOTREACHED*/
66931455Sminshall     }
67031457Sminshall     return shell_active;		/* Go back to main loop */
67131455Sminshall }
672