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*38211Sminshall static char sccsid[] = "@(#)system.c 4.2 (Berkeley) 05/30/89"; 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 28*38211Sminshall /* 29*38211Sminshall * Wouldn't it be nice if these REALLY were in <sys/inode.h>? Or, 30*38211Sminshall * equivalently, if <sys/inode.h> REALLY existed? 31*38211Sminshall */ 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> 4731457Sminshall #include <pwd.h> 4831455Sminshall 4931455Sminshall #include "../general/general.h" 5031873Sminshall #include "../ctlr/api.h" 5131873Sminshall #include "../api/api_exch.h" 5231455Sminshall 5331455Sminshall #include "../general/globals.h" 5431455Sminshall 5531795Sminshall #ifndef FD_SETSIZE 5631795Sminshall /* 5731795Sminshall * The following is defined just in case someone should want to run 5831795Sminshall * this telnet on a 4.2 system. 5931795Sminshall * 6031795Sminshall */ 6131455Sminshall 6231795Sminshall #define FD_SET(n, p) ((p)->fds_bits[0] |= (1<<(n))) 6331795Sminshall #define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1<<(n))) 6431795Sminshall #define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n))) 6531795Sminshall #define FD_ZERO(p) ((p)->fds_bits[0] = 0) 6631795Sminshall 6731795Sminshall #endif 6831795Sminshall 6931455Sminshall static int shell_pid = 0; 7031798Sminshall static char key[50]; /* Actual key */ 7131798Sminshall static char *keyname; /* Name of file with key in it */ 7231455Sminshall 7331457Sminshall static char *ourENVlist[200]; /* Lots of room */ 7431457Sminshall 7531465Sminshall static int 7631465Sminshall sock = -1, /* Connected socket */ 7731465Sminshall serversock; /* Server (listening) socket */ 7831457Sminshall 7931457Sminshall static enum { DEAD, UNCONNECTED, CONNECTED } state; 8031457Sminshall 8135423Sminshall static long 8235423Sminshall storage_location; /* Address we have */ 8335423Sminshall static short 8435423Sminshall storage_length = 0; /* Length we have */ 8531455Sminshall static int 8631457Sminshall storage_must_send = 0, /* Storage belongs on other side of wire */ 8731457Sminshall storage_accessed = 0; /* The storage is accessed (so leave alone)! */ 8831457Sminshall 8931503Sminshall static long storage[1000]; 9031457Sminshall 9131463Sminshall static union REGS inputRegs; 9231463Sminshall static struct SREGS inputSregs; 9331457Sminshall 9431463Sminshall 9531463Sminshall static void 9631457Sminshall kill_connection() 9731457Sminshall { 9831465Sminshall state = UNCONNECTED; 9931465Sminshall if (sock != -1) { 10031465Sminshall (void) close(sock); 10131465Sminshall sock = -1; 10231465Sminshall } 10331457Sminshall } 10431457Sminshall 10531457Sminshall 10631457Sminshall static int 10731463Sminshall nextstore() 10831455Sminshall { 10931463Sminshall struct storage_descriptor sd; 11031455Sminshall 11131463Sminshall if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 11231457Sminshall storage_length = 0; 11331457Sminshall return -1; 11431457Sminshall } 11531798Sminshall storage_length = sd.length; 11631798Sminshall storage_location = sd.location; 11731463Sminshall if (storage_length > sizeof storage) { 11831457Sminshall fprintf(stderr, "API client tried to send too much storage (%d).\n", 11931457Sminshall storage_length); 12031463Sminshall storage_length = 0; 12131457Sminshall return -1; 12231457Sminshall } 12331511Sminshall if (api_exch_intype(EXCH_TYPE_BYTES, storage_length, (char *)storage) 12431511Sminshall == -1) { 12531511Sminshall storage_length = 0; 12631511Sminshall return -1; 12731463Sminshall } 12831471Sminshall return 0; 12931457Sminshall } 13031457Sminshall 13131457Sminshall 13231457Sminshall static int 13331457Sminshall doreject(message) 13431457Sminshall char *message; 13531457Sminshall { 13631463Sminshall struct storage_descriptor sd; 13731457Sminshall int length = strlen(message); 13831457Sminshall 13931492Sminshall if (api_exch_outcommand(EXCH_CMD_REJECTED) == -1) { 14031457Sminshall return -1; 14131457Sminshall } 14231798Sminshall sd.length = length; 14331465Sminshall if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 14431463Sminshall return -1; 14531463Sminshall } 14631463Sminshall if (api_exch_outtype(EXCH_TYPE_BYTES, length, message) == -1) { 14731463Sminshall return -1; 14831463Sminshall } 14931457Sminshall return 0; 15031457Sminshall } 15131457Sminshall 15231457Sminshall 15331455Sminshall /* 15431465Sminshall * doassociate() 15531457Sminshall * 15631457Sminshall * Negotiate with the other side and try to do something. 15731798Sminshall * 15831798Sminshall * Returns: 15931798Sminshall * 16031798Sminshall * -1: Error in processing 16131798Sminshall * 0: Invalid password entered 16231798Sminshall * 1: Association OK 16331457Sminshall */ 16431457Sminshall 16531457Sminshall static int 16631465Sminshall doassociate() 16731457Sminshall { 16831457Sminshall struct passwd *pwent; 16931457Sminshall char 17031457Sminshall promptbuf[100], 17131457Sminshall buffer[200]; 17231463Sminshall struct storage_descriptor sd; 17335423Sminshall extern char *crypt(); 17431457Sminshall 17531463Sminshall if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 17631463Sminshall return -1; 17731457Sminshall } 17831798Sminshall sd.length = sd.length; 17931463Sminshall if (sd.length > sizeof buffer) { 18031798Sminshall doreject("(internal error) Authentication key too long"); 18131465Sminshall return -1; 18231457Sminshall } 18331463Sminshall if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) { 18431457Sminshall return -1; 18531457Sminshall } 18631463Sminshall buffer[sd.length] = 0; 18731457Sminshall 18831798Sminshall if (strcmp(buffer, key) != 0) { 18935493Sminshall #if (!defined(sun)) || defined(BSD) && (BSD >= 43) 19035423Sminshall extern uid_t geteuid(); 19135493Sminshall #endif /* (!defined(sun)) || defined(BSD) && (BSD >= 43) */ 19235423Sminshall 19335423Sminshall if ((pwent = getpwuid((int)geteuid())) == 0) { 19431798Sminshall return -1; 19531798Sminshall } 19631798Sminshall sprintf(promptbuf, "Enter password for user %s:", pwent->pw_name); 19731798Sminshall if (api_exch_outcommand(EXCH_CMD_SEND_AUTH) == -1) { 19831798Sminshall return -1; 19931798Sminshall } 20031798Sminshall sd.length = strlen(promptbuf); 20131798Sminshall if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) 20231798Sminshall == -1) { 20331798Sminshall return -1; 20431798Sminshall } 20531798Sminshall if (api_exch_outtype(EXCH_TYPE_BYTES, strlen(promptbuf), promptbuf) 20631798Sminshall == -1) { 20731798Sminshall return -1; 20831798Sminshall } 20931798Sminshall sd.length = strlen(pwent->pw_name); 21031798Sminshall if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) 21131798Sminshall == -1) { 21231798Sminshall return -1; 21331798Sminshall } 21431798Sminshall if (api_exch_outtype(EXCH_TYPE_BYTES, 21531798Sminshall strlen(pwent->pw_name), pwent->pw_name) == -1) { 21631798Sminshall return -1; 21731798Sminshall } 21831798Sminshall if (api_exch_incommand(EXCH_CMD_AUTH) == -1) { 21931798Sminshall return -1; 22031798Sminshall } 22131798Sminshall if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) 22231798Sminshall == -1) { 22331798Sminshall return -1; 22431798Sminshall } 22531798Sminshall sd.length = sd.length; 22631798Sminshall if (sd.length > sizeof buffer) { 22731798Sminshall doreject("Password entered was too long"); 22831798Sminshall return -1; 22931798Sminshall } 23031798Sminshall if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) { 23131798Sminshall return -1; 23231798Sminshall } 23331798Sminshall buffer[sd.length] = 0; 23431465Sminshall 23531798Sminshall /* Is this the correct password? */ 23631798Sminshall if (strlen(pwent->pw_name)) { 23731798Sminshall char *ptr; 23831798Sminshall int i; 23931798Sminshall 24031798Sminshall ptr = pwent->pw_name; 24131798Sminshall i = 0; 24231798Sminshall while (i < sd.length) { 24331798Sminshall buffer[i++] ^= *ptr++; 24431798Sminshall if (*ptr == 0) { 24531798Sminshall ptr = pwent->pw_name; 24631798Sminshall } 24731465Sminshall } 24831465Sminshall } 24931798Sminshall if (strcmp(crypt(buffer, pwent->pw_passwd), pwent->pw_passwd) != 0) { 25031798Sminshall doreject("Invalid password"); 25131798Sminshall sleep(10); /* Don't let us do too many of these */ 25231798Sminshall return 0; 25331798Sminshall } 25431465Sminshall } 25531798Sminshall if (api_exch_outcommand(EXCH_CMD_ASSOCIATED) == -1) { 25631798Sminshall return -1; 25731457Sminshall } else { 25831798Sminshall return 1; 25931457Sminshall } 26031457Sminshall } 26131457Sminshall 26231457Sminshall 26331457Sminshall void 26431457Sminshall freestorage() 26531457Sminshall { 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) 29835423Sminshall long 29935423Sminshall address; 30031508Sminshall int 30131508Sminshall length, 30231508Sminshall copyin; 30331457Sminshall { 30431463Sminshall struct storage_descriptor sd; 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) { 32235423Sminshall sd.location = (long)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 34235423Sminshall /*ARGSUSED*/ 34331457Sminshall void 34431457Sminshall movetous(local, es, di, length) 34531457Sminshall char 34631457Sminshall *local; 34735423Sminshall unsigned int 34831457Sminshall es, 34931457Sminshall di; 35031457Sminshall int 35131457Sminshall length; 35231457Sminshall { 35335423Sminshall long where = SEG_OFF_BACK(es, di); 35435423Sminshall 35531457Sminshall if (length > sizeof storage) { 35631457Sminshall fprintf(stderr, "Internal API error - movetous() length too long.\n"); 35731457Sminshall fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__); 35831457Sminshall quit(); 35931457Sminshall } else if (length == 0) { 36031457Sminshall return; 36131457Sminshall } 36235423Sminshall getstorage(where, length, 1); 36335423Sminshall memcpy(local, (char *)(storage+((where-storage_location))), length); 36431457Sminshall } 36531457Sminshall 36635423Sminshall /*ARGSUSED*/ 36731457Sminshall void 36831457Sminshall movetothem(es, di, local, length) 36935423Sminshall unsigned int 37031457Sminshall es, 37131457Sminshall di; 37231457Sminshall char 37331457Sminshall *local; 37431457Sminshall int 37531457Sminshall length; 37631457Sminshall { 37735423Sminshall long where = SEG_OFF_BACK(es, di); 37835423Sminshall 37931457Sminshall if (length > sizeof storage) { 38031457Sminshall fprintf(stderr, "Internal API error - movetothem() length too long.\n"); 38131457Sminshall fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__); 38231457Sminshall quit(); 38331457Sminshall } else if (length == 0) { 38431457Sminshall return; 38531457Sminshall } 38631457Sminshall freestorage(); 38731457Sminshall memcpy((char *)storage, local, length); 38831457Sminshall storage_length = length; 38935423Sminshall storage_location = where; 39031457Sminshall storage_must_send = 1; 39131457Sminshall } 39231457Sminshall 39331457Sminshall 39431457Sminshall char * 39531508Sminshall access_api(location, length, copyin) 39635423Sminshall char * 39735423Sminshall location; 39831457Sminshall int 39931508Sminshall length, 40031508Sminshall copyin; /* Do we need to copy in initially? */ 40131457Sminshall { 40231457Sminshall if (storage_accessed) { 40331457Sminshall fprintf(stderr, "Internal error - storage accessed twice\n"); 40431503Sminshall fprintf(stderr, "(Encountered in file %s, line %d.)\n", 40531457Sminshall __FILE__, __LINE__); 40631457Sminshall quit(); 40731457Sminshall } else if (length != 0) { 40831457Sminshall freestorage(); 40935423Sminshall getstorage((long)location, length, copyin); 41031503Sminshall storage_accessed = 1; 41131457Sminshall } 41231457Sminshall return (char *) storage; 41331457Sminshall } 41431457Sminshall 41535423Sminshall /*ARGSUSED*/ 41635423Sminshall void 41731508Sminshall unaccess_api(location, local, length, copyout) 41835423Sminshall char *location; 41931457Sminshall char *local; 42031457Sminshall int length; 42135423Sminshall int copyout; 42231457Sminshall { 42331457Sminshall if (storage_accessed == 0) { 42431457Sminshall fprintf(stderr, "Internal error - unnecessary unaccess_api call.\n"); 42531503Sminshall fprintf(stderr, "(Encountered in file %s, line %d.)\n", 42631457Sminshall __FILE__, __LINE__); 42731457Sminshall quit(); 42831457Sminshall } 42931457Sminshall storage_accessed = 0; 43031508Sminshall storage_must_send = copyout; /* if needs to go back */ 43131457Sminshall } 43231457Sminshall 43331465Sminshall /* 43431465Sminshall * Accept a connection from an API client, aborting if the child dies. 43531465Sminshall */ 43631457Sminshall 43731465Sminshall static int 43831465Sminshall doconnect() 43931465Sminshall { 44031465Sminshall fd_set fdset; 44131465Sminshall int i; 44231465Sminshall 44331465Sminshall sock = -1; 44431465Sminshall FD_ZERO(&fdset); 44531465Sminshall while (shell_active && (sock == -1)) { 44631465Sminshall FD_SET(serversock, &fdset); 44735423Sminshall if ((i = select(serversock+1, &fdset, 44835423Sminshall (fd_set *)0, (fd_set *)0, (struct timeval *)0)) < 0) { 44931465Sminshall if (errno = EINTR) { 45031465Sminshall continue; 45131465Sminshall } else { 45231465Sminshall perror("in select waiting for API connection"); 45331465Sminshall return -1; 45431465Sminshall } 45531465Sminshall } else { 45635423Sminshall i = accept(serversock, (struct sockaddr *)0, (int *)0); 45731465Sminshall if (i == -1) { 45831465Sminshall perror("accepting API connection"); 45931465Sminshall return -1; 46031465Sminshall } 46131465Sminshall sock = i; 46231465Sminshall } 46331465Sminshall } 46431465Sminshall /* If the process has already exited, we may need to close */ 46531465Sminshall if ((shell_active == 0) && (sock != -1)) { 46635423Sminshall extern void setcommandmode(); 46735423Sminshall 46831465Sminshall (void) close(sock); 46931465Sminshall sock = -1; 47031465Sminshall setcommandmode(); /* In case child_died sneaked in */ 47131465Sminshall } 47235423Sminshall return 0; 47331465Sminshall } 47431465Sminshall 47531457Sminshall /* 47631455Sminshall * shell_continue() actually runs the command, and looks for API 47731455Sminshall * requests coming back in. 47831455Sminshall * 47931455Sminshall * We are called from the main loop in telnet.c. 48031455Sminshall */ 48131455Sminshall 48231455Sminshall int 48331455Sminshall shell_continue() 48431455Sminshall { 48531492Sminshall int i; 48631492Sminshall 48731457Sminshall switch (state) { 48831457Sminshall case DEAD: 48931457Sminshall pause(); /* Nothing to do */ 49031457Sminshall break; 49131457Sminshall case UNCONNECTED: 49231465Sminshall if (doconnect() == -1) { 49331457Sminshall kill_connection(); 49431465Sminshall return -1; 49531465Sminshall } 496*38211Sminshall /* At this point, it is possible that we've gone away */ 497*38211Sminshall if (shell_active == 0) { 498*38211Sminshall kill_connection(); 499*38211Sminshall return -1; 500*38211Sminshall } 50131492Sminshall if (api_exch_init(sock, "server") == -1) { 50231465Sminshall return -1; 50331465Sminshall } 50431465Sminshall while (state == UNCONNECTED) { 50531492Sminshall if (api_exch_incommand(EXCH_CMD_ASSOCIATE) == -1) { 50631457Sminshall kill_connection(); 50731465Sminshall return -1; 50831465Sminshall } else { 50931465Sminshall switch (doassociate()) { 51031465Sminshall case -1: 51131465Sminshall kill_connection(); 51231465Sminshall return -1; 51331465Sminshall case 0: 51431465Sminshall break; 51531465Sminshall case 1: 51631465Sminshall state = CONNECTED; 51731465Sminshall } 51831457Sminshall } 51931457Sminshall } 52031457Sminshall break; 52131457Sminshall case CONNECTED: 52231492Sminshall switch (i = api_exch_nextcommand()) { 52331492Sminshall case EXCH_CMD_REQUEST: 52431492Sminshall if (api_exch_intype(EXCH_TYPE_REGS, sizeof inputRegs, 52531492Sminshall (char *)&inputRegs) == -1) { 52631463Sminshall kill_connection(); 52731492Sminshall } else if (api_exch_intype(EXCH_TYPE_SREGS, sizeof inputSregs, 52831492Sminshall (char *)&inputSregs) == -1) { 52931463Sminshall kill_connection(); 53031492Sminshall } else if (nextstore() == -1) { 53131463Sminshall kill_connection(); 53231492Sminshall } else { 53331492Sminshall handle_api(&inputRegs, &inputSregs); 53431492Sminshall freestorage(); /* Send any storage back */ 53531492Sminshall if (api_exch_outcommand(EXCH_CMD_REPLY) == -1) { 53631492Sminshall kill_connection(); 53731492Sminshall } else if (api_exch_outtype(EXCH_TYPE_REGS, sizeof inputRegs, 53831492Sminshall (char *)&inputRegs) == -1) { 53931492Sminshall kill_connection(); 54031492Sminshall } else if (api_exch_outtype(EXCH_TYPE_SREGS, sizeof inputSregs, 54131492Sminshall (char *)&inputSregs) == -1) { 54231492Sminshall kill_connection(); 54331492Sminshall } 54431492Sminshall /* Done, and it all worked! */ 54531463Sminshall } 54631492Sminshall break; 54731492Sminshall case EXCH_CMD_DISASSOCIATE: 54831492Sminshall kill_connection(); 54931492Sminshall break; 55031492Sminshall default: 55131503Sminshall if (i != -1) { 55231503Sminshall fprintf(stderr, 55331503Sminshall "Looking for a REQUEST or DISASSOCIATE command\n"); 55431503Sminshall fprintf(stderr, "\treceived 0x%02x.\n", i); 55531503Sminshall } 55631492Sminshall kill_connection(); 55731503Sminshall break; 55831457Sminshall } 55931457Sminshall } 56031455Sminshall return shell_active; 56131455Sminshall } 56231455Sminshall 56331455Sminshall 56431463Sminshall static int 56531463Sminshall child_died() 56631463Sminshall { 56735423Sminshall union wait status; 56831463Sminshall register int pid; 56931463Sminshall 57035423Sminshall while ((pid = wait3(&status, WNOHANG, (struct rusage *)0)) > 0) { 57131463Sminshall if (pid == shell_pid) { 57231463Sminshall char inputbuffer[100]; 57335423Sminshall extern void setconnmode(); 57435423Sminshall extern void ConnectScreen(); 57531463Sminshall 57631463Sminshall shell_active = 0; 57731463Sminshall if (sock != -1) { 57831463Sminshall (void) close(sock); 57931463Sminshall sock = -1; 58031463Sminshall } 58131471Sminshall printf("[Hit return to continue]"); 58231471Sminshall fflush(stdout); 58331471Sminshall (void) gets(inputbuffer); 58431465Sminshall setconnmode(); 58531465Sminshall ConnectScreen(); /* Turn screen on (if need be) */ 58631465Sminshall (void) close(serversock); 58731798Sminshall (void) unlink(keyname); 58831463Sminshall } 58931463Sminshall } 59031463Sminshall signal(SIGCHLD, child_died); 59131463Sminshall } 59231463Sminshall 59331463Sminshall 59431455Sminshall /* 59531455Sminshall * Called from telnet.c to fork a lower command.com. We 59631455Sminshall * use the spint... routines so that we can pick up 59731455Sminshall * interrupts generated by application programs. 59831455Sminshall */ 59931455Sminshall 60031455Sminshall 60131455Sminshall int 60231455Sminshall shell(argc,argv) 60331455Sminshall int argc; 60431455Sminshall char *argv[]; 60531455Sminshall { 60631465Sminshall int length; 60731457Sminshall struct sockaddr_in server; 60831457Sminshall char sockNAME[100]; 60931457Sminshall static char **whereAPI = 0; 61031798Sminshall int fd; 61131798Sminshall struct timeval tv; 61231798Sminshall long ikey; 61331798Sminshall extern long random(); 61431798Sminshall extern char *mktemp(); 61535423Sminshall extern char *strcpy(); 61631457Sminshall 61731798Sminshall /* First, create verification file. */ 61831798Sminshall do { 61931798Sminshall keyname = mktemp("/tmp/apiXXXXXX"); 62031798Sminshall fd = open(keyname, O_RDWR|O_CREAT|O_EXCL, IREAD|IWRITE); 62131798Sminshall } while ((fd == -1) && (errno == EEXIST)); 62231798Sminshall 62331798Sminshall if (fd == -1) { 62431798Sminshall perror("open"); 62531798Sminshall return 0; 62631798Sminshall } 62731798Sminshall 62831798Sminshall /* Now, get seed for random */ 62931798Sminshall 63035423Sminshall if (gettimeofday(&tv, (struct timezone *)0) == -1) { 63131798Sminshall perror("gettimeofday"); 63231798Sminshall return 0; 63331798Sminshall } 63431798Sminshall srandom(tv.tv_usec); /* seed random number generator */ 63531798Sminshall do { 63631798Sminshall ikey = random(); 63731798Sminshall } while (ikey == 0); 63835423Sminshall sprintf(key, "%lu\n", (unsigned long) ikey); 63931798Sminshall if (write(fd, key, strlen(key)) != strlen(key)) { 64031798Sminshall perror("write"); 64131798Sminshall return 0; 64231798Sminshall } 64331798Sminshall key[strlen(key)-1] = 0; /* Get rid of newline */ 64431798Sminshall 64531798Sminshall if (close(fd) == -1) { 64631798Sminshall perror("close"); 64731798Sminshall return 0; 64831798Sminshall } 64931798Sminshall 65031798Sminshall /* Next, create the socket which will be connected to */ 65131457Sminshall serversock = socket(AF_INET, SOCK_STREAM, 0); 65231457Sminshall if (serversock < 0) { 65331457Sminshall perror("opening API socket"); 65431457Sminshall return 0; 65531457Sminshall } 65631457Sminshall server.sin_family = AF_INET; 65731457Sminshall server.sin_addr.s_addr = INADDR_ANY; 65831457Sminshall server.sin_port = 0; 65935423Sminshall if (bind(serversock, (struct sockaddr *)&server, sizeof server) < 0) { 66031457Sminshall perror("binding API socket"); 66131457Sminshall return 0; 66231457Sminshall } 66331457Sminshall length = sizeof server; 66435423Sminshall if (getsockname(serversock, (struct sockaddr *)&server, &length) < 0) { 66531457Sminshall perror("getting API socket name"); 66631457Sminshall (void) close(serversock); 66731457Sminshall } 66831457Sminshall listen(serversock, 1); 66931457Sminshall /* Get name to advertise in address list */ 67031457Sminshall strcpy(sockNAME, "API3270="); 67131457Sminshall gethostname(sockNAME+strlen(sockNAME), sizeof sockNAME-strlen(sockNAME)); 67231798Sminshall if (strlen(sockNAME) > (sizeof sockNAME-(10+strlen(keyname)))) { 67331457Sminshall fprintf(stderr, "Local hostname too large; using 'localhost'.\n"); 67431457Sminshall strcpy(sockNAME, "localhost"); 67531457Sminshall } 67635423Sminshall sprintf(sockNAME+strlen(sockNAME), ":%u", ntohs(server.sin_port)); 67731798Sminshall sprintf(sockNAME+strlen(sockNAME), ":%s", keyname); 67831457Sminshall 67931457Sminshall if (whereAPI == 0) { 68031457Sminshall char **ptr, **nextenv; 68131457Sminshall extern char **environ; 68231457Sminshall 68331457Sminshall ptr = environ; 68431457Sminshall nextenv = ourENVlist; 68531457Sminshall while (*ptr) { 68631457Sminshall if (nextenv >= &ourENVlist[highestof(ourENVlist)-1]) { 68731457Sminshall fprintf(stderr, "Too many environmental variables\n"); 68831457Sminshall break; 68931457Sminshall } 69031457Sminshall *nextenv++ = *ptr++; 69131457Sminshall } 69231457Sminshall whereAPI = nextenv++; 69331457Sminshall *nextenv++ = 0; 69431457Sminshall environ = ourENVlist; /* New environment */ 69531457Sminshall } 69631457Sminshall *whereAPI = sockNAME; 69731457Sminshall 69831457Sminshall child_died(); /* Start up signal handler */ 69931457Sminshall shell_active = 1; /* We are running down below */ 70031457Sminshall if (shell_pid = vfork()) { 70131457Sminshall if (shell_pid == -1) { 70231457Sminshall perror("vfork"); 70331457Sminshall (void) close(serversock); 70431457Sminshall } else { 70531465Sminshall state = UNCONNECTED; 70631457Sminshall } 70731455Sminshall } else { /* New process */ 70831455Sminshall register int i; 70931455Sminshall 71031455Sminshall for (i = 3; i < 30; i++) { 71131455Sminshall (void) close(i); 71231455Sminshall } 71331455Sminshall if (argc == 1) { /* Just get a shell */ 71431455Sminshall char *cmdname; 71531457Sminshall extern char *getenv(); 71631455Sminshall 71731455Sminshall cmdname = getenv("SHELL"); 71831455Sminshall execlp(cmdname, cmdname, 0); 71931455Sminshall perror("Exec'ing new shell...\n"); 72031455Sminshall exit(1); 72131455Sminshall } else { 72231455Sminshall execvp(argv[1], &argv[1]); 72331455Sminshall perror("Exec'ing command.\n"); 72431455Sminshall exit(1); 72531455Sminshall } 72631455Sminshall /*NOTREACHED*/ 72731455Sminshall } 72831457Sminshall return shell_active; /* Go back to main loop */ 72931455Sminshall } 730