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 6*35423Sminshall * provided that the above copyright notice and this paragraph are 7*35423Sminshall * duplicated in all such forms and that any documentation, 8*35423Sminshall * advertising materials, and other materials related to such 9*35423Sminshall * distribution and use acknowledge that the software was developed 10*35423Sminshall * by the University of California, Berkeley. The name of the 11*35423Sminshall * University may not be used to endorse or promote products derived 12*35423Sminshall * from this software without specific prior written permission. 13*35423Sminshall * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*35423Sminshall * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*35423Sminshall * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1631894Sminshall */ 1731894Sminshall 1831894Sminshall #ifndef lint 19*35423Sminshall static char sccsid[] = "@(#)system.c 3.4 (Berkeley) 08/28/88"; 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 2833269Sminshall #if !defined(sun) && !defined(pyr) 2931798Sminshall #include <sys/inode.h> 3031863Sminshall #else /* !defined(sun) */ 3131863Sminshall #define IREAD 00400 3231863Sminshall #define IWRITE 00200 3331863Sminshall #endif /* !defined(sun) */ 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 81*35423Sminshall static long 82*35423Sminshall storage_location; /* Address we have */ 83*35423Sminshall static short 84*35423Sminshall 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; 173*35423Sminshall 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) { 189*35423Sminshall extern uid_t geteuid(); 190*35423Sminshall 191*35423Sminshall if ((pwent = getpwuid((int)geteuid())) == 0) { 19231798Sminshall return -1; 19331798Sminshall } 19431798Sminshall sprintf(promptbuf, "Enter password for user %s:", pwent->pw_name); 19531798Sminshall if (api_exch_outcommand(EXCH_CMD_SEND_AUTH) == -1) { 19631798Sminshall return -1; 19731798Sminshall } 19831798Sminshall sd.length = strlen(promptbuf); 19931798Sminshall if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) 20031798Sminshall == -1) { 20131798Sminshall return -1; 20231798Sminshall } 20331798Sminshall if (api_exch_outtype(EXCH_TYPE_BYTES, strlen(promptbuf), promptbuf) 20431798Sminshall == -1) { 20531798Sminshall return -1; 20631798Sminshall } 20731798Sminshall sd.length = strlen(pwent->pw_name); 20831798Sminshall if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) 20931798Sminshall == -1) { 21031798Sminshall return -1; 21131798Sminshall } 21231798Sminshall if (api_exch_outtype(EXCH_TYPE_BYTES, 21331798Sminshall strlen(pwent->pw_name), pwent->pw_name) == -1) { 21431798Sminshall return -1; 21531798Sminshall } 21631798Sminshall if (api_exch_incommand(EXCH_CMD_AUTH) == -1) { 21731798Sminshall return -1; 21831798Sminshall } 21931798Sminshall if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) 22031798Sminshall == -1) { 22131798Sminshall return -1; 22231798Sminshall } 22331798Sminshall sd.length = sd.length; 22431798Sminshall if (sd.length > sizeof buffer) { 22531798Sminshall doreject("Password entered was too long"); 22631798Sminshall return -1; 22731798Sminshall } 22831798Sminshall if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) { 22931798Sminshall return -1; 23031798Sminshall } 23131798Sminshall buffer[sd.length] = 0; 23231465Sminshall 23331798Sminshall /* Is this the correct password? */ 23431798Sminshall if (strlen(pwent->pw_name)) { 23531798Sminshall char *ptr; 23631798Sminshall int i; 23731798Sminshall 23831798Sminshall ptr = pwent->pw_name; 23931798Sminshall i = 0; 24031798Sminshall while (i < sd.length) { 24131798Sminshall buffer[i++] ^= *ptr++; 24231798Sminshall if (*ptr == 0) { 24331798Sminshall ptr = pwent->pw_name; 24431798Sminshall } 24531465Sminshall } 24631465Sminshall } 24731798Sminshall if (strcmp(crypt(buffer, pwent->pw_passwd), pwent->pw_passwd) != 0) { 24831798Sminshall doreject("Invalid password"); 24931798Sminshall sleep(10); /* Don't let us do too many of these */ 25031798Sminshall return 0; 25131798Sminshall } 25231465Sminshall } 25331798Sminshall if (api_exch_outcommand(EXCH_CMD_ASSOCIATED) == -1) { 25431798Sminshall return -1; 25531457Sminshall } else { 25631798Sminshall return 1; 25731457Sminshall } 25831457Sminshall } 25931457Sminshall 26031457Sminshall 26131457Sminshall void 26231457Sminshall freestorage() 26331457Sminshall { 26431463Sminshall struct storage_descriptor sd; 26531457Sminshall 26631457Sminshall if (storage_accessed) { 26731457Sminshall fprintf(stderr, "Internal error - attempt to free accessed storage.\n"); 26831503Sminshall fprintf(stderr, "(Encountered in file %s at line %d.)\n", 26931457Sminshall __FILE__, __LINE__); 27031457Sminshall quit(); 27131457Sminshall } 27231457Sminshall if (storage_must_send == 0) { 27331457Sminshall return; 27431457Sminshall } 27531457Sminshall storage_must_send = 0; 27631492Sminshall if (api_exch_outcommand(EXCH_CMD_HEREIS) == -1) { 27731457Sminshall kill_connection(); 27831457Sminshall return; 27931457Sminshall } 28031798Sminshall sd.length = storage_length; 28131798Sminshall sd.location = storage_location; 28231463Sminshall if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 28331457Sminshall kill_connection(); 28431457Sminshall return; 28531457Sminshall } 28631511Sminshall if (api_exch_outtype(EXCH_TYPE_BYTES, storage_length, (char *)storage) 28731511Sminshall == -1) { 28831511Sminshall kill_connection(); 28931511Sminshall return; 29031463Sminshall } 29131457Sminshall } 29231457Sminshall 29331457Sminshall 29431463Sminshall static int 29531508Sminshall getstorage(address, length, copyin) 296*35423Sminshall long 297*35423Sminshall address; 29831508Sminshall int 29931508Sminshall length, 30031508Sminshall copyin; 30131457Sminshall { 30231463Sminshall struct storage_descriptor sd; 30331457Sminshall 30431457Sminshall freestorage(); 30531457Sminshall if (storage_accessed) { 30631457Sminshall fprintf(stderr, 30731457Sminshall "Internal error - attempt to get while storage accessed.\n"); 30831503Sminshall fprintf(stderr, "(Encountered in file %s at line %d.)\n", 30931457Sminshall __FILE__, __LINE__); 31031457Sminshall quit(); 31131457Sminshall } 31231457Sminshall storage_must_send = 0; 31331492Sminshall if (api_exch_outcommand(EXCH_CMD_GIMME) == -1) { 31431457Sminshall kill_connection(); 31531463Sminshall return -1; 31631457Sminshall } 31731471Sminshall storage_location = address; 31831471Sminshall storage_length = length; 31931508Sminshall if (copyin) { 320*35423Sminshall sd.location = (long)storage_location; 32131798Sminshall sd.length = storage_length; 32231508Sminshall if (api_exch_outtype(EXCH_TYPE_STORE_DESC, 32331508Sminshall sizeof sd, (char *)&sd) == -1) { 32431508Sminshall kill_connection(); 32531508Sminshall return -1; 32631508Sminshall } 32731508Sminshall if (api_exch_incommand(EXCH_CMD_HEREIS) == -1) { 32831508Sminshall fprintf(stderr, "Bad data from other side.\n"); 32931508Sminshall fprintf(stderr, "(Encountered at %s, %d.)\n", __FILE__, __LINE__); 33031508Sminshall return -1; 33131508Sminshall } 33231508Sminshall if (nextstore() == -1) { 33331508Sminshall kill_connection(); 33431508Sminshall return -1; 33531508Sminshall } 33631463Sminshall } 33731463Sminshall return 0; 33831457Sminshall } 33931457Sminshall 340*35423Sminshall /*ARGSUSED*/ 34131457Sminshall void 34231457Sminshall movetous(local, es, di, length) 34331457Sminshall char 34431457Sminshall *local; 345*35423Sminshall unsigned int 34631457Sminshall es, 34731457Sminshall di; 34831457Sminshall int 34931457Sminshall length; 35031457Sminshall { 351*35423Sminshall long where = SEG_OFF_BACK(es, di); 352*35423Sminshall 35331457Sminshall if (length > sizeof storage) { 35431457Sminshall fprintf(stderr, "Internal API error - movetous() length too long.\n"); 35531457Sminshall fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__); 35631457Sminshall quit(); 35731457Sminshall } else if (length == 0) { 35831457Sminshall return; 35931457Sminshall } 360*35423Sminshall getstorage(where, length, 1); 361*35423Sminshall memcpy(local, (char *)(storage+((where-storage_location))), length); 36231457Sminshall } 36331457Sminshall 364*35423Sminshall /*ARGSUSED*/ 36531457Sminshall void 36631457Sminshall movetothem(es, di, local, length) 367*35423Sminshall unsigned int 36831457Sminshall es, 36931457Sminshall di; 37031457Sminshall char 37131457Sminshall *local; 37231457Sminshall int 37331457Sminshall length; 37431457Sminshall { 375*35423Sminshall long where = SEG_OFF_BACK(es, di); 376*35423Sminshall 37731457Sminshall if (length > sizeof storage) { 37831457Sminshall fprintf(stderr, "Internal API error - movetothem() length too long.\n"); 37931457Sminshall fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__); 38031457Sminshall quit(); 38131457Sminshall } else if (length == 0) { 38231457Sminshall return; 38331457Sminshall } 38431457Sminshall freestorage(); 38531457Sminshall memcpy((char *)storage, local, length); 38631457Sminshall storage_length = length; 387*35423Sminshall storage_location = where; 38831457Sminshall storage_must_send = 1; 38931457Sminshall } 39031457Sminshall 39131457Sminshall 39231457Sminshall char * 39331508Sminshall access_api(location, length, copyin) 394*35423Sminshall char * 395*35423Sminshall location; 39631457Sminshall int 39731508Sminshall length, 39831508Sminshall copyin; /* Do we need to copy in initially? */ 39931457Sminshall { 40031457Sminshall if (storage_accessed) { 40131457Sminshall fprintf(stderr, "Internal error - storage accessed twice\n"); 40231503Sminshall fprintf(stderr, "(Encountered in file %s, line %d.)\n", 40331457Sminshall __FILE__, __LINE__); 40431457Sminshall quit(); 40531457Sminshall } else if (length != 0) { 40631457Sminshall freestorage(); 407*35423Sminshall getstorage((long)location, length, copyin); 40831503Sminshall storage_accessed = 1; 40931457Sminshall } 41031457Sminshall return (char *) storage; 41131457Sminshall } 41231457Sminshall 413*35423Sminshall /*ARGSUSED*/ 414*35423Sminshall void 41531508Sminshall unaccess_api(location, local, length, copyout) 416*35423Sminshall char *location; 41731457Sminshall char *local; 41831457Sminshall int length; 419*35423Sminshall int copyout; 42031457Sminshall { 42131457Sminshall if (storage_accessed == 0) { 42231457Sminshall fprintf(stderr, "Internal error - unnecessary unaccess_api call.\n"); 42331503Sminshall fprintf(stderr, "(Encountered in file %s, line %d.)\n", 42431457Sminshall __FILE__, __LINE__); 42531457Sminshall quit(); 42631457Sminshall } 42731457Sminshall storage_accessed = 0; 42831508Sminshall storage_must_send = copyout; /* if needs to go back */ 42931457Sminshall } 43031457Sminshall 43131465Sminshall /* 43231465Sminshall * Accept a connection from an API client, aborting if the child dies. 43331465Sminshall */ 43431457Sminshall 43531465Sminshall static int 43631465Sminshall doconnect() 43731465Sminshall { 43831465Sminshall fd_set fdset; 43931465Sminshall int i; 44031465Sminshall 44131465Sminshall sock = -1; 44231465Sminshall FD_ZERO(&fdset); 44331465Sminshall while (shell_active && (sock == -1)) { 44431465Sminshall FD_SET(serversock, &fdset); 445*35423Sminshall if ((i = select(serversock+1, &fdset, 446*35423Sminshall (fd_set *)0, (fd_set *)0, (struct timeval *)0)) < 0) { 44731465Sminshall if (errno = EINTR) { 44831465Sminshall continue; 44931465Sminshall } else { 45031465Sminshall perror("in select waiting for API connection"); 45131465Sminshall return -1; 45231465Sminshall } 45331465Sminshall } else { 454*35423Sminshall i = accept(serversock, (struct sockaddr *)0, (int *)0); 45531465Sminshall if (i == -1) { 45631465Sminshall perror("accepting API connection"); 45731465Sminshall return -1; 45831465Sminshall } 45931465Sminshall sock = i; 46031465Sminshall } 46131465Sminshall } 46231465Sminshall /* If the process has already exited, we may need to close */ 46331465Sminshall if ((shell_active == 0) && (sock != -1)) { 464*35423Sminshall extern void setcommandmode(); 465*35423Sminshall 46631465Sminshall (void) close(sock); 46731465Sminshall sock = -1; 46831465Sminshall setcommandmode(); /* In case child_died sneaked in */ 46931465Sminshall } 470*35423Sminshall return 0; 47131465Sminshall } 47231465Sminshall 47331457Sminshall /* 47431455Sminshall * shell_continue() actually runs the command, and looks for API 47531455Sminshall * requests coming back in. 47631455Sminshall * 47731455Sminshall * We are called from the main loop in telnet.c. 47831455Sminshall */ 47931455Sminshall 48031455Sminshall int 48131455Sminshall shell_continue() 48231455Sminshall { 48331492Sminshall int i; 48431492Sminshall 48531457Sminshall switch (state) { 48631457Sminshall case DEAD: 48731457Sminshall pause(); /* Nothing to do */ 48831457Sminshall break; 48931457Sminshall case UNCONNECTED: 49031465Sminshall if (doconnect() == -1) { 49131457Sminshall kill_connection(); 49231465Sminshall return -1; 49331465Sminshall } 49431492Sminshall if (api_exch_init(sock, "server") == -1) { 49531465Sminshall return -1; 49631465Sminshall } 49731465Sminshall while (state == UNCONNECTED) { 49831492Sminshall if (api_exch_incommand(EXCH_CMD_ASSOCIATE) == -1) { 49931457Sminshall kill_connection(); 50031465Sminshall return -1; 50131465Sminshall } else { 50231465Sminshall switch (doassociate()) { 50331465Sminshall case -1: 50431465Sminshall kill_connection(); 50531465Sminshall return -1; 50631465Sminshall case 0: 50731465Sminshall break; 50831465Sminshall case 1: 50931465Sminshall state = CONNECTED; 51031465Sminshall } 51131457Sminshall } 51231457Sminshall } 51331457Sminshall break; 51431457Sminshall case CONNECTED: 51531492Sminshall switch (i = api_exch_nextcommand()) { 51631492Sminshall case EXCH_CMD_REQUEST: 51731492Sminshall if (api_exch_intype(EXCH_TYPE_REGS, sizeof inputRegs, 51831492Sminshall (char *)&inputRegs) == -1) { 51931463Sminshall kill_connection(); 52031492Sminshall } else if (api_exch_intype(EXCH_TYPE_SREGS, sizeof inputSregs, 52131492Sminshall (char *)&inputSregs) == -1) { 52231463Sminshall kill_connection(); 52331492Sminshall } else if (nextstore() == -1) { 52431463Sminshall kill_connection(); 52531492Sminshall } else { 52631492Sminshall handle_api(&inputRegs, &inputSregs); 52731492Sminshall freestorage(); /* Send any storage back */ 52831492Sminshall if (api_exch_outcommand(EXCH_CMD_REPLY) == -1) { 52931492Sminshall kill_connection(); 53031492Sminshall } else if (api_exch_outtype(EXCH_TYPE_REGS, sizeof inputRegs, 53131492Sminshall (char *)&inputRegs) == -1) { 53231492Sminshall kill_connection(); 53331492Sminshall } else if (api_exch_outtype(EXCH_TYPE_SREGS, sizeof inputSregs, 53431492Sminshall (char *)&inputSregs) == -1) { 53531492Sminshall kill_connection(); 53631492Sminshall } 53731492Sminshall /* Done, and it all worked! */ 53831463Sminshall } 53931492Sminshall break; 54031492Sminshall case EXCH_CMD_DISASSOCIATE: 54131492Sminshall kill_connection(); 54231492Sminshall break; 54331492Sminshall default: 54431503Sminshall if (i != -1) { 54531503Sminshall fprintf(stderr, 54631503Sminshall "Looking for a REQUEST or DISASSOCIATE command\n"); 54731503Sminshall fprintf(stderr, "\treceived 0x%02x.\n", i); 54831503Sminshall } 54931492Sminshall kill_connection(); 55031503Sminshall break; 55131457Sminshall } 55231457Sminshall } 55331455Sminshall return shell_active; 55431455Sminshall } 55531455Sminshall 55631455Sminshall 55731463Sminshall static int 55831463Sminshall child_died() 55931463Sminshall { 560*35423Sminshall union wait status; 56131463Sminshall register int pid; 56231463Sminshall 563*35423Sminshall while ((pid = wait3(&status, WNOHANG, (struct rusage *)0)) > 0) { 56431463Sminshall if (pid == shell_pid) { 56531463Sminshall char inputbuffer[100]; 566*35423Sminshall extern void setconnmode(); 567*35423Sminshall extern void ConnectScreen(); 56831463Sminshall 56931463Sminshall shell_active = 0; 57031463Sminshall if (sock != -1) { 57131463Sminshall (void) close(sock); 57231463Sminshall sock = -1; 57331463Sminshall } 57431471Sminshall printf("[Hit return to continue]"); 57531471Sminshall fflush(stdout); 57631471Sminshall (void) gets(inputbuffer); 57731465Sminshall setconnmode(); 57831465Sminshall ConnectScreen(); /* Turn screen on (if need be) */ 57931465Sminshall (void) close(serversock); 58031798Sminshall (void) unlink(keyname); 58131463Sminshall } 58231463Sminshall } 58331463Sminshall signal(SIGCHLD, child_died); 58431463Sminshall } 58531463Sminshall 58631463Sminshall 58731455Sminshall /* 58831455Sminshall * Called from telnet.c to fork a lower command.com. We 58931455Sminshall * use the spint... routines so that we can pick up 59031455Sminshall * interrupts generated by application programs. 59131455Sminshall */ 59231455Sminshall 59331455Sminshall 59431455Sminshall int 59531455Sminshall shell(argc,argv) 59631455Sminshall int argc; 59731455Sminshall char *argv[]; 59831455Sminshall { 59931465Sminshall int length; 60031457Sminshall struct sockaddr_in server; 60131457Sminshall char sockNAME[100]; 60231457Sminshall static char **whereAPI = 0; 60331798Sminshall int fd; 60431798Sminshall struct timeval tv; 60531798Sminshall long ikey; 60631798Sminshall extern long random(); 60731798Sminshall extern char *mktemp(); 608*35423Sminshall extern char *strcpy(); 60931457Sminshall 61031798Sminshall /* First, create verification file. */ 61131798Sminshall do { 61231798Sminshall keyname = mktemp("/tmp/apiXXXXXX"); 61331798Sminshall fd = open(keyname, O_RDWR|O_CREAT|O_EXCL, IREAD|IWRITE); 61431798Sminshall } while ((fd == -1) && (errno == EEXIST)); 61531798Sminshall 61631798Sminshall if (fd == -1) { 61731798Sminshall perror("open"); 61831798Sminshall return 0; 61931798Sminshall } 62031798Sminshall 62131798Sminshall /* Now, get seed for random */ 62231798Sminshall 623*35423Sminshall if (gettimeofday(&tv, (struct timezone *)0) == -1) { 62431798Sminshall perror("gettimeofday"); 62531798Sminshall return 0; 62631798Sminshall } 62731798Sminshall srandom(tv.tv_usec); /* seed random number generator */ 62831798Sminshall do { 62931798Sminshall ikey = random(); 63031798Sminshall } while (ikey == 0); 631*35423Sminshall sprintf(key, "%lu\n", (unsigned long) ikey); 63231798Sminshall if (write(fd, key, strlen(key)) != strlen(key)) { 63331798Sminshall perror("write"); 63431798Sminshall return 0; 63531798Sminshall } 63631798Sminshall key[strlen(key)-1] = 0; /* Get rid of newline */ 63731798Sminshall 63831798Sminshall if (close(fd) == -1) { 63931798Sminshall perror("close"); 64031798Sminshall return 0; 64131798Sminshall } 64231798Sminshall 64331798Sminshall /* Next, create the socket which will be connected to */ 64431457Sminshall serversock = socket(AF_INET, SOCK_STREAM, 0); 64531457Sminshall if (serversock < 0) { 64631457Sminshall perror("opening API socket"); 64731457Sminshall return 0; 64831457Sminshall } 64931457Sminshall server.sin_family = AF_INET; 65031457Sminshall server.sin_addr.s_addr = INADDR_ANY; 65131457Sminshall server.sin_port = 0; 652*35423Sminshall if (bind(serversock, (struct sockaddr *)&server, sizeof server) < 0) { 65331457Sminshall perror("binding API socket"); 65431457Sminshall return 0; 65531457Sminshall } 65631457Sminshall length = sizeof server; 657*35423Sminshall if (getsockname(serversock, (struct sockaddr *)&server, &length) < 0) { 65831457Sminshall perror("getting API socket name"); 65931457Sminshall (void) close(serversock); 66031457Sminshall } 66131457Sminshall listen(serversock, 1); 66231457Sminshall /* Get name to advertise in address list */ 66331457Sminshall strcpy(sockNAME, "API3270="); 66431457Sminshall gethostname(sockNAME+strlen(sockNAME), sizeof sockNAME-strlen(sockNAME)); 66531798Sminshall if (strlen(sockNAME) > (sizeof sockNAME-(10+strlen(keyname)))) { 66631457Sminshall fprintf(stderr, "Local hostname too large; using 'localhost'.\n"); 66731457Sminshall strcpy(sockNAME, "localhost"); 66831457Sminshall } 669*35423Sminshall sprintf(sockNAME+strlen(sockNAME), ":%u", ntohs(server.sin_port)); 67031798Sminshall sprintf(sockNAME+strlen(sockNAME), ":%s", keyname); 67131457Sminshall 67231457Sminshall if (whereAPI == 0) { 67331457Sminshall char **ptr, **nextenv; 67431457Sminshall extern char **environ; 67531457Sminshall 67631457Sminshall ptr = environ; 67731457Sminshall nextenv = ourENVlist; 67831457Sminshall while (*ptr) { 67931457Sminshall if (nextenv >= &ourENVlist[highestof(ourENVlist)-1]) { 68031457Sminshall fprintf(stderr, "Too many environmental variables\n"); 68131457Sminshall break; 68231457Sminshall } 68331457Sminshall *nextenv++ = *ptr++; 68431457Sminshall } 68531457Sminshall whereAPI = nextenv++; 68631457Sminshall *nextenv++ = 0; 68731457Sminshall environ = ourENVlist; /* New environment */ 68831457Sminshall } 68931457Sminshall *whereAPI = sockNAME; 69031457Sminshall 69131457Sminshall child_died(); /* Start up signal handler */ 69231457Sminshall shell_active = 1; /* We are running down below */ 69331457Sminshall if (shell_pid = vfork()) { 69431457Sminshall if (shell_pid == -1) { 69531457Sminshall perror("vfork"); 69631457Sminshall (void) close(serversock); 69731457Sminshall } else { 69831465Sminshall state = UNCONNECTED; 69931457Sminshall } 70031455Sminshall } else { /* New process */ 70131455Sminshall register int i; 70231455Sminshall 70331455Sminshall for (i = 3; i < 30; i++) { 70431455Sminshall (void) close(i); 70531455Sminshall } 70631455Sminshall if (argc == 1) { /* Just get a shell */ 70731455Sminshall char *cmdname; 70831457Sminshall extern char *getenv(); 70931455Sminshall 71031455Sminshall cmdname = getenv("SHELL"); 71131455Sminshall execlp(cmdname, cmdname, 0); 71231455Sminshall perror("Exec'ing new shell...\n"); 71331455Sminshall exit(1); 71431455Sminshall } else { 71531455Sminshall execvp(argv[1], &argv[1]); 71631455Sminshall perror("Exec'ing command.\n"); 71731455Sminshall exit(1); 71831455Sminshall } 71931455Sminshall /*NOTREACHED*/ 72031455Sminshall } 72131457Sminshall return shell_active; /* Go back to main loop */ 72231455Sminshall } 723