131894Sminshall /*
231894Sminshall  *	Copyright (c) 1984-1987 by the Regents of the
331894Sminshall  *	University of California and by Gregory Glenn Minshall.
431894Sminshall  *
531894Sminshall  *	Permission to use, copy, modify, and distribute these
631894Sminshall  *	programs and their documentation for any purpose and
731894Sminshall  *	without fee is hereby granted, provided that this
831894Sminshall  *	copyright and permission appear on all copies and
931894Sminshall  *	supporting documentation, the name of the Regents of
1031894Sminshall  *	the University of California not be used in advertising
1131894Sminshall  *	or publicity pertaining to distribution of the programs
1231894Sminshall  *	without specific prior permission, and notice be given in
1331894Sminshall  *	supporting documentation that copying and distribution is
1431894Sminshall  *	by permission of the Regents of the University of California
1531894Sminshall  *	and by Gregory Glenn Minshall.  Neither the Regents of the
1631894Sminshall  *	University of California nor Gregory Glenn Minshall make
1731894Sminshall  *	representations about the suitability of this software
1831894Sminshall  *	for any purpose.  It is provided "as is" without
1931894Sminshall  *	express or implied warranty.
2031894Sminshall  */
2131894Sminshall 
2231894Sminshall #ifndef lint
23*33269Sminshall static char sccsid[] = "@(#)system.c	3.2 (Berkeley) 01/05/88";
2431894Sminshall #endif	/* not lint */
2531894Sminshall 
2631457Sminshall #include <sys/types.h>
2731863Sminshall 
28*33269Sminshall #if     defined(pyr)
29*33269Sminshall #define fd_set fdset_t
30*33269Sminshall #endif  /* defined(pyr) */
31*33269Sminshall 
32*33269Sminshall #if	!defined(sun) && !defined(pyr)
3331798Sminshall #include <sys/inode.h>
3431863Sminshall #else	/* !defined(sun) */
3531863Sminshall #define	IREAD	00400
3631863Sminshall #define	IWRITE	00200
3731863Sminshall #endif	/* !defined(sun) */
3831863Sminshall 
3931798Sminshall #include <sys/file.h>
4031798Sminshall #include <sys/time.h>
4131457Sminshall #include <sys/socket.h>
4231457Sminshall #include <netinet/in.h>
4331455Sminshall #include <sys/wait.h>
4431455Sminshall 
4531457Sminshall #include <errno.h>
4631457Sminshall extern int errno;
4731457Sminshall 
4831457Sminshall #include <netdb.h>
4931457Sminshall #include <signal.h>
5031455Sminshall #include <stdio.h>
5131457Sminshall #include <pwd.h>
5231455Sminshall 
5331455Sminshall #include "../general/general.h"
5431873Sminshall #include "../ctlr/api.h"
5531873Sminshall #include "../api/api_exch.h"
5631455Sminshall 
5731455Sminshall #include "../general/globals.h"
5831455Sminshall 
5931795Sminshall #ifndef	FD_SETSIZE
6031795Sminshall /*
6131795Sminshall  * The following is defined just in case someone should want to run
6231795Sminshall  * this telnet on a 4.2 system.
6331795Sminshall  *
6431795Sminshall  */
6531455Sminshall 
6631795Sminshall #define	FD_SET(n, p)	((p)->fds_bits[0] |= (1<<(n)))
6731795Sminshall #define	FD_CLR(n, p)	((p)->fds_bits[0] &= ~(1<<(n)))
6831795Sminshall #define	FD_ISSET(n, p)	((p)->fds_bits[0] & (1<<(n)))
6931795Sminshall #define FD_ZERO(p)	((p)->fds_bits[0] = 0)
7031795Sminshall 
7131795Sminshall #endif
7231795Sminshall 
7331455Sminshall static int shell_pid = 0;
7431798Sminshall static char key[50];			/* Actual key */
7531798Sminshall static char *keyname;			/* Name of file with key in it */
7631455Sminshall 
7731457Sminshall static char *ourENVlist[200];		/* Lots of room */
7831457Sminshall 
7931465Sminshall static int
8031465Sminshall     sock = -1,				/* Connected socket */
8131465Sminshall     serversock;				/* Server (listening) socket */
8231457Sminshall 
8331457Sminshall static enum { DEAD, UNCONNECTED, CONNECTED } state;
8431457Sminshall 
8531455Sminshall static int
8631463Sminshall     storage_location,		/* Address we have */
8731457Sminshall     storage_length = 0,		/* Length we have */
8831457Sminshall     storage_must_send = 0,	/* Storage belongs on other side of wire */
8931457Sminshall     storage_accessed = 0;	/* The storage is accessed (so leave alone)! */
9031457Sminshall 
9131503Sminshall static long storage[1000];
9231457Sminshall 
9331463Sminshall static union REGS inputRegs;
9431463Sminshall static struct SREGS inputSregs;
9531457Sminshall 
9631463Sminshall 
9731463Sminshall static void
9831457Sminshall kill_connection()
9931457Sminshall {
10031465Sminshall     state = UNCONNECTED;
10131465Sminshall     if (sock != -1) {
10231465Sminshall 	(void) close(sock);
10331465Sminshall 	sock = -1;
10431465Sminshall     }
10531457Sminshall }
10631457Sminshall 
10731457Sminshall 
10831457Sminshall static int
10931463Sminshall nextstore()
11031455Sminshall {
11131463Sminshall     struct storage_descriptor sd;
11231455Sminshall 
11331463Sminshall     if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
11431457Sminshall 	storage_length = 0;
11531457Sminshall 	return -1;
11631457Sminshall     }
11731798Sminshall     storage_length = sd.length;
11831798Sminshall     storage_location = sd.location;
11931463Sminshall     if (storage_length > sizeof storage) {
12031457Sminshall 	fprintf(stderr, "API client tried to send too much storage (%d).\n",
12131457Sminshall 		storage_length);
12231463Sminshall 	storage_length = 0;
12331457Sminshall 	return -1;
12431457Sminshall     }
12531511Sminshall     if (api_exch_intype(EXCH_TYPE_BYTES, storage_length, (char *)storage)
12631511Sminshall 							== -1) {
12731511Sminshall 	storage_length = 0;
12831511Sminshall 	return -1;
12931463Sminshall     }
13031471Sminshall     return 0;
13131457Sminshall }
13231457Sminshall 
13331457Sminshall 
13431457Sminshall static int
13531457Sminshall doreject(message)
13631457Sminshall char	*message;
13731457Sminshall {
13831463Sminshall     struct storage_descriptor sd;
13931457Sminshall     int length = strlen(message);
14031457Sminshall 
14131492Sminshall     if (api_exch_outcommand(EXCH_CMD_REJECTED) == -1) {
14231457Sminshall 	return -1;
14331457Sminshall     }
14431798Sminshall     sd.length = length;
14531465Sminshall     if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
14631463Sminshall 	return -1;
14731463Sminshall     }
14831463Sminshall     if (api_exch_outtype(EXCH_TYPE_BYTES, length, message) == -1) {
14931463Sminshall 	return -1;
15031463Sminshall     }
15131457Sminshall     return 0;
15231457Sminshall }
15331457Sminshall 
15431457Sminshall 
15531455Sminshall /*
15631465Sminshall  * doassociate()
15731457Sminshall  *
15831457Sminshall  * Negotiate with the other side and try to do something.
15931798Sminshall  *
16031798Sminshall  * Returns:
16131798Sminshall  *
16231798Sminshall  *	-1:	Error in processing
16331798Sminshall  *	 0:	Invalid password entered
16431798Sminshall  *	 1:	Association OK
16531457Sminshall  */
16631457Sminshall 
16731457Sminshall static int
16831465Sminshall doassociate()
16931457Sminshall {
17031457Sminshall     struct passwd *pwent;
17131457Sminshall     char
17231457Sminshall 	promptbuf[100],
17331457Sminshall 	buffer[200];
17431457Sminshall     int length;
17531457Sminshall     int was;
17631463Sminshall     struct storage_descriptor sd;
17731457Sminshall 
17831463Sminshall     if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
17931463Sminshall 	return -1;
18031457Sminshall     }
18131798Sminshall     sd.length = sd.length;
18231463Sminshall     if (sd.length > sizeof buffer) {
18331798Sminshall 	doreject("(internal error) Authentication key too long");
18431465Sminshall 	return -1;
18531457Sminshall     }
18631463Sminshall     if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) {
18731457Sminshall 	return -1;
18831457Sminshall     }
18931463Sminshall     buffer[sd.length] = 0;
19031457Sminshall 
19131798Sminshall     if (strcmp(buffer, key) != 0) {
19231798Sminshall 	if ((pwent = getpwuid(geteuid())) == 0) {
19331798Sminshall 	    return -1;
19431798Sminshall 	}
19531798Sminshall 	sprintf(promptbuf, "Enter password for user %s:", pwent->pw_name);
19631798Sminshall 	if (api_exch_outcommand(EXCH_CMD_SEND_AUTH) == -1) {
19731798Sminshall 	    return -1;
19831798Sminshall 	}
19931798Sminshall 	sd.length = strlen(promptbuf);
20031798Sminshall 	if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd)
20131798Sminshall 									== -1) {
20231798Sminshall 	    return -1;
20331798Sminshall 	}
20431798Sminshall 	if (api_exch_outtype(EXCH_TYPE_BYTES, strlen(promptbuf), promptbuf)
20531798Sminshall 									== -1) {
20631798Sminshall 	    return -1;
20731798Sminshall 	}
20831798Sminshall 	sd.length = strlen(pwent->pw_name);
20931798Sminshall 	if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd)
21031798Sminshall 									== -1) {
21131798Sminshall 	    return -1;
21231798Sminshall 	}
21331798Sminshall 	if (api_exch_outtype(EXCH_TYPE_BYTES,
21431798Sminshall 			    strlen(pwent->pw_name), pwent->pw_name) == -1) {
21531798Sminshall 	    return -1;
21631798Sminshall 	}
21731798Sminshall 	if (api_exch_incommand(EXCH_CMD_AUTH) == -1) {
21831798Sminshall 	    return -1;
21931798Sminshall 	}
22031798Sminshall 	if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd)
22131798Sminshall 									== -1) {
22231798Sminshall 	    return -1;
22331798Sminshall 	}
22431798Sminshall 	sd.length = sd.length;
22531798Sminshall 	if (sd.length > sizeof buffer) {
22631798Sminshall 	    doreject("Password entered was too long");
22731798Sminshall 	    return -1;
22831798Sminshall 	}
22931798Sminshall 	if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) {
23031798Sminshall 	    return -1;
23131798Sminshall 	}
23231798Sminshall 	buffer[sd.length] = 0;
23331465Sminshall 
23431798Sminshall 	/* Is this the correct password? */
23531798Sminshall 	if (strlen(pwent->pw_name)) {
23631798Sminshall 	    char *ptr;
23731798Sminshall 	    int i;
23831798Sminshall 
23931798Sminshall 	    ptr = pwent->pw_name;
24031798Sminshall 	    i = 0;
24131798Sminshall 	    while (i < sd.length) {
24231798Sminshall 		buffer[i++] ^= *ptr++;
24331798Sminshall 		if (*ptr == 0) {
24431798Sminshall 		    ptr = pwent->pw_name;
24531798Sminshall 		}
24631465Sminshall 	    }
24731465Sminshall 	}
24831798Sminshall 	if (strcmp(crypt(buffer, pwent->pw_passwd), pwent->pw_passwd) != 0) {
24931798Sminshall 	    doreject("Invalid password");
25031798Sminshall 	    sleep(10);		/* Don't let us do too many of these */
25131798Sminshall 	    return 0;
25231798Sminshall 	}
25331465Sminshall     }
25431798Sminshall     if (api_exch_outcommand(EXCH_CMD_ASSOCIATED) == -1) {
25531798Sminshall 	return -1;
25631457Sminshall     } else {
25731798Sminshall 	return 1;
25831457Sminshall     }
25931457Sminshall }
26031457Sminshall 
26131457Sminshall 
26231457Sminshall void
26331457Sminshall freestorage()
26431457Sminshall {
26531457Sminshall     char buffer[40];
26631463Sminshall     struct storage_descriptor sd;
26731457Sminshall 
26831457Sminshall     if (storage_accessed) {
26931457Sminshall 	fprintf(stderr, "Internal error - attempt to free accessed storage.\n");
27031503Sminshall 	fprintf(stderr, "(Encountered in file %s at line %d.)\n",
27131457Sminshall 			__FILE__, __LINE__);
27231457Sminshall 	quit();
27331457Sminshall     }
27431457Sminshall     if (storage_must_send == 0) {
27531457Sminshall 	return;
27631457Sminshall     }
27731457Sminshall     storage_must_send = 0;
27831492Sminshall     if (api_exch_outcommand(EXCH_CMD_HEREIS) == -1) {
27931457Sminshall 	kill_connection();
28031457Sminshall 	return;
28131457Sminshall     }
28231798Sminshall     sd.length = storage_length;
28331798Sminshall     sd.location = storage_location;
28431463Sminshall     if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
28531457Sminshall 	kill_connection();
28631457Sminshall 	return;
28731457Sminshall     }
28831511Sminshall     if (api_exch_outtype(EXCH_TYPE_BYTES, storage_length, (char *)storage)
28931511Sminshall 							    == -1) {
29031511Sminshall 	kill_connection();
29131511Sminshall 	return;
29231463Sminshall     }
29331457Sminshall }
29431457Sminshall 
29531457Sminshall 
29631463Sminshall static int
29731508Sminshall getstorage(address, length, copyin)
29831508Sminshall int
29931508Sminshall     address,
30031508Sminshall     length,
30131508Sminshall     copyin;
30231457Sminshall {
30331463Sminshall     struct storage_descriptor sd;
30431457Sminshall     char buffer[40];
30531457Sminshall 
30631457Sminshall     freestorage();
30731457Sminshall     if (storage_accessed) {
30831457Sminshall 	fprintf(stderr,
30931457Sminshall 		"Internal error - attempt to get while storage accessed.\n");
31031503Sminshall 	fprintf(stderr, "(Encountered in file %s at line %d.)\n",
31131457Sminshall 			__FILE__, __LINE__);
31231457Sminshall 	quit();
31331457Sminshall     }
31431457Sminshall     storage_must_send = 0;
31531492Sminshall     if (api_exch_outcommand(EXCH_CMD_GIMME) == -1) {
31631457Sminshall 	kill_connection();
31731463Sminshall 	return -1;
31831457Sminshall     }
31931471Sminshall     storage_location = address;
32031471Sminshall     storage_length = length;
32131508Sminshall     if (copyin) {
32231798Sminshall 	sd.location = storage_location;
32331798Sminshall 	sd.length = storage_length;
32431508Sminshall 	if (api_exch_outtype(EXCH_TYPE_STORE_DESC,
32531508Sminshall 					sizeof sd, (char *)&sd) == -1) {
32631508Sminshall 	    kill_connection();
32731508Sminshall 	    return -1;
32831508Sminshall 	}
32931508Sminshall 	if (api_exch_incommand(EXCH_CMD_HEREIS) == -1) {
33031508Sminshall 	    fprintf(stderr, "Bad data from other side.\n");
33131508Sminshall 	    fprintf(stderr, "(Encountered at %s, %d.)\n", __FILE__, __LINE__);
33231508Sminshall 	    return -1;
33331508Sminshall 	}
33431508Sminshall 	if (nextstore() == -1) {
33531508Sminshall 	    kill_connection();
33631508Sminshall 	    return -1;
33731508Sminshall 	}
33831463Sminshall     }
33931463Sminshall     return 0;
34031457Sminshall }
34131457Sminshall 
34231457Sminshall void
34331457Sminshall movetous(local, es, di, length)
34431457Sminshall char
34531457Sminshall     *local;
34631457Sminshall int
34731457Sminshall     es,
34831457Sminshall     di;
34931457Sminshall int
35031457Sminshall     length;
35131457Sminshall {
35231457Sminshall     if (length > sizeof storage) {
35331457Sminshall 	fprintf(stderr, "Internal API error - movetous() length too long.\n");
35431457Sminshall 	fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__);
35531457Sminshall 	quit();
35631457Sminshall     } else if (length == 0) {
35731457Sminshall 	return;
35831457Sminshall     }
35931508Sminshall     getstorage(di, length, 1);
36031463Sminshall     memcpy(local, storage+(di-storage_location), length);
36131457Sminshall }
36231457Sminshall 
36331457Sminshall void
36431457Sminshall movetothem(es, di, local, length)
36531457Sminshall int
36631457Sminshall     es,
36731457Sminshall     di;
36831457Sminshall char
36931457Sminshall     *local;
37031457Sminshall int
37131457Sminshall     length;
37231457Sminshall {
37331457Sminshall     if (length > sizeof storage) {
37431457Sminshall 	fprintf(stderr, "Internal API error - movetothem() length too long.\n");
37531457Sminshall 	fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__);
37631457Sminshall 	quit();
37731457Sminshall     } else if (length == 0) {
37831457Sminshall 	return;
37931457Sminshall     }
38031457Sminshall     freestorage();
38131457Sminshall     memcpy((char *)storage, local, length);
38231457Sminshall     storage_length = length;
38331463Sminshall     storage_location = di;
38431457Sminshall     storage_must_send = 1;
38531457Sminshall }
38631457Sminshall 
38731457Sminshall 
38831457Sminshall char *
38931508Sminshall access_api(location, length, copyin)
39031457Sminshall int
39131457Sminshall     location,
39231508Sminshall     length,
39331508Sminshall     copyin;			/* Do we need to copy in initially? */
39431457Sminshall {
39531457Sminshall     if (storage_accessed) {
39631457Sminshall 	fprintf(stderr, "Internal error - storage accessed twice\n");
39731503Sminshall 	fprintf(stderr, "(Encountered in file %s, line %d.)\n",
39831457Sminshall 				__FILE__, __LINE__);
39931457Sminshall 	quit();
40031457Sminshall     } else if (length != 0) {
40131457Sminshall 	freestorage();
40231508Sminshall 	getstorage(location, length, copyin);
40331503Sminshall 	storage_accessed = 1;
40431457Sminshall     }
40531457Sminshall     return (char *) storage;
40631457Sminshall }
40731457Sminshall 
40831508Sminshall unaccess_api(location, local, length, copyout)
40931457Sminshall int	location;
41031457Sminshall char	*local;
41131457Sminshall int	length;
41231457Sminshall {
41331457Sminshall     if (storage_accessed == 0) {
41431457Sminshall 	fprintf(stderr, "Internal error - unnecessary unaccess_api call.\n");
41531503Sminshall 	fprintf(stderr, "(Encountered in file %s, line %d.)\n",
41631457Sminshall 			__FILE__, __LINE__);
41731457Sminshall 	quit();
41831457Sminshall     }
41931457Sminshall     storage_accessed = 0;
42031508Sminshall     storage_must_send = copyout;	/* if needs to go back */
42131457Sminshall }
42231457Sminshall 
42331465Sminshall /*
42431465Sminshall  * Accept a connection from an API client, aborting if the child dies.
42531465Sminshall  */
42631457Sminshall 
42731465Sminshall static int
42831465Sminshall doconnect()
42931465Sminshall {
43031465Sminshall     fd_set fdset;
43131465Sminshall     int i;
43231465Sminshall 
43331465Sminshall     sock = -1;
43431465Sminshall     FD_ZERO(&fdset);
43531465Sminshall     while (shell_active && (sock == -1)) {
43631465Sminshall 	FD_SET(serversock, &fdset);
43731465Sminshall 	if ((i = select(serversock+1, &fdset, 0, 0, 0)) < 0) {
43831465Sminshall 	    if (errno = EINTR) {
43931465Sminshall 		continue;
44031465Sminshall 	    } else {
44131465Sminshall 		perror("in select waiting for API connection");
44231465Sminshall 		return -1;
44331465Sminshall 	    }
44431465Sminshall 	} else {
44531465Sminshall 	    i = accept(serversock, 0, 0);
44631465Sminshall 	    if (i == -1) {
44731465Sminshall 		perror("accepting API connection");
44831465Sminshall 		return -1;
44931465Sminshall 	    }
45031465Sminshall 	    sock = i;
45131465Sminshall 	}
45231465Sminshall     }
45331465Sminshall     /* If the process has already exited, we may need to close */
45431465Sminshall     if ((shell_active == 0) && (sock != -1)) {
45531465Sminshall 	(void) close(sock);
45631465Sminshall 	sock = -1;
45731465Sminshall 	setcommandmode();	/* In case child_died sneaked in */
45831465Sminshall     }
45931465Sminshall }
46031465Sminshall 
46131457Sminshall /*
46231455Sminshall  * shell_continue() actually runs the command, and looks for API
46331455Sminshall  * requests coming back in.
46431455Sminshall  *
46531455Sminshall  * We are called from the main loop in telnet.c.
46631455Sminshall  */
46731455Sminshall 
46831455Sminshall int
46931455Sminshall shell_continue()
47031455Sminshall {
47131492Sminshall     int i;
47231492Sminshall 
47331457Sminshall     switch (state) {
47431457Sminshall     case DEAD:
47531457Sminshall 	pause();			/* Nothing to do */
47631457Sminshall 	break;
47731457Sminshall     case UNCONNECTED:
47831465Sminshall 	if (doconnect() == -1) {
47931457Sminshall 	    kill_connection();
48031465Sminshall 	    return -1;
48131465Sminshall 	}
48231492Sminshall 	if (api_exch_init(sock, "server") == -1) {
48331465Sminshall 	    return -1;
48431465Sminshall 	}
48531465Sminshall 	while (state == UNCONNECTED) {
48631492Sminshall 	    if (api_exch_incommand(EXCH_CMD_ASSOCIATE) == -1) {
48731457Sminshall 		kill_connection();
48831465Sminshall 		return -1;
48931465Sminshall 	    } else {
49031465Sminshall 		switch (doassociate()) {
49131465Sminshall 		case -1:
49231465Sminshall 		    kill_connection();
49331465Sminshall 		    return -1;
49431465Sminshall 		case 0:
49531465Sminshall 		    break;
49631465Sminshall 		case 1:
49731465Sminshall 		    state = CONNECTED;
49831465Sminshall 		}
49931457Sminshall 	    }
50031457Sminshall 	}
50131457Sminshall 	break;
50231457Sminshall     case CONNECTED:
50331492Sminshall 	switch (i = api_exch_nextcommand()) {
50431492Sminshall 	case EXCH_CMD_REQUEST:
50531492Sminshall 	    if (api_exch_intype(EXCH_TYPE_REGS, sizeof inputRegs,
50631492Sminshall 				    (char *)&inputRegs) == -1) {
50731463Sminshall 		kill_connection();
50831492Sminshall 	    } else if (api_exch_intype(EXCH_TYPE_SREGS, sizeof inputSregs,
50931492Sminshall 				    (char *)&inputSregs) == -1) {
51031463Sminshall 		kill_connection();
51131492Sminshall 	    } else if (nextstore() == -1) {
51231463Sminshall 		kill_connection();
51331492Sminshall 	    } else {
51431492Sminshall 		handle_api(&inputRegs, &inputSregs);
51531492Sminshall 		freestorage();			/* Send any storage back */
51631492Sminshall 		if (api_exch_outcommand(EXCH_CMD_REPLY) == -1) {
51731492Sminshall 		    kill_connection();
51831492Sminshall 		} else if (api_exch_outtype(EXCH_TYPE_REGS, sizeof inputRegs,
51931492Sminshall 				    (char *)&inputRegs) == -1) {
52031492Sminshall 		    kill_connection();
52131492Sminshall 		} else if (api_exch_outtype(EXCH_TYPE_SREGS, sizeof inputSregs,
52231492Sminshall 				    (char *)&inputSregs) == -1) {
52331492Sminshall 		    kill_connection();
52431492Sminshall 		}
52531492Sminshall 		/* Done, and it all worked! */
52631463Sminshall 	    }
52731492Sminshall 	    break;
52831492Sminshall 	case EXCH_CMD_DISASSOCIATE:
52931492Sminshall 	    kill_connection();
53031492Sminshall 	    break;
53131492Sminshall 	default:
53231503Sminshall 	    if (i != -1) {
53331503Sminshall 		fprintf(stderr,
53431503Sminshall 			"Looking for a REQUEST or DISASSOCIATE command\n");
53531503Sminshall 		fprintf(stderr, "\treceived 0x%02x.\n", i);
53631503Sminshall 	    }
53731492Sminshall 	    kill_connection();
53831503Sminshall 	    break;
53931457Sminshall 	}
54031457Sminshall     }
54131455Sminshall     return shell_active;
54231455Sminshall }
54331455Sminshall 
54431455Sminshall 
54531463Sminshall static int
54631463Sminshall child_died()
54731463Sminshall {
54831463Sminshall     union wait *status;
54931463Sminshall     register int pid;
55031463Sminshall 
55131463Sminshall     while ((pid = wait3(&status, WNOHANG, 0)) > 0) {
55231463Sminshall 	if (pid == shell_pid) {
55331463Sminshall 	    char inputbuffer[100];
55431463Sminshall 
55531463Sminshall 	    shell_active = 0;
55631463Sminshall 	    if (sock != -1) {
55731463Sminshall 		(void) close(sock);
55831463Sminshall 		sock = -1;
55931463Sminshall 	    }
56031471Sminshall 	    printf("[Hit return to continue]");
56131471Sminshall 	    fflush(stdout);
56231471Sminshall 	    (void) gets(inputbuffer);
56331465Sminshall 	    setconnmode();
56431465Sminshall 	    ConnectScreen();	/* Turn screen on (if need be) */
56531465Sminshall 	    (void) close(serversock);
56631798Sminshall 	    (void) unlink(keyname);
56731463Sminshall 	}
56831463Sminshall     }
56931463Sminshall     signal(SIGCHLD, child_died);
57031463Sminshall }
57131463Sminshall 
57231463Sminshall 
57331455Sminshall /*
57431455Sminshall  * Called from telnet.c to fork a lower command.com.  We
57531455Sminshall  * use the spint... routines so that we can pick up
57631455Sminshall  * interrupts generated by application programs.
57731455Sminshall  */
57831455Sminshall 
57931455Sminshall 
58031455Sminshall int
58131455Sminshall shell(argc,argv)
58231455Sminshall int	argc;
58331455Sminshall char	*argv[];
58431455Sminshall {
58531465Sminshall     int length;
58631457Sminshall     struct sockaddr_in server;
58731457Sminshall     char sockNAME[100];
58831457Sminshall     static char **whereAPI = 0;
58931798Sminshall     int fd;
59031798Sminshall     struct timeval tv;
59131798Sminshall     long ikey;
59231798Sminshall     extern long random();
59331798Sminshall     extern char *mktemp();
59431457Sminshall 
59531798Sminshall     /* First, create verification file. */
59631798Sminshall     do {
59731798Sminshall 	keyname = mktemp("/tmp/apiXXXXXX");
59831798Sminshall 	fd = open(keyname, O_RDWR|O_CREAT|O_EXCL, IREAD|IWRITE);
59931798Sminshall     } while ((fd == -1) && (errno == EEXIST));
60031798Sminshall 
60131798Sminshall     if (fd == -1) {
60231798Sminshall 	perror("open");
60331798Sminshall 	return 0;
60431798Sminshall     }
60531798Sminshall 
60631798Sminshall     /* Now, get seed for random */
60731798Sminshall 
60831798Sminshall     if (gettimeofday(&tv, 0) == -1) {
60931798Sminshall 	perror("gettimeofday");
61031798Sminshall 	return 0;
61131798Sminshall     }
61231798Sminshall     srandom(tv.tv_usec);		/* seed random number generator */
61331798Sminshall     do {
61431798Sminshall 	ikey = random();
61531798Sminshall     } while (ikey == 0);
61631798Sminshall     sprintf(key, "%lu\n", ikey);
61731798Sminshall     if (write(fd, key, strlen(key)) != strlen(key)) {
61831798Sminshall 	perror("write");
61931798Sminshall 	return 0;
62031798Sminshall     }
62131798Sminshall     key[strlen(key)-1] = 0;		/* Get rid of newline */
62231798Sminshall 
62331798Sminshall     if (close(fd) == -1) {
62431798Sminshall 	perror("close");
62531798Sminshall 	return 0;
62631798Sminshall     }
62731798Sminshall 
62831798Sminshall     /* Next, create the socket which will be connected to */
62931457Sminshall     serversock = socket(AF_INET, SOCK_STREAM, 0);
63031457Sminshall     if (serversock < 0) {
63131457Sminshall 	perror("opening API socket");
63231457Sminshall 	return 0;
63331457Sminshall     }
63431457Sminshall     server.sin_family = AF_INET;
63531457Sminshall     server.sin_addr.s_addr = INADDR_ANY;
63631457Sminshall     server.sin_port = 0;
63731457Sminshall     if (bind(serversock, &server, sizeof server) < 0) {
63831457Sminshall 	perror("binding API socket");
63931457Sminshall 	return 0;
64031457Sminshall     }
64131457Sminshall     length = sizeof server;
64231457Sminshall     if (getsockname(serversock, &server, &length) < 0) {
64331457Sminshall 	perror("getting API socket name");
64431457Sminshall 	(void) close(serversock);
64531457Sminshall     }
64631457Sminshall     listen(serversock, 1);
64731457Sminshall     /* Get name to advertise in address list */
64831457Sminshall     strcpy(sockNAME, "API3270=");
64931457Sminshall     gethostname(sockNAME+strlen(sockNAME), sizeof sockNAME-strlen(sockNAME));
65031798Sminshall     if (strlen(sockNAME) > (sizeof sockNAME-(10+strlen(keyname)))) {
65131457Sminshall 	fprintf(stderr, "Local hostname too large; using 'localhost'.\n");
65231457Sminshall 	strcpy(sockNAME, "localhost");
65331457Sminshall     }
65431457Sminshall     sprintf(sockNAME+strlen(sockNAME), ":%d", ntohs(server.sin_port));
65531798Sminshall     sprintf(sockNAME+strlen(sockNAME), ":%s", keyname);
65631457Sminshall 
65731457Sminshall     if (whereAPI == 0) {
65831457Sminshall 	char **ptr, **nextenv;
65931457Sminshall 	extern char **environ;
66031457Sminshall 
66131457Sminshall 	ptr = environ;
66231457Sminshall 	nextenv = ourENVlist;
66331457Sminshall 	while (*ptr) {
66431457Sminshall 	    if (nextenv >= &ourENVlist[highestof(ourENVlist)-1]) {
66531457Sminshall 		fprintf(stderr, "Too many environmental variables\n");
66631457Sminshall 		break;
66731457Sminshall 	    }
66831457Sminshall 	    *nextenv++ = *ptr++;
66931457Sminshall 	}
67031457Sminshall 	whereAPI = nextenv++;
67131457Sminshall 	*nextenv++ = 0;
67231457Sminshall 	environ = ourENVlist;		/* New environment */
67331457Sminshall     }
67431457Sminshall     *whereAPI = sockNAME;
67531457Sminshall 
67631457Sminshall     child_died();			/* Start up signal handler */
67731457Sminshall     shell_active = 1;			/* We are running down below */
67831457Sminshall     if (shell_pid = vfork()) {
67931457Sminshall 	if (shell_pid == -1) {
68031457Sminshall 	    perror("vfork");
68131457Sminshall 	    (void) close(serversock);
68231457Sminshall 	} else {
68331465Sminshall 	    state = UNCONNECTED;
68431457Sminshall 	}
68531455Sminshall     } else {				/* New process */
68631455Sminshall 	register int i;
68731455Sminshall 
68831455Sminshall 	for (i = 3; i < 30; i++) {
68931455Sminshall 	    (void) close(i);
69031455Sminshall 	}
69131455Sminshall 	if (argc == 1) {		/* Just get a shell */
69231455Sminshall 	    char *cmdname;
69331457Sminshall 	    extern char *getenv();
69431455Sminshall 
69531455Sminshall 	    cmdname = getenv("SHELL");
69631455Sminshall 	    execlp(cmdname, cmdname, 0);
69731455Sminshall 	    perror("Exec'ing new shell...\n");
69831455Sminshall 	    exit(1);
69931455Sminshall 	} else {
70031455Sminshall 	    execvp(argv[1], &argv[1]);
70131455Sminshall 	    perror("Exec'ing command.\n");
70231455Sminshall 	    exit(1);
70331455Sminshall 	}
70431455Sminshall 	/*NOTREACHED*/
70531455Sminshall     }
70631457Sminshall     return shell_active;		/* Go back to main loop */
70731455Sminshall }
708