131894Sminshall /*
2*33810Sbostic  * Copyright (c) 1988 Regents of the University of California.
3*33810Sbostic  * All rights reserved.
431894Sminshall  *
5*33810Sbostic  * Redistribution and use in source and binary forms are permitted
6*33810Sbostic  * provided that this notice is preserved and that due credit is given
7*33810Sbostic  * to the University of California at Berkeley. The name of the University
8*33810Sbostic  * may not be used to endorse or promote products derived from this
9*33810Sbostic  * software without specific prior written permission. This software
10*33810Sbostic  * is provided ``as is'' without express or implied warranty.
1131894Sminshall  */
1231894Sminshall 
1331894Sminshall #ifndef lint
14*33810Sbostic static char sccsid[] = "@(#)system.c	3.3 (Berkeley) 03/28/88";
15*33810Sbostic #endif /* not lint */
1631894Sminshall 
1731457Sminshall #include <sys/types.h>
1831863Sminshall 
1933269Sminshall #if     defined(pyr)
2033269Sminshall #define fd_set fdset_t
2133269Sminshall #endif  /* defined(pyr) */
2233269Sminshall 
2333269Sminshall #if	!defined(sun) && !defined(pyr)
2431798Sminshall #include <sys/inode.h>
2531863Sminshall #else	/* !defined(sun) */
2631863Sminshall #define	IREAD	00400
2731863Sminshall #define	IWRITE	00200
2831863Sminshall #endif	/* !defined(sun) */
2931863Sminshall 
3031798Sminshall #include <sys/file.h>
3131798Sminshall #include <sys/time.h>
3231457Sminshall #include <sys/socket.h>
3331457Sminshall #include <netinet/in.h>
3431455Sminshall #include <sys/wait.h>
3531455Sminshall 
3631457Sminshall #include <errno.h>
3731457Sminshall extern int errno;
3831457Sminshall 
3931457Sminshall #include <netdb.h>
4031457Sminshall #include <signal.h>
4131455Sminshall #include <stdio.h>
4231457Sminshall #include <pwd.h>
4331455Sminshall 
4431455Sminshall #include "../general/general.h"
4531873Sminshall #include "../ctlr/api.h"
4631873Sminshall #include "../api/api_exch.h"
4731455Sminshall 
4831455Sminshall #include "../general/globals.h"
4931455Sminshall 
5031795Sminshall #ifndef	FD_SETSIZE
5131795Sminshall /*
5231795Sminshall  * The following is defined just in case someone should want to run
5331795Sminshall  * this telnet on a 4.2 system.
5431795Sminshall  *
5531795Sminshall  */
5631455Sminshall 
5731795Sminshall #define	FD_SET(n, p)	((p)->fds_bits[0] |= (1<<(n)))
5831795Sminshall #define	FD_CLR(n, p)	((p)->fds_bits[0] &= ~(1<<(n)))
5931795Sminshall #define	FD_ISSET(n, p)	((p)->fds_bits[0] & (1<<(n)))
6031795Sminshall #define FD_ZERO(p)	((p)->fds_bits[0] = 0)
6131795Sminshall 
6231795Sminshall #endif
6331795Sminshall 
6431455Sminshall static int shell_pid = 0;
6531798Sminshall static char key[50];			/* Actual key */
6631798Sminshall static char *keyname;			/* Name of file with key in it */
6731455Sminshall 
6831457Sminshall static char *ourENVlist[200];		/* Lots of room */
6931457Sminshall 
7031465Sminshall static int
7131465Sminshall     sock = -1,				/* Connected socket */
7231465Sminshall     serversock;				/* Server (listening) socket */
7331457Sminshall 
7431457Sminshall static enum { DEAD, UNCONNECTED, CONNECTED } state;
7531457Sminshall 
7631455Sminshall static int
7731463Sminshall     storage_location,		/* Address we have */
7831457Sminshall     storage_length = 0,		/* Length we have */
7931457Sminshall     storage_must_send = 0,	/* Storage belongs on other side of wire */
8031457Sminshall     storage_accessed = 0;	/* The storage is accessed (so leave alone)! */
8131457Sminshall 
8231503Sminshall static long storage[1000];
8331457Sminshall 
8431463Sminshall static union REGS inputRegs;
8531463Sminshall static struct SREGS inputSregs;
8631457Sminshall 
8731463Sminshall 
8831463Sminshall static void
8931457Sminshall kill_connection()
9031457Sminshall {
9131465Sminshall     state = UNCONNECTED;
9231465Sminshall     if (sock != -1) {
9331465Sminshall 	(void) close(sock);
9431465Sminshall 	sock = -1;
9531465Sminshall     }
9631457Sminshall }
9731457Sminshall 
9831457Sminshall 
9931457Sminshall static int
10031463Sminshall nextstore()
10131455Sminshall {
10231463Sminshall     struct storage_descriptor sd;
10331455Sminshall 
10431463Sminshall     if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
10531457Sminshall 	storage_length = 0;
10631457Sminshall 	return -1;
10731457Sminshall     }
10831798Sminshall     storage_length = sd.length;
10931798Sminshall     storage_location = sd.location;
11031463Sminshall     if (storage_length > sizeof storage) {
11131457Sminshall 	fprintf(stderr, "API client tried to send too much storage (%d).\n",
11231457Sminshall 		storage_length);
11331463Sminshall 	storage_length = 0;
11431457Sminshall 	return -1;
11531457Sminshall     }
11631511Sminshall     if (api_exch_intype(EXCH_TYPE_BYTES, storage_length, (char *)storage)
11731511Sminshall 							== -1) {
11831511Sminshall 	storage_length = 0;
11931511Sminshall 	return -1;
12031463Sminshall     }
12131471Sminshall     return 0;
12231457Sminshall }
12331457Sminshall 
12431457Sminshall 
12531457Sminshall static int
12631457Sminshall doreject(message)
12731457Sminshall char	*message;
12831457Sminshall {
12931463Sminshall     struct storage_descriptor sd;
13031457Sminshall     int length = strlen(message);
13131457Sminshall 
13231492Sminshall     if (api_exch_outcommand(EXCH_CMD_REJECTED) == -1) {
13331457Sminshall 	return -1;
13431457Sminshall     }
13531798Sminshall     sd.length = length;
13631465Sminshall     if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
13731463Sminshall 	return -1;
13831463Sminshall     }
13931463Sminshall     if (api_exch_outtype(EXCH_TYPE_BYTES, length, message) == -1) {
14031463Sminshall 	return -1;
14131463Sminshall     }
14231457Sminshall     return 0;
14331457Sminshall }
14431457Sminshall 
14531457Sminshall 
14631455Sminshall /*
14731465Sminshall  * doassociate()
14831457Sminshall  *
14931457Sminshall  * Negotiate with the other side and try to do something.
15031798Sminshall  *
15131798Sminshall  * Returns:
15231798Sminshall  *
15331798Sminshall  *	-1:	Error in processing
15431798Sminshall  *	 0:	Invalid password entered
15531798Sminshall  *	 1:	Association OK
15631457Sminshall  */
15731457Sminshall 
15831457Sminshall static int
15931465Sminshall doassociate()
16031457Sminshall {
16131457Sminshall     struct passwd *pwent;
16231457Sminshall     char
16331457Sminshall 	promptbuf[100],
16431457Sminshall 	buffer[200];
16531457Sminshall     int length;
16631457Sminshall     int was;
16731463Sminshall     struct storage_descriptor sd;
16831457Sminshall 
16931463Sminshall     if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
17031463Sminshall 	return -1;
17131457Sminshall     }
17231798Sminshall     sd.length = sd.length;
17331463Sminshall     if (sd.length > sizeof buffer) {
17431798Sminshall 	doreject("(internal error) Authentication key too long");
17531465Sminshall 	return -1;
17631457Sminshall     }
17731463Sminshall     if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) {
17831457Sminshall 	return -1;
17931457Sminshall     }
18031463Sminshall     buffer[sd.length] = 0;
18131457Sminshall 
18231798Sminshall     if (strcmp(buffer, key) != 0) {
18331798Sminshall 	if ((pwent = getpwuid(geteuid())) == 0) {
18431798Sminshall 	    return -1;
18531798Sminshall 	}
18631798Sminshall 	sprintf(promptbuf, "Enter password for user %s:", pwent->pw_name);
18731798Sminshall 	if (api_exch_outcommand(EXCH_CMD_SEND_AUTH) == -1) {
18831798Sminshall 	    return -1;
18931798Sminshall 	}
19031798Sminshall 	sd.length = strlen(promptbuf);
19131798Sminshall 	if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd)
19231798Sminshall 									== -1) {
19331798Sminshall 	    return -1;
19431798Sminshall 	}
19531798Sminshall 	if (api_exch_outtype(EXCH_TYPE_BYTES, strlen(promptbuf), promptbuf)
19631798Sminshall 									== -1) {
19731798Sminshall 	    return -1;
19831798Sminshall 	}
19931798Sminshall 	sd.length = strlen(pwent->pw_name);
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,
20531798Sminshall 			    strlen(pwent->pw_name), pwent->pw_name) == -1) {
20631798Sminshall 	    return -1;
20731798Sminshall 	}
20831798Sminshall 	if (api_exch_incommand(EXCH_CMD_AUTH) == -1) {
20931798Sminshall 	    return -1;
21031798Sminshall 	}
21131798Sminshall 	if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd)
21231798Sminshall 									== -1) {
21331798Sminshall 	    return -1;
21431798Sminshall 	}
21531798Sminshall 	sd.length = sd.length;
21631798Sminshall 	if (sd.length > sizeof buffer) {
21731798Sminshall 	    doreject("Password entered was too long");
21831798Sminshall 	    return -1;
21931798Sminshall 	}
22031798Sminshall 	if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) {
22131798Sminshall 	    return -1;
22231798Sminshall 	}
22331798Sminshall 	buffer[sd.length] = 0;
22431465Sminshall 
22531798Sminshall 	/* Is this the correct password? */
22631798Sminshall 	if (strlen(pwent->pw_name)) {
22731798Sminshall 	    char *ptr;
22831798Sminshall 	    int i;
22931798Sminshall 
23031798Sminshall 	    ptr = pwent->pw_name;
23131798Sminshall 	    i = 0;
23231798Sminshall 	    while (i < sd.length) {
23331798Sminshall 		buffer[i++] ^= *ptr++;
23431798Sminshall 		if (*ptr == 0) {
23531798Sminshall 		    ptr = pwent->pw_name;
23631798Sminshall 		}
23731465Sminshall 	    }
23831465Sminshall 	}
23931798Sminshall 	if (strcmp(crypt(buffer, pwent->pw_passwd), pwent->pw_passwd) != 0) {
24031798Sminshall 	    doreject("Invalid password");
24131798Sminshall 	    sleep(10);		/* Don't let us do too many of these */
24231798Sminshall 	    return 0;
24331798Sminshall 	}
24431465Sminshall     }
24531798Sminshall     if (api_exch_outcommand(EXCH_CMD_ASSOCIATED) == -1) {
24631798Sminshall 	return -1;
24731457Sminshall     } else {
24831798Sminshall 	return 1;
24931457Sminshall     }
25031457Sminshall }
25131457Sminshall 
25231457Sminshall 
25331457Sminshall void
25431457Sminshall freestorage()
25531457Sminshall {
25631457Sminshall     char buffer[40];
25731463Sminshall     struct storage_descriptor sd;
25831457Sminshall 
25931457Sminshall     if (storage_accessed) {
26031457Sminshall 	fprintf(stderr, "Internal error - attempt to free accessed storage.\n");
26131503Sminshall 	fprintf(stderr, "(Encountered in file %s at line %d.)\n",
26231457Sminshall 			__FILE__, __LINE__);
26331457Sminshall 	quit();
26431457Sminshall     }
26531457Sminshall     if (storage_must_send == 0) {
26631457Sminshall 	return;
26731457Sminshall     }
26831457Sminshall     storage_must_send = 0;
26931492Sminshall     if (api_exch_outcommand(EXCH_CMD_HEREIS) == -1) {
27031457Sminshall 	kill_connection();
27131457Sminshall 	return;
27231457Sminshall     }
27331798Sminshall     sd.length = storage_length;
27431798Sminshall     sd.location = storage_location;
27531463Sminshall     if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
27631457Sminshall 	kill_connection();
27731457Sminshall 	return;
27831457Sminshall     }
27931511Sminshall     if (api_exch_outtype(EXCH_TYPE_BYTES, storage_length, (char *)storage)
28031511Sminshall 							    == -1) {
28131511Sminshall 	kill_connection();
28231511Sminshall 	return;
28331463Sminshall     }
28431457Sminshall }
28531457Sminshall 
28631457Sminshall 
28731463Sminshall static int
28831508Sminshall getstorage(address, length, copyin)
28931508Sminshall int
29031508Sminshall     address,
29131508Sminshall     length,
29231508Sminshall     copyin;
29331457Sminshall {
29431463Sminshall     struct storage_descriptor sd;
29531457Sminshall     char buffer[40];
29631457Sminshall 
29731457Sminshall     freestorage();
29831457Sminshall     if (storage_accessed) {
29931457Sminshall 	fprintf(stderr,
30031457Sminshall 		"Internal error - attempt to get while storage accessed.\n");
30131503Sminshall 	fprintf(stderr, "(Encountered in file %s at line %d.)\n",
30231457Sminshall 			__FILE__, __LINE__);
30331457Sminshall 	quit();
30431457Sminshall     }
30531457Sminshall     storage_must_send = 0;
30631492Sminshall     if (api_exch_outcommand(EXCH_CMD_GIMME) == -1) {
30731457Sminshall 	kill_connection();
30831463Sminshall 	return -1;
30931457Sminshall     }
31031471Sminshall     storage_location = address;
31131471Sminshall     storage_length = length;
31231508Sminshall     if (copyin) {
31331798Sminshall 	sd.location = storage_location;
31431798Sminshall 	sd.length = storage_length;
31531508Sminshall 	if (api_exch_outtype(EXCH_TYPE_STORE_DESC,
31631508Sminshall 					sizeof sd, (char *)&sd) == -1) {
31731508Sminshall 	    kill_connection();
31831508Sminshall 	    return -1;
31931508Sminshall 	}
32031508Sminshall 	if (api_exch_incommand(EXCH_CMD_HEREIS) == -1) {
32131508Sminshall 	    fprintf(stderr, "Bad data from other side.\n");
32231508Sminshall 	    fprintf(stderr, "(Encountered at %s, %d.)\n", __FILE__, __LINE__);
32331508Sminshall 	    return -1;
32431508Sminshall 	}
32531508Sminshall 	if (nextstore() == -1) {
32631508Sminshall 	    kill_connection();
32731508Sminshall 	    return -1;
32831508Sminshall 	}
32931463Sminshall     }
33031463Sminshall     return 0;
33131457Sminshall }
33231457Sminshall 
33331457Sminshall void
33431457Sminshall movetous(local, es, di, length)
33531457Sminshall char
33631457Sminshall     *local;
33731457Sminshall int
33831457Sminshall     es,
33931457Sminshall     di;
34031457Sminshall int
34131457Sminshall     length;
34231457Sminshall {
34331457Sminshall     if (length > sizeof storage) {
34431457Sminshall 	fprintf(stderr, "Internal API error - movetous() length too long.\n");
34531457Sminshall 	fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__);
34631457Sminshall 	quit();
34731457Sminshall     } else if (length == 0) {
34831457Sminshall 	return;
34931457Sminshall     }
35031508Sminshall     getstorage(di, length, 1);
35131463Sminshall     memcpy(local, storage+(di-storage_location), length);
35231457Sminshall }
35331457Sminshall 
35431457Sminshall void
35531457Sminshall movetothem(es, di, local, length)
35631457Sminshall int
35731457Sminshall     es,
35831457Sminshall     di;
35931457Sminshall char
36031457Sminshall     *local;
36131457Sminshall int
36231457Sminshall     length;
36331457Sminshall {
36431457Sminshall     if (length > sizeof storage) {
36531457Sminshall 	fprintf(stderr, "Internal API error - movetothem() length too long.\n");
36631457Sminshall 	fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__);
36731457Sminshall 	quit();
36831457Sminshall     } else if (length == 0) {
36931457Sminshall 	return;
37031457Sminshall     }
37131457Sminshall     freestorage();
37231457Sminshall     memcpy((char *)storage, local, length);
37331457Sminshall     storage_length = length;
37431463Sminshall     storage_location = di;
37531457Sminshall     storage_must_send = 1;
37631457Sminshall }
37731457Sminshall 
37831457Sminshall 
37931457Sminshall char *
38031508Sminshall access_api(location, length, copyin)
38131457Sminshall int
38231457Sminshall     location,
38331508Sminshall     length,
38431508Sminshall     copyin;			/* Do we need to copy in initially? */
38531457Sminshall {
38631457Sminshall     if (storage_accessed) {
38731457Sminshall 	fprintf(stderr, "Internal error - storage accessed twice\n");
38831503Sminshall 	fprintf(stderr, "(Encountered in file %s, line %d.)\n",
38931457Sminshall 				__FILE__, __LINE__);
39031457Sminshall 	quit();
39131457Sminshall     } else if (length != 0) {
39231457Sminshall 	freestorage();
39331508Sminshall 	getstorage(location, length, copyin);
39431503Sminshall 	storage_accessed = 1;
39531457Sminshall     }
39631457Sminshall     return (char *) storage;
39731457Sminshall }
39831457Sminshall 
39931508Sminshall unaccess_api(location, local, length, copyout)
40031457Sminshall int	location;
40131457Sminshall char	*local;
40231457Sminshall int	length;
40331457Sminshall {
40431457Sminshall     if (storage_accessed == 0) {
40531457Sminshall 	fprintf(stderr, "Internal error - unnecessary unaccess_api call.\n");
40631503Sminshall 	fprintf(stderr, "(Encountered in file %s, line %d.)\n",
40731457Sminshall 			__FILE__, __LINE__);
40831457Sminshall 	quit();
40931457Sminshall     }
41031457Sminshall     storage_accessed = 0;
41131508Sminshall     storage_must_send = copyout;	/* if needs to go back */
41231457Sminshall }
41331457Sminshall 
41431465Sminshall /*
41531465Sminshall  * Accept a connection from an API client, aborting if the child dies.
41631465Sminshall  */
41731457Sminshall 
41831465Sminshall static int
41931465Sminshall doconnect()
42031465Sminshall {
42131465Sminshall     fd_set fdset;
42231465Sminshall     int i;
42331465Sminshall 
42431465Sminshall     sock = -1;
42531465Sminshall     FD_ZERO(&fdset);
42631465Sminshall     while (shell_active && (sock == -1)) {
42731465Sminshall 	FD_SET(serversock, &fdset);
42831465Sminshall 	if ((i = select(serversock+1, &fdset, 0, 0, 0)) < 0) {
42931465Sminshall 	    if (errno = EINTR) {
43031465Sminshall 		continue;
43131465Sminshall 	    } else {
43231465Sminshall 		perror("in select waiting for API connection");
43331465Sminshall 		return -1;
43431465Sminshall 	    }
43531465Sminshall 	} else {
43631465Sminshall 	    i = accept(serversock, 0, 0);
43731465Sminshall 	    if (i == -1) {
43831465Sminshall 		perror("accepting API connection");
43931465Sminshall 		return -1;
44031465Sminshall 	    }
44131465Sminshall 	    sock = i;
44231465Sminshall 	}
44331465Sminshall     }
44431465Sminshall     /* If the process has already exited, we may need to close */
44531465Sminshall     if ((shell_active == 0) && (sock != -1)) {
44631465Sminshall 	(void) close(sock);
44731465Sminshall 	sock = -1;
44831465Sminshall 	setcommandmode();	/* In case child_died sneaked in */
44931465Sminshall     }
45031465Sminshall }
45131465Sminshall 
45231457Sminshall /*
45331455Sminshall  * shell_continue() actually runs the command, and looks for API
45431455Sminshall  * requests coming back in.
45531455Sminshall  *
45631455Sminshall  * We are called from the main loop in telnet.c.
45731455Sminshall  */
45831455Sminshall 
45931455Sminshall int
46031455Sminshall shell_continue()
46131455Sminshall {
46231492Sminshall     int i;
46331492Sminshall 
46431457Sminshall     switch (state) {
46531457Sminshall     case DEAD:
46631457Sminshall 	pause();			/* Nothing to do */
46731457Sminshall 	break;
46831457Sminshall     case UNCONNECTED:
46931465Sminshall 	if (doconnect() == -1) {
47031457Sminshall 	    kill_connection();
47131465Sminshall 	    return -1;
47231465Sminshall 	}
47331492Sminshall 	if (api_exch_init(sock, "server") == -1) {
47431465Sminshall 	    return -1;
47531465Sminshall 	}
47631465Sminshall 	while (state == UNCONNECTED) {
47731492Sminshall 	    if (api_exch_incommand(EXCH_CMD_ASSOCIATE) == -1) {
47831457Sminshall 		kill_connection();
47931465Sminshall 		return -1;
48031465Sminshall 	    } else {
48131465Sminshall 		switch (doassociate()) {
48231465Sminshall 		case -1:
48331465Sminshall 		    kill_connection();
48431465Sminshall 		    return -1;
48531465Sminshall 		case 0:
48631465Sminshall 		    break;
48731465Sminshall 		case 1:
48831465Sminshall 		    state = CONNECTED;
48931465Sminshall 		}
49031457Sminshall 	    }
49131457Sminshall 	}
49231457Sminshall 	break;
49331457Sminshall     case CONNECTED:
49431492Sminshall 	switch (i = api_exch_nextcommand()) {
49531492Sminshall 	case EXCH_CMD_REQUEST:
49631492Sminshall 	    if (api_exch_intype(EXCH_TYPE_REGS, sizeof inputRegs,
49731492Sminshall 				    (char *)&inputRegs) == -1) {
49831463Sminshall 		kill_connection();
49931492Sminshall 	    } else if (api_exch_intype(EXCH_TYPE_SREGS, sizeof inputSregs,
50031492Sminshall 				    (char *)&inputSregs) == -1) {
50131463Sminshall 		kill_connection();
50231492Sminshall 	    } else if (nextstore() == -1) {
50331463Sminshall 		kill_connection();
50431492Sminshall 	    } else {
50531492Sminshall 		handle_api(&inputRegs, &inputSregs);
50631492Sminshall 		freestorage();			/* Send any storage back */
50731492Sminshall 		if (api_exch_outcommand(EXCH_CMD_REPLY) == -1) {
50831492Sminshall 		    kill_connection();
50931492Sminshall 		} else if (api_exch_outtype(EXCH_TYPE_REGS, sizeof inputRegs,
51031492Sminshall 				    (char *)&inputRegs) == -1) {
51131492Sminshall 		    kill_connection();
51231492Sminshall 		} else if (api_exch_outtype(EXCH_TYPE_SREGS, sizeof inputSregs,
51331492Sminshall 				    (char *)&inputSregs) == -1) {
51431492Sminshall 		    kill_connection();
51531492Sminshall 		}
51631492Sminshall 		/* Done, and it all worked! */
51731463Sminshall 	    }
51831492Sminshall 	    break;
51931492Sminshall 	case EXCH_CMD_DISASSOCIATE:
52031492Sminshall 	    kill_connection();
52131492Sminshall 	    break;
52231492Sminshall 	default:
52331503Sminshall 	    if (i != -1) {
52431503Sminshall 		fprintf(stderr,
52531503Sminshall 			"Looking for a REQUEST or DISASSOCIATE command\n");
52631503Sminshall 		fprintf(stderr, "\treceived 0x%02x.\n", i);
52731503Sminshall 	    }
52831492Sminshall 	    kill_connection();
52931503Sminshall 	    break;
53031457Sminshall 	}
53131457Sminshall     }
53231455Sminshall     return shell_active;
53331455Sminshall }
53431455Sminshall 
53531455Sminshall 
53631463Sminshall static int
53731463Sminshall child_died()
53831463Sminshall {
53931463Sminshall     union wait *status;
54031463Sminshall     register int pid;
54131463Sminshall 
54231463Sminshall     while ((pid = wait3(&status, WNOHANG, 0)) > 0) {
54331463Sminshall 	if (pid == shell_pid) {
54431463Sminshall 	    char inputbuffer[100];
54531463Sminshall 
54631463Sminshall 	    shell_active = 0;
54731463Sminshall 	    if (sock != -1) {
54831463Sminshall 		(void) close(sock);
54931463Sminshall 		sock = -1;
55031463Sminshall 	    }
55131471Sminshall 	    printf("[Hit return to continue]");
55231471Sminshall 	    fflush(stdout);
55331471Sminshall 	    (void) gets(inputbuffer);
55431465Sminshall 	    setconnmode();
55531465Sminshall 	    ConnectScreen();	/* Turn screen on (if need be) */
55631465Sminshall 	    (void) close(serversock);
55731798Sminshall 	    (void) unlink(keyname);
55831463Sminshall 	}
55931463Sminshall     }
56031463Sminshall     signal(SIGCHLD, child_died);
56131463Sminshall }
56231463Sminshall 
56331463Sminshall 
56431455Sminshall /*
56531455Sminshall  * Called from telnet.c to fork a lower command.com.  We
56631455Sminshall  * use the spint... routines so that we can pick up
56731455Sminshall  * interrupts generated by application programs.
56831455Sminshall  */
56931455Sminshall 
57031455Sminshall 
57131455Sminshall int
57231455Sminshall shell(argc,argv)
57331455Sminshall int	argc;
57431455Sminshall char	*argv[];
57531455Sminshall {
57631465Sminshall     int length;
57731457Sminshall     struct sockaddr_in server;
57831457Sminshall     char sockNAME[100];
57931457Sminshall     static char **whereAPI = 0;
58031798Sminshall     int fd;
58131798Sminshall     struct timeval tv;
58231798Sminshall     long ikey;
58331798Sminshall     extern long random();
58431798Sminshall     extern char *mktemp();
58531457Sminshall 
58631798Sminshall     /* First, create verification file. */
58731798Sminshall     do {
58831798Sminshall 	keyname = mktemp("/tmp/apiXXXXXX");
58931798Sminshall 	fd = open(keyname, O_RDWR|O_CREAT|O_EXCL, IREAD|IWRITE);
59031798Sminshall     } while ((fd == -1) && (errno == EEXIST));
59131798Sminshall 
59231798Sminshall     if (fd == -1) {
59331798Sminshall 	perror("open");
59431798Sminshall 	return 0;
59531798Sminshall     }
59631798Sminshall 
59731798Sminshall     /* Now, get seed for random */
59831798Sminshall 
59931798Sminshall     if (gettimeofday(&tv, 0) == -1) {
60031798Sminshall 	perror("gettimeofday");
60131798Sminshall 	return 0;
60231798Sminshall     }
60331798Sminshall     srandom(tv.tv_usec);		/* seed random number generator */
60431798Sminshall     do {
60531798Sminshall 	ikey = random();
60631798Sminshall     } while (ikey == 0);
60731798Sminshall     sprintf(key, "%lu\n", ikey);
60831798Sminshall     if (write(fd, key, strlen(key)) != strlen(key)) {
60931798Sminshall 	perror("write");
61031798Sminshall 	return 0;
61131798Sminshall     }
61231798Sminshall     key[strlen(key)-1] = 0;		/* Get rid of newline */
61331798Sminshall 
61431798Sminshall     if (close(fd) == -1) {
61531798Sminshall 	perror("close");
61631798Sminshall 	return 0;
61731798Sminshall     }
61831798Sminshall 
61931798Sminshall     /* Next, create the socket which will be connected to */
62031457Sminshall     serversock = socket(AF_INET, SOCK_STREAM, 0);
62131457Sminshall     if (serversock < 0) {
62231457Sminshall 	perror("opening API socket");
62331457Sminshall 	return 0;
62431457Sminshall     }
62531457Sminshall     server.sin_family = AF_INET;
62631457Sminshall     server.sin_addr.s_addr = INADDR_ANY;
62731457Sminshall     server.sin_port = 0;
62831457Sminshall     if (bind(serversock, &server, sizeof server) < 0) {
62931457Sminshall 	perror("binding API socket");
63031457Sminshall 	return 0;
63131457Sminshall     }
63231457Sminshall     length = sizeof server;
63331457Sminshall     if (getsockname(serversock, &server, &length) < 0) {
63431457Sminshall 	perror("getting API socket name");
63531457Sminshall 	(void) close(serversock);
63631457Sminshall     }
63731457Sminshall     listen(serversock, 1);
63831457Sminshall     /* Get name to advertise in address list */
63931457Sminshall     strcpy(sockNAME, "API3270=");
64031457Sminshall     gethostname(sockNAME+strlen(sockNAME), sizeof sockNAME-strlen(sockNAME));
64131798Sminshall     if (strlen(sockNAME) > (sizeof sockNAME-(10+strlen(keyname)))) {
64231457Sminshall 	fprintf(stderr, "Local hostname too large; using 'localhost'.\n");
64331457Sminshall 	strcpy(sockNAME, "localhost");
64431457Sminshall     }
64531457Sminshall     sprintf(sockNAME+strlen(sockNAME), ":%d", ntohs(server.sin_port));
64631798Sminshall     sprintf(sockNAME+strlen(sockNAME), ":%s", keyname);
64731457Sminshall 
64831457Sminshall     if (whereAPI == 0) {
64931457Sminshall 	char **ptr, **nextenv;
65031457Sminshall 	extern char **environ;
65131457Sminshall 
65231457Sminshall 	ptr = environ;
65331457Sminshall 	nextenv = ourENVlist;
65431457Sminshall 	while (*ptr) {
65531457Sminshall 	    if (nextenv >= &ourENVlist[highestof(ourENVlist)-1]) {
65631457Sminshall 		fprintf(stderr, "Too many environmental variables\n");
65731457Sminshall 		break;
65831457Sminshall 	    }
65931457Sminshall 	    *nextenv++ = *ptr++;
66031457Sminshall 	}
66131457Sminshall 	whereAPI = nextenv++;
66231457Sminshall 	*nextenv++ = 0;
66331457Sminshall 	environ = ourENVlist;		/* New environment */
66431457Sminshall     }
66531457Sminshall     *whereAPI = sockNAME;
66631457Sminshall 
66731457Sminshall     child_died();			/* Start up signal handler */
66831457Sminshall     shell_active = 1;			/* We are running down below */
66931457Sminshall     if (shell_pid = vfork()) {
67031457Sminshall 	if (shell_pid == -1) {
67131457Sminshall 	    perror("vfork");
67231457Sminshall 	    (void) close(serversock);
67331457Sminshall 	} else {
67431465Sminshall 	    state = UNCONNECTED;
67531457Sminshall 	}
67631455Sminshall     } else {				/* New process */
67731455Sminshall 	register int i;
67831455Sminshall 
67931455Sminshall 	for (i = 3; i < 30; i++) {
68031455Sminshall 	    (void) close(i);
68131455Sminshall 	}
68231455Sminshall 	if (argc == 1) {		/* Just get a shell */
68331455Sminshall 	    char *cmdname;
68431457Sminshall 	    extern char *getenv();
68531455Sminshall 
68631455Sminshall 	    cmdname = getenv("SHELL");
68731455Sminshall 	    execlp(cmdname, cmdname, 0);
68831455Sminshall 	    perror("Exec'ing new shell...\n");
68931455Sminshall 	    exit(1);
69031455Sminshall 	} else {
69131455Sminshall 	    execvp(argv[1], &argv[1]);
69231455Sminshall 	    perror("Exec'ing command.\n");
69331455Sminshall 	    exit(1);
69431455Sminshall 	}
69531455Sminshall 	/*NOTREACHED*/
69631455Sminshall     }
69731457Sminshall     return shell_active;		/* Go back to main loop */
69831455Sminshall }
699