131457Sminshall #include <sys/types.h>
2*31863Sminshall 
3*31863Sminshall #if	!defined(sun)
431798Sminshall #include <sys/inode.h>
5*31863Sminshall #else	/* !defined(sun) */
6*31863Sminshall #define	IREAD	00400
7*31863Sminshall #define	IWRITE	00200
8*31863Sminshall #endif	/* !defined(sun) */
9*31863Sminshall 
1031798Sminshall #include <sys/file.h>
1131798Sminshall #include <sys/time.h>
1231457Sminshall #include <sys/socket.h>
1331457Sminshall #include <netinet/in.h>
1431455Sminshall #include <sys/wait.h>
1531455Sminshall 
1631457Sminshall #include <errno.h>
1731457Sminshall extern int errno;
1831457Sminshall 
1931457Sminshall #include <netdb.h>
2031457Sminshall #include <signal.h>
2131455Sminshall #include <stdio.h>
2231457Sminshall #include <pwd.h>
2331455Sminshall 
2431455Sminshall #include "../general/general.h"
2531455Sminshall #include "../api/api.h"
2631463Sminshall #include "../apilib/api_exch.h"
2731455Sminshall 
2831455Sminshall #include "../general/globals.h"
2931455Sminshall 
3031795Sminshall #ifndef	FD_SETSIZE
3131795Sminshall /*
3231795Sminshall  * The following is defined just in case someone should want to run
3331795Sminshall  * this telnet on a 4.2 system.
3431795Sminshall  *
3531795Sminshall  */
3631455Sminshall 
3731795Sminshall #define	FD_SET(n, p)	((p)->fds_bits[0] |= (1<<(n)))
3831795Sminshall #define	FD_CLR(n, p)	((p)->fds_bits[0] &= ~(1<<(n)))
3931795Sminshall #define	FD_ISSET(n, p)	((p)->fds_bits[0] & (1<<(n)))
4031795Sminshall #define FD_ZERO(p)	((p)->fds_bits[0] = 0)
4131795Sminshall 
4231795Sminshall #endif
4331795Sminshall 
4431455Sminshall static int shell_pid = 0;
4531798Sminshall static char key[50];			/* Actual key */
4631798Sminshall static char *keyname;			/* Name of file with key in it */
4731455Sminshall 
4831457Sminshall static char *ourENVlist[200];		/* Lots of room */
4931457Sminshall 
5031465Sminshall static int
5131465Sminshall     sock = -1,				/* Connected socket */
5231465Sminshall     serversock;				/* Server (listening) socket */
5331457Sminshall 
5431457Sminshall static enum { DEAD, UNCONNECTED, CONNECTED } state;
5531457Sminshall 
5631455Sminshall static int
5731463Sminshall     storage_location,		/* Address we have */
5831457Sminshall     storage_length = 0,		/* Length we have */
5931457Sminshall     storage_must_send = 0,	/* Storage belongs on other side of wire */
6031457Sminshall     storage_accessed = 0;	/* The storage is accessed (so leave alone)! */
6131457Sminshall 
6231503Sminshall static long storage[1000];
6331457Sminshall 
6431463Sminshall static union REGS inputRegs;
6531463Sminshall static struct SREGS inputSregs;
6631457Sminshall 
6731463Sminshall 
6831463Sminshall static void
6931457Sminshall kill_connection()
7031457Sminshall {
7131465Sminshall     state = UNCONNECTED;
7231465Sminshall     if (sock != -1) {
7331465Sminshall 	(void) close(sock);
7431465Sminshall 	sock = -1;
7531465Sminshall     }
7631457Sminshall }
7731457Sminshall 
7831457Sminshall 
7931457Sminshall static int
8031463Sminshall nextstore()
8131455Sminshall {
8231463Sminshall     struct storage_descriptor sd;
8331455Sminshall 
8431463Sminshall     if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
8531457Sminshall 	storage_length = 0;
8631457Sminshall 	return -1;
8731457Sminshall     }
8831798Sminshall     storage_length = sd.length;
8931798Sminshall     storage_location = sd.location;
9031463Sminshall     if (storage_length > sizeof storage) {
9131457Sminshall 	fprintf(stderr, "API client tried to send too much storage (%d).\n",
9231457Sminshall 		storage_length);
9331463Sminshall 	storage_length = 0;
9431457Sminshall 	return -1;
9531457Sminshall     }
9631511Sminshall     if (api_exch_intype(EXCH_TYPE_BYTES, storage_length, (char *)storage)
9731511Sminshall 							== -1) {
9831511Sminshall 	storage_length = 0;
9931511Sminshall 	return -1;
10031463Sminshall     }
10131471Sminshall     return 0;
10231457Sminshall }
10331457Sminshall 
10431457Sminshall 
10531457Sminshall static int
10631457Sminshall doreject(message)
10731457Sminshall char	*message;
10831457Sminshall {
10931463Sminshall     struct storage_descriptor sd;
11031457Sminshall     int length = strlen(message);
11131457Sminshall 
11231492Sminshall     if (api_exch_outcommand(EXCH_CMD_REJECTED) == -1) {
11331457Sminshall 	return -1;
11431457Sminshall     }
11531798Sminshall     sd.length = length;
11631465Sminshall     if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
11731463Sminshall 	return -1;
11831463Sminshall     }
11931463Sminshall     if (api_exch_outtype(EXCH_TYPE_BYTES, length, message) == -1) {
12031463Sminshall 	return -1;
12131463Sminshall     }
12231457Sminshall     return 0;
12331457Sminshall }
12431457Sminshall 
12531457Sminshall 
12631455Sminshall /*
12731465Sminshall  * doassociate()
12831457Sminshall  *
12931457Sminshall  * Negotiate with the other side and try to do something.
13031798Sminshall  *
13131798Sminshall  * Returns:
13231798Sminshall  *
13331798Sminshall  *	-1:	Error in processing
13431798Sminshall  *	 0:	Invalid password entered
13531798Sminshall  *	 1:	Association OK
13631457Sminshall  */
13731457Sminshall 
13831457Sminshall static int
13931465Sminshall doassociate()
14031457Sminshall {
14131457Sminshall     struct passwd *pwent;
14231457Sminshall     char
14331457Sminshall 	promptbuf[100],
14431457Sminshall 	buffer[200];
14531457Sminshall     int length;
14631457Sminshall     int was;
14731463Sminshall     struct storage_descriptor sd;
14831457Sminshall 
14931463Sminshall     if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
15031463Sminshall 	return -1;
15131457Sminshall     }
15231798Sminshall     sd.length = sd.length;
15331463Sminshall     if (sd.length > sizeof buffer) {
15431798Sminshall 	doreject("(internal error) Authentication key too long");
15531465Sminshall 	return -1;
15631457Sminshall     }
15731463Sminshall     if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) {
15831457Sminshall 	return -1;
15931457Sminshall     }
16031463Sminshall     buffer[sd.length] = 0;
16131457Sminshall 
16231798Sminshall     if (strcmp(buffer, key) != 0) {
16331798Sminshall 	if ((pwent = getpwuid(geteuid())) == 0) {
16431798Sminshall 	    return -1;
16531798Sminshall 	}
16631798Sminshall 	sprintf(promptbuf, "Enter password for user %s:", pwent->pw_name);
16731798Sminshall 	if (api_exch_outcommand(EXCH_CMD_SEND_AUTH) == -1) {
16831798Sminshall 	    return -1;
16931798Sminshall 	}
17031798Sminshall 	sd.length = strlen(promptbuf);
17131798Sminshall 	if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd)
17231798Sminshall 									== -1) {
17331798Sminshall 	    return -1;
17431798Sminshall 	}
17531798Sminshall 	if (api_exch_outtype(EXCH_TYPE_BYTES, strlen(promptbuf), promptbuf)
17631798Sminshall 									== -1) {
17731798Sminshall 	    return -1;
17831798Sminshall 	}
17931798Sminshall 	sd.length = strlen(pwent->pw_name);
18031798Sminshall 	if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd)
18131798Sminshall 									== -1) {
18231798Sminshall 	    return -1;
18331798Sminshall 	}
18431798Sminshall 	if (api_exch_outtype(EXCH_TYPE_BYTES,
18531798Sminshall 			    strlen(pwent->pw_name), pwent->pw_name) == -1) {
18631798Sminshall 	    return -1;
18731798Sminshall 	}
18831798Sminshall 	if (api_exch_incommand(EXCH_CMD_AUTH) == -1) {
18931798Sminshall 	    return -1;
19031798Sminshall 	}
19131798Sminshall 	if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd)
19231798Sminshall 									== -1) {
19331798Sminshall 	    return -1;
19431798Sminshall 	}
19531798Sminshall 	sd.length = sd.length;
19631798Sminshall 	if (sd.length > sizeof buffer) {
19731798Sminshall 	    doreject("Password entered was too long");
19831798Sminshall 	    return -1;
19931798Sminshall 	}
20031798Sminshall 	if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) {
20131798Sminshall 	    return -1;
20231798Sminshall 	}
20331798Sminshall 	buffer[sd.length] = 0;
20431465Sminshall 
20531798Sminshall 	/* Is this the correct password? */
20631798Sminshall 	if (strlen(pwent->pw_name)) {
20731798Sminshall 	    char *ptr;
20831798Sminshall 	    int i;
20931798Sminshall 
21031798Sminshall 	    ptr = pwent->pw_name;
21131798Sminshall 	    i = 0;
21231798Sminshall 	    while (i < sd.length) {
21331798Sminshall 		buffer[i++] ^= *ptr++;
21431798Sminshall 		if (*ptr == 0) {
21531798Sminshall 		    ptr = pwent->pw_name;
21631798Sminshall 		}
21731465Sminshall 	    }
21831465Sminshall 	}
21931798Sminshall 	if (strcmp(crypt(buffer, pwent->pw_passwd), pwent->pw_passwd) != 0) {
22031798Sminshall 	    doreject("Invalid password");
22131798Sminshall 	    sleep(10);		/* Don't let us do too many of these */
22231798Sminshall 	    return 0;
22331798Sminshall 	}
22431465Sminshall     }
22531798Sminshall     if (api_exch_outcommand(EXCH_CMD_ASSOCIATED) == -1) {
22631798Sminshall 	return -1;
22731457Sminshall     } else {
22831798Sminshall 	return 1;
22931457Sminshall     }
23031457Sminshall }
23131457Sminshall 
23231457Sminshall 
23331457Sminshall void
23431457Sminshall freestorage()
23531457Sminshall {
23631457Sminshall     char buffer[40];
23731463Sminshall     struct storage_descriptor sd;
23831457Sminshall 
23931457Sminshall     if (storage_accessed) {
24031457Sminshall 	fprintf(stderr, "Internal error - attempt to free accessed storage.\n");
24131503Sminshall 	fprintf(stderr, "(Encountered in file %s at line %d.)\n",
24231457Sminshall 			__FILE__, __LINE__);
24331457Sminshall 	quit();
24431457Sminshall     }
24531457Sminshall     if (storage_must_send == 0) {
24631457Sminshall 	return;
24731457Sminshall     }
24831457Sminshall     storage_must_send = 0;
24931492Sminshall     if (api_exch_outcommand(EXCH_CMD_HEREIS) == -1) {
25031457Sminshall 	kill_connection();
25131457Sminshall 	return;
25231457Sminshall     }
25331798Sminshall     sd.length = storage_length;
25431798Sminshall     sd.location = storage_location;
25531463Sminshall     if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
25631457Sminshall 	kill_connection();
25731457Sminshall 	return;
25831457Sminshall     }
25931511Sminshall     if (api_exch_outtype(EXCH_TYPE_BYTES, storage_length, (char *)storage)
26031511Sminshall 							    == -1) {
26131511Sminshall 	kill_connection();
26231511Sminshall 	return;
26331463Sminshall     }
26431457Sminshall }
26531457Sminshall 
26631457Sminshall 
26731463Sminshall static int
26831508Sminshall getstorage(address, length, copyin)
26931508Sminshall int
27031508Sminshall     address,
27131508Sminshall     length,
27231508Sminshall     copyin;
27331457Sminshall {
27431463Sminshall     struct storage_descriptor sd;
27531457Sminshall     char buffer[40];
27631457Sminshall 
27731457Sminshall     freestorage();
27831457Sminshall     if (storage_accessed) {
27931457Sminshall 	fprintf(stderr,
28031457Sminshall 		"Internal error - attempt to get while storage accessed.\n");
28131503Sminshall 	fprintf(stderr, "(Encountered in file %s at line %d.)\n",
28231457Sminshall 			__FILE__, __LINE__);
28331457Sminshall 	quit();
28431457Sminshall     }
28531457Sminshall     storage_must_send = 0;
28631492Sminshall     if (api_exch_outcommand(EXCH_CMD_GIMME) == -1) {
28731457Sminshall 	kill_connection();
28831463Sminshall 	return -1;
28931457Sminshall     }
29031471Sminshall     storage_location = address;
29131471Sminshall     storage_length = length;
29231508Sminshall     if (copyin) {
29331798Sminshall 	sd.location = storage_location;
29431798Sminshall 	sd.length = storage_length;
29531508Sminshall 	if (api_exch_outtype(EXCH_TYPE_STORE_DESC,
29631508Sminshall 					sizeof sd, (char *)&sd) == -1) {
29731508Sminshall 	    kill_connection();
29831508Sminshall 	    return -1;
29931508Sminshall 	}
30031508Sminshall 	if (api_exch_incommand(EXCH_CMD_HEREIS) == -1) {
30131508Sminshall 	    fprintf(stderr, "Bad data from other side.\n");
30231508Sminshall 	    fprintf(stderr, "(Encountered at %s, %d.)\n", __FILE__, __LINE__);
30331508Sminshall 	    return -1;
30431508Sminshall 	}
30531508Sminshall 	if (nextstore() == -1) {
30631508Sminshall 	    kill_connection();
30731508Sminshall 	    return -1;
30831508Sminshall 	}
30931463Sminshall     }
31031463Sminshall     return 0;
31131457Sminshall }
31231457Sminshall 
31331457Sminshall void
31431457Sminshall movetous(local, es, di, length)
31531457Sminshall char
31631457Sminshall     *local;
31731457Sminshall int
31831457Sminshall     es,
31931457Sminshall     di;
32031457Sminshall int
32131457Sminshall     length;
32231457Sminshall {
32331457Sminshall     if (length > sizeof storage) {
32431457Sminshall 	fprintf(stderr, "Internal API error - movetous() length too long.\n");
32531457Sminshall 	fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__);
32631457Sminshall 	quit();
32731457Sminshall     } else if (length == 0) {
32831457Sminshall 	return;
32931457Sminshall     }
33031508Sminshall     getstorage(di, length, 1);
33131463Sminshall     memcpy(local, storage+(di-storage_location), length);
33231457Sminshall }
33331457Sminshall 
33431457Sminshall void
33531457Sminshall movetothem(es, di, local, length)
33631457Sminshall int
33731457Sminshall     es,
33831457Sminshall     di;
33931457Sminshall char
34031457Sminshall     *local;
34131457Sminshall int
34231457Sminshall     length;
34331457Sminshall {
34431457Sminshall     if (length > sizeof storage) {
34531457Sminshall 	fprintf(stderr, "Internal API error - movetothem() length too long.\n");
34631457Sminshall 	fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__);
34731457Sminshall 	quit();
34831457Sminshall     } else if (length == 0) {
34931457Sminshall 	return;
35031457Sminshall     }
35131457Sminshall     freestorage();
35231457Sminshall     memcpy((char *)storage, local, length);
35331457Sminshall     storage_length = length;
35431463Sminshall     storage_location = di;
35531457Sminshall     storage_must_send = 1;
35631457Sminshall }
35731457Sminshall 
35831457Sminshall 
35931457Sminshall char *
36031508Sminshall access_api(location, length, copyin)
36131457Sminshall int
36231457Sminshall     location,
36331508Sminshall     length,
36431508Sminshall     copyin;			/* Do we need to copy in initially? */
36531457Sminshall {
36631457Sminshall     if (storage_accessed) {
36731457Sminshall 	fprintf(stderr, "Internal error - storage accessed twice\n");
36831503Sminshall 	fprintf(stderr, "(Encountered in file %s, line %d.)\n",
36931457Sminshall 				__FILE__, __LINE__);
37031457Sminshall 	quit();
37131457Sminshall     } else if (length != 0) {
37231457Sminshall 	freestorage();
37331508Sminshall 	getstorage(location, length, copyin);
37431503Sminshall 	storage_accessed = 1;
37531457Sminshall     }
37631457Sminshall     return (char *) storage;
37731457Sminshall }
37831457Sminshall 
37931508Sminshall unaccess_api(location, local, length, copyout)
38031457Sminshall int	location;
38131457Sminshall char	*local;
38231457Sminshall int	length;
38331457Sminshall {
38431457Sminshall     if (storage_accessed == 0) {
38531457Sminshall 	fprintf(stderr, "Internal error - unnecessary unaccess_api call.\n");
38631503Sminshall 	fprintf(stderr, "(Encountered in file %s, line %d.)\n",
38731457Sminshall 			__FILE__, __LINE__);
38831457Sminshall 	quit();
38931457Sminshall     }
39031457Sminshall     storage_accessed = 0;
39131508Sminshall     storage_must_send = copyout;	/* if needs to go back */
39231457Sminshall }
39331457Sminshall 
39431465Sminshall /*
39531465Sminshall  * Accept a connection from an API client, aborting if the child dies.
39631465Sminshall  */
39731457Sminshall 
39831465Sminshall static int
39931465Sminshall doconnect()
40031465Sminshall {
40131465Sminshall     fd_set fdset;
40231465Sminshall     int i;
40331465Sminshall 
40431465Sminshall     sock = -1;
40531465Sminshall     FD_ZERO(&fdset);
40631465Sminshall     while (shell_active && (sock == -1)) {
40731465Sminshall 	FD_SET(serversock, &fdset);
40831465Sminshall 	if ((i = select(serversock+1, &fdset, 0, 0, 0)) < 0) {
40931465Sminshall 	    if (errno = EINTR) {
41031465Sminshall 		continue;
41131465Sminshall 	    } else {
41231465Sminshall 		perror("in select waiting for API connection");
41331465Sminshall 		return -1;
41431465Sminshall 	    }
41531465Sminshall 	} else {
41631465Sminshall 	    i = accept(serversock, 0, 0);
41731465Sminshall 	    if (i == -1) {
41831465Sminshall 		perror("accepting API connection");
41931465Sminshall 		return -1;
42031465Sminshall 	    }
42131465Sminshall 	    sock = i;
42231465Sminshall 	}
42331465Sminshall     }
42431465Sminshall     /* If the process has already exited, we may need to close */
42531465Sminshall     if ((shell_active == 0) && (sock != -1)) {
42631465Sminshall 	(void) close(sock);
42731465Sminshall 	sock = -1;
42831465Sminshall 	setcommandmode();	/* In case child_died sneaked in */
42931465Sminshall     }
43031465Sminshall }
43131465Sminshall 
43231457Sminshall /*
43331455Sminshall  * shell_continue() actually runs the command, and looks for API
43431455Sminshall  * requests coming back in.
43531455Sminshall  *
43631455Sminshall  * We are called from the main loop in telnet.c.
43731455Sminshall  */
43831455Sminshall 
43931455Sminshall int
44031455Sminshall shell_continue()
44131455Sminshall {
44231492Sminshall     int i;
44331492Sminshall 
44431457Sminshall     switch (state) {
44531457Sminshall     case DEAD:
44631457Sminshall 	pause();			/* Nothing to do */
44731457Sminshall 	break;
44831457Sminshall     case UNCONNECTED:
44931465Sminshall 	if (doconnect() == -1) {
45031457Sminshall 	    kill_connection();
45131465Sminshall 	    return -1;
45231465Sminshall 	}
45331492Sminshall 	if (api_exch_init(sock, "server") == -1) {
45431465Sminshall 	    return -1;
45531465Sminshall 	}
45631465Sminshall 	while (state == UNCONNECTED) {
45731492Sminshall 	    if (api_exch_incommand(EXCH_CMD_ASSOCIATE) == -1) {
45831457Sminshall 		kill_connection();
45931465Sminshall 		return -1;
46031465Sminshall 	    } else {
46131465Sminshall 		switch (doassociate()) {
46231465Sminshall 		case -1:
46331465Sminshall 		    kill_connection();
46431465Sminshall 		    return -1;
46531465Sminshall 		case 0:
46631465Sminshall 		    break;
46731465Sminshall 		case 1:
46831465Sminshall 		    state = CONNECTED;
46931465Sminshall 		}
47031457Sminshall 	    }
47131457Sminshall 	}
47231457Sminshall 	break;
47331457Sminshall     case CONNECTED:
47431492Sminshall 	switch (i = api_exch_nextcommand()) {
47531492Sminshall 	case EXCH_CMD_REQUEST:
47631492Sminshall 	    if (api_exch_intype(EXCH_TYPE_REGS, sizeof inputRegs,
47731492Sminshall 				    (char *)&inputRegs) == -1) {
47831463Sminshall 		kill_connection();
47931492Sminshall 	    } else if (api_exch_intype(EXCH_TYPE_SREGS, sizeof inputSregs,
48031492Sminshall 				    (char *)&inputSregs) == -1) {
48131463Sminshall 		kill_connection();
48231492Sminshall 	    } else if (nextstore() == -1) {
48331463Sminshall 		kill_connection();
48431492Sminshall 	    } else {
48531492Sminshall 		handle_api(&inputRegs, &inputSregs);
48631492Sminshall 		freestorage();			/* Send any storage back */
48731492Sminshall 		if (api_exch_outcommand(EXCH_CMD_REPLY) == -1) {
48831492Sminshall 		    kill_connection();
48931492Sminshall 		} else if (api_exch_outtype(EXCH_TYPE_REGS, sizeof inputRegs,
49031492Sminshall 				    (char *)&inputRegs) == -1) {
49131492Sminshall 		    kill_connection();
49231492Sminshall 		} else if (api_exch_outtype(EXCH_TYPE_SREGS, sizeof inputSregs,
49331492Sminshall 				    (char *)&inputSregs) == -1) {
49431492Sminshall 		    kill_connection();
49531492Sminshall 		}
49631492Sminshall 		/* Done, and it all worked! */
49731463Sminshall 	    }
49831492Sminshall 	    break;
49931492Sminshall 	case EXCH_CMD_DISASSOCIATE:
50031492Sminshall 	    kill_connection();
50131492Sminshall 	    break;
50231492Sminshall 	default:
50331503Sminshall 	    if (i != -1) {
50431503Sminshall 		fprintf(stderr,
50531503Sminshall 			"Looking for a REQUEST or DISASSOCIATE command\n");
50631503Sminshall 		fprintf(stderr, "\treceived 0x%02x.\n", i);
50731503Sminshall 	    }
50831492Sminshall 	    kill_connection();
50931503Sminshall 	    break;
51031457Sminshall 	}
51131457Sminshall     }
51231455Sminshall     return shell_active;
51331455Sminshall }
51431455Sminshall 
51531455Sminshall 
51631463Sminshall static int
51731463Sminshall child_died()
51831463Sminshall {
51931463Sminshall     union wait *status;
52031463Sminshall     register int pid;
52131463Sminshall 
52231463Sminshall     while ((pid = wait3(&status, WNOHANG, 0)) > 0) {
52331463Sminshall 	if (pid == shell_pid) {
52431463Sminshall 	    char inputbuffer[100];
52531463Sminshall 
52631463Sminshall 	    shell_active = 0;
52731463Sminshall 	    if (sock != -1) {
52831463Sminshall 		(void) close(sock);
52931463Sminshall 		sock = -1;
53031463Sminshall 	    }
53131471Sminshall 	    printf("[Hit return to continue]");
53231471Sminshall 	    fflush(stdout);
53331471Sminshall 	    (void) gets(inputbuffer);
53431465Sminshall 	    setconnmode();
53531465Sminshall 	    ConnectScreen();	/* Turn screen on (if need be) */
53631465Sminshall 	    (void) close(serversock);
53731798Sminshall 	    (void) unlink(keyname);
53831463Sminshall 	}
53931463Sminshall     }
54031463Sminshall     signal(SIGCHLD, child_died);
54131463Sminshall }
54231463Sminshall 
54331463Sminshall 
54431455Sminshall /*
54531455Sminshall  * Called from telnet.c to fork a lower command.com.  We
54631455Sminshall  * use the spint... routines so that we can pick up
54731455Sminshall  * interrupts generated by application programs.
54831455Sminshall  */
54931455Sminshall 
55031455Sminshall 
55131455Sminshall int
55231455Sminshall shell(argc,argv)
55331455Sminshall int	argc;
55431455Sminshall char	*argv[];
55531455Sminshall {
55631465Sminshall     int length;
55731457Sminshall     struct sockaddr_in server;
55831457Sminshall     char sockNAME[100];
55931457Sminshall     static char **whereAPI = 0;
56031798Sminshall     int fd;
56131798Sminshall     struct timeval tv;
56231798Sminshall     long ikey;
56331798Sminshall     extern long random();
56431798Sminshall     extern char *mktemp();
56531457Sminshall 
56631798Sminshall     /* First, create verification file. */
56731798Sminshall     do {
56831798Sminshall 	keyname = mktemp("/tmp/apiXXXXXX");
56931798Sminshall 	fd = open(keyname, O_RDWR|O_CREAT|O_EXCL, IREAD|IWRITE);
57031798Sminshall     } while ((fd == -1) && (errno == EEXIST));
57131798Sminshall 
57231798Sminshall     if (fd == -1) {
57331798Sminshall 	perror("open");
57431798Sminshall 	return 0;
57531798Sminshall     }
57631798Sminshall 
57731798Sminshall     /* Now, get seed for random */
57831798Sminshall 
57931798Sminshall     if (gettimeofday(&tv, 0) == -1) {
58031798Sminshall 	perror("gettimeofday");
58131798Sminshall 	return 0;
58231798Sminshall     }
58331798Sminshall     srandom(tv.tv_usec);		/* seed random number generator */
58431798Sminshall     do {
58531798Sminshall 	ikey = random();
58631798Sminshall     } while (ikey == 0);
58731798Sminshall     sprintf(key, "%lu\n", ikey);
58831798Sminshall     if (write(fd, key, strlen(key)) != strlen(key)) {
58931798Sminshall 	perror("write");
59031798Sminshall 	return 0;
59131798Sminshall     }
59231798Sminshall     key[strlen(key)-1] = 0;		/* Get rid of newline */
59331798Sminshall 
59431798Sminshall     if (close(fd) == -1) {
59531798Sminshall 	perror("close");
59631798Sminshall 	return 0;
59731798Sminshall     }
59831798Sminshall 
59931798Sminshall     /* Next, create the socket which will be connected to */
60031457Sminshall     serversock = socket(AF_INET, SOCK_STREAM, 0);
60131457Sminshall     if (serversock < 0) {
60231457Sminshall 	perror("opening API socket");
60331457Sminshall 	return 0;
60431457Sminshall     }
60531457Sminshall     server.sin_family = AF_INET;
60631457Sminshall     server.sin_addr.s_addr = INADDR_ANY;
60731457Sminshall     server.sin_port = 0;
60831457Sminshall     if (bind(serversock, &server, sizeof server) < 0) {
60931457Sminshall 	perror("binding API socket");
61031457Sminshall 	return 0;
61131457Sminshall     }
61231457Sminshall     length = sizeof server;
61331457Sminshall     if (getsockname(serversock, &server, &length) < 0) {
61431457Sminshall 	perror("getting API socket name");
61531457Sminshall 	(void) close(serversock);
61631457Sminshall     }
61731457Sminshall     listen(serversock, 1);
61831457Sminshall     /* Get name to advertise in address list */
61931457Sminshall     strcpy(sockNAME, "API3270=");
62031457Sminshall     gethostname(sockNAME+strlen(sockNAME), sizeof sockNAME-strlen(sockNAME));
62131798Sminshall     if (strlen(sockNAME) > (sizeof sockNAME-(10+strlen(keyname)))) {
62231457Sminshall 	fprintf(stderr, "Local hostname too large; using 'localhost'.\n");
62331457Sminshall 	strcpy(sockNAME, "localhost");
62431457Sminshall     }
62531457Sminshall     sprintf(sockNAME+strlen(sockNAME), ":%d", ntohs(server.sin_port));
62631798Sminshall     sprintf(sockNAME+strlen(sockNAME), ":%s", keyname);
62731457Sminshall 
62831457Sminshall     if (whereAPI == 0) {
62931457Sminshall 	char **ptr, **nextenv;
63031457Sminshall 	extern char **environ;
63131457Sminshall 
63231457Sminshall 	ptr = environ;
63331457Sminshall 	nextenv = ourENVlist;
63431457Sminshall 	while (*ptr) {
63531457Sminshall 	    if (nextenv >= &ourENVlist[highestof(ourENVlist)-1]) {
63631457Sminshall 		fprintf(stderr, "Too many environmental variables\n");
63731457Sminshall 		break;
63831457Sminshall 	    }
63931457Sminshall 	    *nextenv++ = *ptr++;
64031457Sminshall 	}
64131457Sminshall 	whereAPI = nextenv++;
64231457Sminshall 	*nextenv++ = 0;
64331457Sminshall 	environ = ourENVlist;		/* New environment */
64431457Sminshall     }
64531457Sminshall     *whereAPI = sockNAME;
64631457Sminshall 
64731457Sminshall     child_died();			/* Start up signal handler */
64831457Sminshall     shell_active = 1;			/* We are running down below */
64931457Sminshall     if (shell_pid = vfork()) {
65031457Sminshall 	if (shell_pid == -1) {
65131457Sminshall 	    perror("vfork");
65231457Sminshall 	    (void) close(serversock);
65331457Sminshall 	} else {
65431465Sminshall 	    state = UNCONNECTED;
65531457Sminshall 	}
65631455Sminshall     } else {				/* New process */
65731455Sminshall 	register int i;
65831455Sminshall 
65931455Sminshall 	for (i = 3; i < 30; i++) {
66031455Sminshall 	    (void) close(i);
66131455Sminshall 	}
66231455Sminshall 	if (argc == 1) {		/* Just get a shell */
66331455Sminshall 	    char *cmdname;
66431457Sminshall 	    extern char *getenv();
66531455Sminshall 
66631455Sminshall 	    cmdname = getenv("SHELL");
66731455Sminshall 	    execlp(cmdname, cmdname, 0);
66831455Sminshall 	    perror("Exec'ing new shell...\n");
66931455Sminshall 	    exit(1);
67031455Sminshall 	} else {
67131455Sminshall 	    execvp(argv[1], &argv[1]);
67231455Sminshall 	    perror("Exec'ing command.\n");
67331455Sminshall 	    exit(1);
67431455Sminshall 	}
67531455Sminshall 	/*NOTREACHED*/
67631455Sminshall     }
67731457Sminshall     return shell_active;		/* Go back to main loop */
67831455Sminshall }
679