131894Sminshall /*
233810Sbostic  * Copyright (c) 1988 Regents of the University of California.
333810Sbostic  * All rights reserved.
431894Sminshall  *
533810Sbostic  * Redistribution and use in source and binary forms are permitted
635423Sminshall  * provided that the above copyright notice and this paragraph are
735423Sminshall  * duplicated in all such forms and that any documentation,
835423Sminshall  * advertising materials, and other materials related to such
935423Sminshall  * distribution and use acknowledge that the software was developed
1035423Sminshall  * by the University of California, Berkeley.  The name of the
1135423Sminshall  * University may not be used to endorse or promote products derived
1235423Sminshall  * from this software without specific prior written permission.
1335423Sminshall  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1435423Sminshall  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1535423Sminshall  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1631894Sminshall  */
1731894Sminshall 
1831894Sminshall #ifndef lint
19*47031Sdonn static char sccsid[] = "@(#)system.c	4.4 (Berkeley) 03/06/91";
2033810Sbostic #endif /* not lint */
2131894Sminshall 
2231457Sminshall #include <sys/types.h>
2331863Sminshall 
2433269Sminshall #if     defined(pyr)
2533269Sminshall #define fd_set fdset_t
2633269Sminshall #endif  /* defined(pyr) */
2733269Sminshall 
2838211Sminshall /*
2938211Sminshall  * Wouldn't it be nice if these REALLY were in <sys/inode.h>?  Or,
3038211Sminshall  * equivalently, if <sys/inode.h> REALLY existed?
3138211Sminshall  */
3231863Sminshall #define	IREAD	00400
3331863Sminshall #define	IWRITE	00200
3431863Sminshall 
3531798Sminshall #include <sys/file.h>
3631798Sminshall #include <sys/time.h>
3731457Sminshall #include <sys/socket.h>
3831457Sminshall #include <netinet/in.h>
3931455Sminshall #include <sys/wait.h>
4031455Sminshall 
4131457Sminshall #include <errno.h>
4231457Sminshall extern int errno;
4331457Sminshall 
4431457Sminshall #include <netdb.h>
4531457Sminshall #include <signal.h>
4631455Sminshall #include <stdio.h>
47*47031Sdonn #include <string.h>
4831457Sminshall #include <pwd.h>
4931455Sminshall 
5031455Sminshall #include "../general/general.h"
5131873Sminshall #include "../ctlr/api.h"
5231873Sminshall #include "../api/api_exch.h"
5331455Sminshall 
5431455Sminshall #include "../general/globals.h"
5531455Sminshall 
5631795Sminshall #ifndef	FD_SETSIZE
5731795Sminshall /*
5831795Sminshall  * The following is defined just in case someone should want to run
5931795Sminshall  * this telnet on a 4.2 system.
6031795Sminshall  *
6131795Sminshall  */
6231455Sminshall 
6331795Sminshall #define	FD_SET(n, p)	((p)->fds_bits[0] |= (1<<(n)))
6431795Sminshall #define	FD_CLR(n, p)	((p)->fds_bits[0] &= ~(1<<(n)))
6531795Sminshall #define	FD_ISSET(n, p)	((p)->fds_bits[0] & (1<<(n)))
6631795Sminshall #define FD_ZERO(p)	((p)->fds_bits[0] = 0)
6731795Sminshall 
6831795Sminshall #endif
6931795Sminshall 
7031455Sminshall static int shell_pid = 0;
7131798Sminshall static char key[50];			/* Actual key */
7231798Sminshall static char *keyname;			/* Name of file with key in it */
7331455Sminshall 
7431457Sminshall static char *ourENVlist[200];		/* Lots of room */
7531457Sminshall 
7631465Sminshall static int
7731465Sminshall     sock = -1,				/* Connected socket */
7831465Sminshall     serversock;				/* Server (listening) socket */
7931457Sminshall 
8031457Sminshall static enum { DEAD, UNCONNECTED, CONNECTED } state;
8131457Sminshall 
8235423Sminshall static long
8335423Sminshall     storage_location;		/* Address we have */
8435423Sminshall static short
8535423Sminshall     storage_length = 0;		/* Length we have */
8631455Sminshall static int
8731457Sminshall     storage_must_send = 0,	/* Storage belongs on other side of wire */
8831457Sminshall     storage_accessed = 0;	/* The storage is accessed (so leave alone)! */
8931457Sminshall 
9031503Sminshall static long storage[1000];
9131457Sminshall 
9231463Sminshall static union REGS inputRegs;
9331463Sminshall static struct SREGS inputSregs;
9431457Sminshall 
9538923Sminshall extern int apitrace;
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];
17431463Sminshall     struct storage_descriptor sd;
17535423Sminshall     extern char *crypt();
17631457Sminshall 
17731463Sminshall     if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
17831463Sminshall 	return -1;
17931457Sminshall     }
18031798Sminshall     sd.length = sd.length;
18131463Sminshall     if (sd.length > sizeof buffer) {
18231798Sminshall 	doreject("(internal error) Authentication key too long");
18331465Sminshall 	return -1;
18431457Sminshall     }
18531463Sminshall     if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) {
18631457Sminshall 	return -1;
18731457Sminshall     }
18831463Sminshall     buffer[sd.length] = 0;
18931457Sminshall 
19031798Sminshall     if (strcmp(buffer, key) != 0) {
19135493Sminshall #if	(!defined(sun)) || defined(BSD) && (BSD >= 43)
19235423Sminshall 	extern uid_t geteuid();
19335493Sminshall #endif	/* (!defined(sun)) || defined(BSD) && (BSD >= 43) */
19435423Sminshall 
19535423Sminshall 	if ((pwent = getpwuid((int)geteuid())) == 0) {
19631798Sminshall 	    return -1;
19731798Sminshall 	}
19831798Sminshall 	sprintf(promptbuf, "Enter password for user %s:", pwent->pw_name);
19931798Sminshall 	if (api_exch_outcommand(EXCH_CMD_SEND_AUTH) == -1) {
20031798Sminshall 	    return -1;
20131798Sminshall 	}
20231798Sminshall 	sd.length = strlen(promptbuf);
20331798Sminshall 	if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd)
20431798Sminshall 									== -1) {
20531798Sminshall 	    return -1;
20631798Sminshall 	}
20731798Sminshall 	if (api_exch_outtype(EXCH_TYPE_BYTES, strlen(promptbuf), promptbuf)
20831798Sminshall 									== -1) {
20931798Sminshall 	    return -1;
21031798Sminshall 	}
21131798Sminshall 	sd.length = strlen(pwent->pw_name);
21231798Sminshall 	if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd)
21331798Sminshall 									== -1) {
21431798Sminshall 	    return -1;
21531798Sminshall 	}
21631798Sminshall 	if (api_exch_outtype(EXCH_TYPE_BYTES,
21731798Sminshall 			    strlen(pwent->pw_name), pwent->pw_name) == -1) {
21831798Sminshall 	    return -1;
21931798Sminshall 	}
22031798Sminshall 	if (api_exch_incommand(EXCH_CMD_AUTH) == -1) {
22131798Sminshall 	    return -1;
22231798Sminshall 	}
22331798Sminshall 	if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd)
22431798Sminshall 									== -1) {
22531798Sminshall 	    return -1;
22631798Sminshall 	}
22731798Sminshall 	sd.length = sd.length;
22831798Sminshall 	if (sd.length > sizeof buffer) {
22931798Sminshall 	    doreject("Password entered was too long");
23031798Sminshall 	    return -1;
23131798Sminshall 	}
23231798Sminshall 	if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) {
23331798Sminshall 	    return -1;
23431798Sminshall 	}
23531798Sminshall 	buffer[sd.length] = 0;
23631465Sminshall 
23731798Sminshall 	/* Is this the correct password? */
23831798Sminshall 	if (strlen(pwent->pw_name)) {
23931798Sminshall 	    char *ptr;
24031798Sminshall 	    int i;
24131798Sminshall 
24231798Sminshall 	    ptr = pwent->pw_name;
24331798Sminshall 	    i = 0;
24431798Sminshall 	    while (i < sd.length) {
24531798Sminshall 		buffer[i++] ^= *ptr++;
24631798Sminshall 		if (*ptr == 0) {
24731798Sminshall 		    ptr = pwent->pw_name;
24831798Sminshall 		}
24931465Sminshall 	    }
25031465Sminshall 	}
25131798Sminshall 	if (strcmp(crypt(buffer, pwent->pw_passwd), pwent->pw_passwd) != 0) {
25231798Sminshall 	    doreject("Invalid password");
25331798Sminshall 	    sleep(10);		/* Don't let us do too many of these */
25431798Sminshall 	    return 0;
25531798Sminshall 	}
25631465Sminshall     }
25731798Sminshall     if (api_exch_outcommand(EXCH_CMD_ASSOCIATED) == -1) {
25831798Sminshall 	return -1;
25931457Sminshall     } else {
26031798Sminshall 	return 1;
26131457Sminshall     }
26231457Sminshall }
26331457Sminshall 
26431457Sminshall 
26531457Sminshall void
26631457Sminshall freestorage()
26731457Sminshall {
26831463Sminshall     struct storage_descriptor sd;
26931457Sminshall 
27031457Sminshall     if (storage_accessed) {
27131457Sminshall 	fprintf(stderr, "Internal error - attempt to free accessed storage.\n");
27231503Sminshall 	fprintf(stderr, "(Encountered in file %s at line %d.)\n",
27331457Sminshall 			__FILE__, __LINE__);
27431457Sminshall 	quit();
27531457Sminshall     }
27631457Sminshall     if (storage_must_send == 0) {
27731457Sminshall 	return;
27831457Sminshall     }
27931457Sminshall     storage_must_send = 0;
28031492Sminshall     if (api_exch_outcommand(EXCH_CMD_HEREIS) == -1) {
28131457Sminshall 	kill_connection();
28231457Sminshall 	return;
28331457Sminshall     }
28431798Sminshall     sd.length = storage_length;
28531798Sminshall     sd.location = storage_location;
28631463Sminshall     if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
28731457Sminshall 	kill_connection();
28831457Sminshall 	return;
28931457Sminshall     }
29031511Sminshall     if (api_exch_outtype(EXCH_TYPE_BYTES, storage_length, (char *)storage)
29131511Sminshall 							    == -1) {
29231511Sminshall 	kill_connection();
29331511Sminshall 	return;
29431463Sminshall     }
29531457Sminshall }
29631457Sminshall 
29731457Sminshall 
29831463Sminshall static int
29931508Sminshall getstorage(address, length, copyin)
30035423Sminshall long
30135423Sminshall     address;
30231508Sminshall int
30331508Sminshall     length,
30431508Sminshall     copyin;
30531457Sminshall {
30631463Sminshall     struct storage_descriptor sd;
30731457Sminshall 
30831457Sminshall     freestorage();
30931457Sminshall     if (storage_accessed) {
31031457Sminshall 	fprintf(stderr,
31131457Sminshall 		"Internal error - attempt to get while storage accessed.\n");
31231503Sminshall 	fprintf(stderr, "(Encountered in file %s at line %d.)\n",
31331457Sminshall 			__FILE__, __LINE__);
31431457Sminshall 	quit();
31531457Sminshall     }
31631457Sminshall     storage_must_send = 0;
31731492Sminshall     if (api_exch_outcommand(EXCH_CMD_GIMME) == -1) {
31831457Sminshall 	kill_connection();
31931463Sminshall 	return -1;
32031457Sminshall     }
32131471Sminshall     storage_location = address;
32231471Sminshall     storage_length = length;
32331508Sminshall     if (copyin) {
32435423Sminshall 	sd.location = (long)storage_location;
32531798Sminshall 	sd.length = storage_length;
32631508Sminshall 	if (api_exch_outtype(EXCH_TYPE_STORE_DESC,
32731508Sminshall 					sizeof sd, (char *)&sd) == -1) {
32831508Sminshall 	    kill_connection();
32931508Sminshall 	    return -1;
33031508Sminshall 	}
33131508Sminshall 	if (api_exch_incommand(EXCH_CMD_HEREIS) == -1) {
33231508Sminshall 	    fprintf(stderr, "Bad data from other side.\n");
33331508Sminshall 	    fprintf(stderr, "(Encountered at %s, %d.)\n", __FILE__, __LINE__);
33431508Sminshall 	    return -1;
33531508Sminshall 	}
33631508Sminshall 	if (nextstore() == -1) {
33731508Sminshall 	    kill_connection();
33831508Sminshall 	    return -1;
33931508Sminshall 	}
34031463Sminshall     }
34131463Sminshall     return 0;
34231457Sminshall }
34331457Sminshall 
34435423Sminshall /*ARGSUSED*/
34531457Sminshall void
34631457Sminshall movetous(local, es, di, length)
34731457Sminshall char
34831457Sminshall     *local;
34935423Sminshall unsigned int
35031457Sminshall     es,
35131457Sminshall     di;
35231457Sminshall int
35331457Sminshall     length;
35431457Sminshall {
35535423Sminshall     long where = SEG_OFF_BACK(es, di);
35635423Sminshall 
35731457Sminshall     if (length > sizeof storage) {
35831457Sminshall 	fprintf(stderr, "Internal API error - movetous() length too long.\n");
35931457Sminshall 	fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__);
36031457Sminshall 	quit();
36131457Sminshall     } else if (length == 0) {
36231457Sminshall 	return;
36331457Sminshall     }
36435423Sminshall     getstorage(where, length, 1);
36535423Sminshall     memcpy(local, (char *)(storage+((where-storage_location))), length);
36638923Sminshall     if (apitrace) {
36738923Sminshall 	Dump('(', local, length);
36838923Sminshall     }
36931457Sminshall }
37031457Sminshall 
37135423Sminshall /*ARGSUSED*/
37231457Sminshall void
37331457Sminshall movetothem(es, di, local, length)
37435423Sminshall unsigned int
37531457Sminshall     es,
37631457Sminshall     di;
37731457Sminshall char
37831457Sminshall     *local;
37931457Sminshall int
38031457Sminshall     length;
38131457Sminshall {
38235423Sminshall     long where = SEG_OFF_BACK(es, di);
38335423Sminshall 
38431457Sminshall     if (length > sizeof storage) {
38531457Sminshall 	fprintf(stderr, "Internal API error - movetothem() length too long.\n");
38631457Sminshall 	fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__);
38731457Sminshall 	quit();
38831457Sminshall     } else if (length == 0) {
38931457Sminshall 	return;
39031457Sminshall     }
39131457Sminshall     freestorage();
39231457Sminshall     memcpy((char *)storage, local, length);
39338923Sminshall     if (apitrace) {
39438923Sminshall 	Dump(')', local, length);
39538923Sminshall     }
39631457Sminshall     storage_length = length;
39735423Sminshall     storage_location = where;
39831457Sminshall     storage_must_send = 1;
39931457Sminshall }
40031457Sminshall 
40131457Sminshall 
40231457Sminshall char *
40331508Sminshall access_api(location, length, copyin)
40435423Sminshall char *
40535423Sminshall     location;
40631457Sminshall int
40731508Sminshall     length,
40831508Sminshall     copyin;			/* Do we need to copy in initially? */
40931457Sminshall {
41031457Sminshall     if (storage_accessed) {
41131457Sminshall 	fprintf(stderr, "Internal error - storage accessed twice\n");
41231503Sminshall 	fprintf(stderr, "(Encountered in file %s, line %d.)\n",
41331457Sminshall 				__FILE__, __LINE__);
41431457Sminshall 	quit();
41531457Sminshall     } else if (length != 0) {
41631457Sminshall 	freestorage();
41735423Sminshall 	getstorage((long)location, length, copyin);
41831503Sminshall 	storage_accessed = 1;
41931457Sminshall     }
42031457Sminshall     return (char *) storage;
42131457Sminshall }
42231457Sminshall 
42335423Sminshall /*ARGSUSED*/
42435423Sminshall void
42531508Sminshall unaccess_api(location, local, length, copyout)
42635423Sminshall char 	*location;
42731457Sminshall char	*local;
42831457Sminshall int	length;
42935423Sminshall int	copyout;
43031457Sminshall {
43131457Sminshall     if (storage_accessed == 0) {
43231457Sminshall 	fprintf(stderr, "Internal error - unnecessary unaccess_api call.\n");
43331503Sminshall 	fprintf(stderr, "(Encountered in file %s, line %d.)\n",
43431457Sminshall 			__FILE__, __LINE__);
43531457Sminshall 	quit();
43631457Sminshall     }
43731457Sminshall     storage_accessed = 0;
43831508Sminshall     storage_must_send = copyout;	/* if needs to go back */
43931457Sminshall }
44031457Sminshall 
44131465Sminshall /*
44231465Sminshall  * Accept a connection from an API client, aborting if the child dies.
44331465Sminshall  */
44431457Sminshall 
44531465Sminshall static int
44631465Sminshall doconnect()
44731465Sminshall {
44831465Sminshall     fd_set fdset;
44931465Sminshall     int i;
45031465Sminshall 
45131465Sminshall     sock = -1;
45231465Sminshall     FD_ZERO(&fdset);
45331465Sminshall     while (shell_active && (sock == -1)) {
45431465Sminshall 	FD_SET(serversock, &fdset);
45535423Sminshall 	if ((i = select(serversock+1, &fdset,
45635423Sminshall 		    (fd_set *)0, (fd_set *)0, (struct timeval *)0)) < 0) {
45731465Sminshall 	    if (errno = EINTR) {
45831465Sminshall 		continue;
45931465Sminshall 	    } else {
46031465Sminshall 		perror("in select waiting for API connection");
46131465Sminshall 		return -1;
46231465Sminshall 	    }
46331465Sminshall 	} else {
46435423Sminshall 	    i = accept(serversock, (struct sockaddr *)0, (int *)0);
46531465Sminshall 	    if (i == -1) {
46631465Sminshall 		perror("accepting API connection");
46731465Sminshall 		return -1;
46831465Sminshall 	    }
46931465Sminshall 	    sock = i;
47031465Sminshall 	}
47131465Sminshall     }
47231465Sminshall     /* If the process has already exited, we may need to close */
47331465Sminshall     if ((shell_active == 0) && (sock != -1)) {
47435423Sminshall 	extern void setcommandmode();
47535423Sminshall 
47631465Sminshall 	(void) close(sock);
47731465Sminshall 	sock = -1;
47831465Sminshall 	setcommandmode();	/* In case child_died sneaked in */
47931465Sminshall     }
48035423Sminshall     return 0;
48131465Sminshall }
48231465Sminshall 
48331457Sminshall /*
48431455Sminshall  * shell_continue() actually runs the command, and looks for API
48531455Sminshall  * requests coming back in.
48631455Sminshall  *
48731455Sminshall  * We are called from the main loop in telnet.c.
48831455Sminshall  */
48931455Sminshall 
49031455Sminshall int
49131455Sminshall shell_continue()
49231455Sminshall {
49331492Sminshall     int i;
49431492Sminshall 
49531457Sminshall     switch (state) {
49631457Sminshall     case DEAD:
49731457Sminshall 	pause();			/* Nothing to do */
49831457Sminshall 	break;
49931457Sminshall     case UNCONNECTED:
50031465Sminshall 	if (doconnect() == -1) {
50131457Sminshall 	    kill_connection();
50231465Sminshall 	    return -1;
50331465Sminshall 	}
50438211Sminshall 	/* At this point, it is possible that we've gone away */
50538211Sminshall 	if (shell_active == 0) {
50638211Sminshall 	    kill_connection();
50738211Sminshall 	    return -1;
50838211Sminshall 	}
50931492Sminshall 	if (api_exch_init(sock, "server") == -1) {
51031465Sminshall 	    return -1;
51131465Sminshall 	}
51231465Sminshall 	while (state == UNCONNECTED) {
51331492Sminshall 	    if (api_exch_incommand(EXCH_CMD_ASSOCIATE) == -1) {
51431457Sminshall 		kill_connection();
51531465Sminshall 		return -1;
51631465Sminshall 	    } else {
51731465Sminshall 		switch (doassociate()) {
51831465Sminshall 		case -1:
51931465Sminshall 		    kill_connection();
52031465Sminshall 		    return -1;
52131465Sminshall 		case 0:
52231465Sminshall 		    break;
52331465Sminshall 		case 1:
52431465Sminshall 		    state = CONNECTED;
52531465Sminshall 		}
52631457Sminshall 	    }
52731457Sminshall 	}
52831457Sminshall 	break;
52931457Sminshall     case CONNECTED:
53031492Sminshall 	switch (i = api_exch_nextcommand()) {
53131492Sminshall 	case EXCH_CMD_REQUEST:
53231492Sminshall 	    if (api_exch_intype(EXCH_TYPE_REGS, sizeof inputRegs,
53331492Sminshall 				    (char *)&inputRegs) == -1) {
53431463Sminshall 		kill_connection();
53531492Sminshall 	    } else if (api_exch_intype(EXCH_TYPE_SREGS, sizeof inputSregs,
53631492Sminshall 				    (char *)&inputSregs) == -1) {
53731463Sminshall 		kill_connection();
53831492Sminshall 	    } else if (nextstore() == -1) {
53931463Sminshall 		kill_connection();
54031492Sminshall 	    } else {
54131492Sminshall 		handle_api(&inputRegs, &inputSregs);
54231492Sminshall 		freestorage();			/* Send any storage back */
54331492Sminshall 		if (api_exch_outcommand(EXCH_CMD_REPLY) == -1) {
54431492Sminshall 		    kill_connection();
54531492Sminshall 		} else if (api_exch_outtype(EXCH_TYPE_REGS, sizeof inputRegs,
54631492Sminshall 				    (char *)&inputRegs) == -1) {
54731492Sminshall 		    kill_connection();
54831492Sminshall 		} else if (api_exch_outtype(EXCH_TYPE_SREGS, sizeof inputSregs,
54931492Sminshall 				    (char *)&inputSregs) == -1) {
55031492Sminshall 		    kill_connection();
55131492Sminshall 		}
55231492Sminshall 		/* Done, and it all worked! */
55331463Sminshall 	    }
55431492Sminshall 	    break;
55531492Sminshall 	case EXCH_CMD_DISASSOCIATE:
55631492Sminshall 	    kill_connection();
55731492Sminshall 	    break;
55831492Sminshall 	default:
55931503Sminshall 	    if (i != -1) {
56031503Sminshall 		fprintf(stderr,
56131503Sminshall 			"Looking for a REQUEST or DISASSOCIATE command\n");
56231503Sminshall 		fprintf(stderr, "\treceived 0x%02x.\n", i);
56331503Sminshall 	    }
56431492Sminshall 	    kill_connection();
56531503Sminshall 	    break;
56631457Sminshall 	}
56731457Sminshall     }
56831455Sminshall     return shell_active;
56931455Sminshall }
57031455Sminshall 
57131455Sminshall 
572*47031Sdonn static void
573*47031Sdonn child_died(code)
57431463Sminshall {
57535423Sminshall     union wait status;
57631463Sminshall     register int pid;
57731463Sminshall 
578*47031Sdonn     while ((pid = wait3((int *)&status, WNOHANG, (struct rusage *)0)) > 0) {
57931463Sminshall 	if (pid == shell_pid) {
58031463Sminshall 	    char inputbuffer[100];
58135423Sminshall 	    extern void setconnmode();
58235423Sminshall 	    extern void ConnectScreen();
58331463Sminshall 
58431463Sminshall 	    shell_active = 0;
58531463Sminshall 	    if (sock != -1) {
58631463Sminshall 		(void) close(sock);
58731463Sminshall 		sock = -1;
58831463Sminshall 	    }
58931471Sminshall 	    printf("[Hit return to continue]");
59031471Sminshall 	    fflush(stdout);
59131471Sminshall 	    (void) gets(inputbuffer);
59231465Sminshall 	    setconnmode();
59331465Sminshall 	    ConnectScreen();	/* Turn screen on (if need be) */
59431465Sminshall 	    (void) close(serversock);
59531798Sminshall 	    (void) unlink(keyname);
59631463Sminshall 	}
59731463Sminshall     }
59831463Sminshall     signal(SIGCHLD, child_died);
59931463Sminshall }
60031463Sminshall 
60131463Sminshall 
60231455Sminshall /*
60331455Sminshall  * Called from telnet.c to fork a lower command.com.  We
60431455Sminshall  * use the spint... routines so that we can pick up
60531455Sminshall  * interrupts generated by application programs.
60631455Sminshall  */
60731455Sminshall 
60831455Sminshall 
60931455Sminshall int
61031455Sminshall shell(argc,argv)
61131455Sminshall int	argc;
61231455Sminshall char	*argv[];
61331455Sminshall {
61431465Sminshall     int length;
61531457Sminshall     struct sockaddr_in server;
61631457Sminshall     char sockNAME[100];
61731457Sminshall     static char **whereAPI = 0;
61831798Sminshall     int fd;
61931798Sminshall     struct timeval tv;
62031798Sminshall     long ikey;
62131798Sminshall     extern long random();
62231798Sminshall     extern char *mktemp();
62335423Sminshall     extern char *strcpy();
62431457Sminshall 
62531798Sminshall     /* First, create verification file. */
62631798Sminshall     do {
627*47031Sdonn 	keyname = mktemp(strdup("/tmp/apiXXXXXX"));
62831798Sminshall 	fd = open(keyname, O_RDWR|O_CREAT|O_EXCL, IREAD|IWRITE);
62931798Sminshall     } while ((fd == -1) && (errno == EEXIST));
63031798Sminshall 
63131798Sminshall     if (fd == -1) {
63231798Sminshall 	perror("open");
63331798Sminshall 	return 0;
63431798Sminshall     }
63531798Sminshall 
63631798Sminshall     /* Now, get seed for random */
63731798Sminshall 
63835423Sminshall     if (gettimeofday(&tv, (struct timezone *)0) == -1) {
63931798Sminshall 	perror("gettimeofday");
64031798Sminshall 	return 0;
64131798Sminshall     }
64231798Sminshall     srandom(tv.tv_usec);		/* seed random number generator */
64331798Sminshall     do {
64431798Sminshall 	ikey = random();
64531798Sminshall     } while (ikey == 0);
64635423Sminshall     sprintf(key, "%lu\n", (unsigned long) ikey);
64731798Sminshall     if (write(fd, key, strlen(key)) != strlen(key)) {
64831798Sminshall 	perror("write");
64931798Sminshall 	return 0;
65031798Sminshall     }
65131798Sminshall     key[strlen(key)-1] = 0;		/* Get rid of newline */
65231798Sminshall 
65331798Sminshall     if (close(fd) == -1) {
65431798Sminshall 	perror("close");
65531798Sminshall 	return 0;
65631798Sminshall     }
65731798Sminshall 
65831798Sminshall     /* Next, create the socket which will be connected to */
65931457Sminshall     serversock = socket(AF_INET, SOCK_STREAM, 0);
66031457Sminshall     if (serversock < 0) {
66131457Sminshall 	perror("opening API socket");
66231457Sminshall 	return 0;
66331457Sminshall     }
66431457Sminshall     server.sin_family = AF_INET;
66531457Sminshall     server.sin_addr.s_addr = INADDR_ANY;
66631457Sminshall     server.sin_port = 0;
66735423Sminshall     if (bind(serversock, (struct sockaddr *)&server, sizeof server) < 0) {
66831457Sminshall 	perror("binding API socket");
66931457Sminshall 	return 0;
67031457Sminshall     }
67131457Sminshall     length = sizeof server;
67235423Sminshall     if (getsockname(serversock, (struct sockaddr *)&server, &length) < 0) {
67331457Sminshall 	perror("getting API socket name");
67431457Sminshall 	(void) close(serversock);
67531457Sminshall     }
67631457Sminshall     listen(serversock, 1);
67731457Sminshall     /* Get name to advertise in address list */
67831457Sminshall     strcpy(sockNAME, "API3270=");
67931457Sminshall     gethostname(sockNAME+strlen(sockNAME), sizeof sockNAME-strlen(sockNAME));
68031798Sminshall     if (strlen(sockNAME) > (sizeof sockNAME-(10+strlen(keyname)))) {
68131457Sminshall 	fprintf(stderr, "Local hostname too large; using 'localhost'.\n");
68231457Sminshall 	strcpy(sockNAME, "localhost");
68331457Sminshall     }
68435423Sminshall     sprintf(sockNAME+strlen(sockNAME), ":%u", ntohs(server.sin_port));
68531798Sminshall     sprintf(sockNAME+strlen(sockNAME), ":%s", keyname);
68631457Sminshall 
68731457Sminshall     if (whereAPI == 0) {
68831457Sminshall 	char **ptr, **nextenv;
68931457Sminshall 	extern char **environ;
69031457Sminshall 
69131457Sminshall 	ptr = environ;
69231457Sminshall 	nextenv = ourENVlist;
69331457Sminshall 	while (*ptr) {
69431457Sminshall 	    if (nextenv >= &ourENVlist[highestof(ourENVlist)-1]) {
69531457Sminshall 		fprintf(stderr, "Too many environmental variables\n");
69631457Sminshall 		break;
69731457Sminshall 	    }
69831457Sminshall 	    *nextenv++ = *ptr++;
69931457Sminshall 	}
70031457Sminshall 	whereAPI = nextenv++;
70131457Sminshall 	*nextenv++ = 0;
70231457Sminshall 	environ = ourENVlist;		/* New environment */
70331457Sminshall     }
70431457Sminshall     *whereAPI = sockNAME;
70531457Sminshall 
70631457Sminshall     child_died();			/* Start up signal handler */
70731457Sminshall     shell_active = 1;			/* We are running down below */
70831457Sminshall     if (shell_pid = vfork()) {
70931457Sminshall 	if (shell_pid == -1) {
71031457Sminshall 	    perror("vfork");
71131457Sminshall 	    (void) close(serversock);
71231457Sminshall 	} else {
71331465Sminshall 	    state = UNCONNECTED;
71431457Sminshall 	}
71531455Sminshall     } else {				/* New process */
71631455Sminshall 	register int i;
71731455Sminshall 
71831455Sminshall 	for (i = 3; i < 30; i++) {
71931455Sminshall 	    (void) close(i);
72031455Sminshall 	}
72131455Sminshall 	if (argc == 1) {		/* Just get a shell */
72231455Sminshall 	    char *cmdname;
72331457Sminshall 	    extern char *getenv();
72431455Sminshall 
72531455Sminshall 	    cmdname = getenv("SHELL");
72631455Sminshall 	    execlp(cmdname, cmdname, 0);
72731455Sminshall 	    perror("Exec'ing new shell...\n");
72831455Sminshall 	    exit(1);
72931455Sminshall 	} else {
73031455Sminshall 	    execvp(argv[1], &argv[1]);
73131455Sminshall 	    perror("Exec'ing command.\n");
73231455Sminshall 	    exit(1);
73331455Sminshall 	}
73431455Sminshall 	/*NOTREACHED*/
73531455Sminshall     }
73631457Sminshall     return shell_active;		/* Go back to main loop */
73731455Sminshall }
738