131457Sminshall #include <sys/types.h> 231457Sminshall #include <sys/socket.h> 331457Sminshall #include <netinet/in.h> 431455Sminshall #include <sys/wait.h> 531455Sminshall 631457Sminshall #include <errno.h> 731457Sminshall extern int errno; 831457Sminshall 931457Sminshall #include <netdb.h> 1031457Sminshall #include <signal.h> 1131455Sminshall #include <stdio.h> 1231457Sminshall #include <pwd.h> 1331455Sminshall 1431455Sminshall #include "../general/general.h" 1531455Sminshall #include "../api/api.h" 1631463Sminshall #include "../apilib/api_exch.h" 1731455Sminshall 1831455Sminshall #include "../general/globals.h" 1931455Sminshall 2031455Sminshall 2131455Sminshall static int shell_pid = 0; 2231455Sminshall 2331457Sminshall static char *ourENVlist[200]; /* Lots of room */ 2431457Sminshall 2531465Sminshall static int 2631465Sminshall sock = -1, /* Connected socket */ 2731465Sminshall serversock; /* Server (listening) socket */ 2831457Sminshall 2931457Sminshall static enum { DEAD, UNCONNECTED, CONNECTED } state; 3031457Sminshall 3131455Sminshall static int 3231463Sminshall storage_location, /* Address we have */ 3331457Sminshall storage_length = 0, /* Length we have */ 3431457Sminshall storage_must_send = 0, /* Storage belongs on other side of wire */ 3531457Sminshall storage_accessed = 0; /* The storage is accessed (so leave alone)! */ 3631457Sminshall 3731457Sminshall static long storage[250]; 3831457Sminshall 3931463Sminshall static union REGS inputRegs; 4031463Sminshall static struct SREGS inputSregs; 4131457Sminshall 4231463Sminshall 4331463Sminshall static void 4431457Sminshall kill_connection() 4531457Sminshall { 4631465Sminshall state = UNCONNECTED; 4731465Sminshall if (sock != -1) { 4831465Sminshall (void) close(sock); 4931465Sminshall sock = -1; 5031465Sminshall } 5131457Sminshall } 5231457Sminshall 5331457Sminshall 5431457Sminshall static int 5531463Sminshall nextstore() 5631455Sminshall { 5731463Sminshall struct storage_descriptor sd; 5831455Sminshall 5931463Sminshall if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 6031457Sminshall storage_length = 0; 6131457Sminshall return -1; 6231457Sminshall } 6331463Sminshall storage_length = ntohs(sd.length); 6431463Sminshall storage_location = ntohl(sd.location); 6531463Sminshall if (storage_length > sizeof storage) { 6631457Sminshall fprintf(stderr, "API client tried to send too much storage (%d).\n", 6731457Sminshall storage_length); 6831463Sminshall storage_length = 0; 6931457Sminshall return -1; 7031457Sminshall } 71*31471Sminshall if (storage_length != 0) { 72*31471Sminshall if (api_exch_intype(EXCH_TYPE_BYTES, storage_length, (char *)storage) 73*31471Sminshall == -1) { 74*31471Sminshall storage_length = 0; 75*31471Sminshall return -1; 76*31471Sminshall } 7731463Sminshall } 78*31471Sminshall return 0; 7931457Sminshall } 8031457Sminshall 8131457Sminshall 8231457Sminshall static int 8331457Sminshall doreject(message) 8431457Sminshall char *message; 8531457Sminshall { 8631463Sminshall struct storage_descriptor sd; 8731457Sminshall int length = strlen(message); 8831457Sminshall 8931463Sminshall if (api_exch_outcommand(EXCH_REJECTED) == -1) { 9031457Sminshall return -1; 9131457Sminshall } 9231463Sminshall sd.length = htons(length); 9331465Sminshall if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 9431463Sminshall return -1; 9531463Sminshall } 9631463Sminshall if (api_exch_outtype(EXCH_TYPE_BYTES, length, message) == -1) { 9731463Sminshall return -1; 9831463Sminshall } 9931457Sminshall return 0; 10031457Sminshall } 10131457Sminshall 10231457Sminshall 10331455Sminshall /* 10431465Sminshall * doassociate() 10531457Sminshall * 10631457Sminshall * Negotiate with the other side and try to do something. 10731457Sminshall */ 10831457Sminshall 10931457Sminshall static int 11031465Sminshall doassociate() 11131457Sminshall { 11231457Sminshall struct passwd *pwent; 11331457Sminshall char 11431457Sminshall promptbuf[100], 11531457Sminshall buffer[200]; 11631457Sminshall int length; 11731457Sminshall int was; 11831463Sminshall struct storage_descriptor sd; 11931457Sminshall 12031457Sminshall if ((pwent = getpwuid(geteuid())) == 0) { 12131457Sminshall return -1; 12231457Sminshall } 12331457Sminshall sprintf(promptbuf, "Enter password for user %s:", pwent->pw_name); 12431465Sminshall if (api_exch_outcommand(EXCH_SEND_AUTH) == -1) { 12531465Sminshall return -1; 12631465Sminshall } 12731465Sminshall sd.length = htons(strlen(promptbuf)); 12831465Sminshall if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 12931465Sminshall return -1; 13031465Sminshall } 13131465Sminshall if (api_exch_outtype(EXCH_TYPE_BYTES, strlen(promptbuf), promptbuf) == -1) { 13231465Sminshall return -1; 13331465Sminshall } 13431465Sminshall sd.length = htons(strlen(pwent->pw_name)); 13531465Sminshall if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 13631465Sminshall return -1; 13731465Sminshall } 13831465Sminshall if (api_exch_outtype(EXCH_TYPE_BYTES, 13931465Sminshall strlen(pwent->pw_name), pwent->pw_name) == -1) { 14031465Sminshall return -1; 14131465Sminshall } 14231463Sminshall if (api_exch_incommand(EXCH_AUTH) == -1) { 14331457Sminshall return -1; 14431457Sminshall } 14531463Sminshall if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 14631463Sminshall return -1; 14731457Sminshall } 14831463Sminshall sd.length = ntohs(sd.length); 14931463Sminshall if (sd.length > sizeof buffer) { 15031457Sminshall doreject("Password entered was too long"); 15131465Sminshall return -1; 15231457Sminshall } 15331463Sminshall if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) { 15431457Sminshall return -1; 15531457Sminshall } 15631463Sminshall buffer[sd.length] = 0; 15731457Sminshall 15831457Sminshall /* Is this the correct password? */ 15931465Sminshall if (strlen(pwent->pw_name)) { 16031465Sminshall char *ptr; 16131465Sminshall int i; 16231465Sminshall 16331465Sminshall ptr = pwent->pw_name; 16431465Sminshall i = 0; 16531465Sminshall while (i < sd.length) { 16631465Sminshall buffer[i++] ^= *ptr++; 16731465Sminshall if (*ptr == 0) { 16831465Sminshall ptr = pwent->pw_name; 16931465Sminshall } 17031465Sminshall } 17131465Sminshall } 17231457Sminshall if (strcmp(crypt(buffer, pwent->pw_passwd), pwent->pw_passwd) == 0) { 17331465Sminshall if (api_exch_outcommand(EXCH_ASSOCIATED) == -1) { 17431465Sminshall return -1; 175*31471Sminshall } else { 176*31471Sminshall return 1; 17731465Sminshall } 17831457Sminshall } else { 17931457Sminshall doreject("Invalid password"); 18031457Sminshall sleep(10); /* Don't let us do too many of these */ 181*31471Sminshall return 0; 18231457Sminshall } 18331457Sminshall } 18431457Sminshall 18531457Sminshall 18631457Sminshall void 18731457Sminshall freestorage() 18831457Sminshall { 18931457Sminshall char buffer[40]; 19031463Sminshall struct storage_descriptor sd; 19131457Sminshall 19231457Sminshall if (storage_accessed) { 19331457Sminshall fprintf(stderr, "Internal error - attempt to free accessed storage.\n"); 19431457Sminshall fprintf(stderr, "(Enountered in file %s at line %s.)\n", 19531457Sminshall __FILE__, __LINE__); 19631457Sminshall quit(); 19731457Sminshall } 19831457Sminshall if (storage_must_send == 0) { 19931457Sminshall return; 20031457Sminshall } 20131457Sminshall storage_must_send = 0; 20231463Sminshall if (api_exch_outcommand(EXCH_HEREIS) == -1) { 20331457Sminshall kill_connection(); 20431457Sminshall return; 20531457Sminshall } 20631463Sminshall sd.length = htons(storage_length); 20731463Sminshall sd.location = htonl(storage_location); 20831463Sminshall if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 20931457Sminshall kill_connection(); 21031457Sminshall return; 21131457Sminshall } 212*31471Sminshall if (storage_length != 0) { 213*31471Sminshall if (api_exch_outtype(EXCH_TYPE_BYTES, storage_length, (char *)storage) 214*31471Sminshall == -1) { 215*31471Sminshall kill_connection(); 216*31471Sminshall return; 217*31471Sminshall } 21831463Sminshall } 21931457Sminshall } 22031457Sminshall 22131457Sminshall 22231463Sminshall static int 22331457Sminshall getstorage(address, length) 22431457Sminshall { 22531463Sminshall struct storage_descriptor sd; 22631457Sminshall char buffer[40]; 22731457Sminshall 22831457Sminshall freestorage(); 22931457Sminshall if (storage_accessed) { 23031457Sminshall fprintf(stderr, 23131457Sminshall "Internal error - attempt to get while storage accessed.\n"); 23231457Sminshall fprintf(stderr, "(Enountered in file %s at line %s.)\n", 23331457Sminshall __FILE__, __LINE__); 23431457Sminshall quit(); 23531457Sminshall } 23631457Sminshall storage_must_send = 0; 23731463Sminshall if (api_exch_outcommand(EXCH_GIMME) == -1) { 23831457Sminshall kill_connection(); 23931463Sminshall return -1; 24031457Sminshall } 241*31471Sminshall storage_location = address; 242*31471Sminshall storage_length = length; 24331463Sminshall sd.location = htonl(storage_location); 24431463Sminshall sd.length = htons(storage_length); 24531463Sminshall if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 24631463Sminshall kill_connection(); 24731463Sminshall return -1; 24831463Sminshall } 249*31471Sminshall if (api_exch_incommand(EXCH_HEREIS) == -1) { 250*31471Sminshall fprintf(stderr, "Bad data from other side.\n"); 251*31471Sminshall fprintf(stderr, "(Encountered at %s, %s.)\n", __FILE__, __LINE__); 252*31471Sminshall return -1; 253*31471Sminshall } 25431457Sminshall if (nextstore() == -1) { 25531457Sminshall kill_connection(); 25631463Sminshall return -1; 25731457Sminshall } 25831463Sminshall return 0; 25931457Sminshall } 26031457Sminshall 26131457Sminshall void 26231457Sminshall movetous(local, es, di, length) 26331457Sminshall char 26431457Sminshall *local; 26531457Sminshall int 26631457Sminshall es, 26731457Sminshall di; 26831457Sminshall int 26931457Sminshall length; 27031457Sminshall { 27131457Sminshall if (length > sizeof storage) { 27231457Sminshall fprintf(stderr, "Internal API error - movetous() length too long.\n"); 27331457Sminshall fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__); 27431457Sminshall quit(); 27531457Sminshall } else if (length == 0) { 27631457Sminshall return; 27731457Sminshall } 27831457Sminshall getstorage(di, length); 27931463Sminshall memcpy(local, storage+(di-storage_location), length); 28031457Sminshall } 28131457Sminshall 28231457Sminshall void 28331457Sminshall movetothem(es, di, local, length) 28431457Sminshall int 28531457Sminshall es, 28631457Sminshall di; 28731457Sminshall char 28831457Sminshall *local; 28931457Sminshall int 29031457Sminshall length; 29131457Sminshall { 29231457Sminshall if (length > sizeof storage) { 29331457Sminshall fprintf(stderr, "Internal API error - movetothem() length too long.\n"); 29431457Sminshall fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__); 29531457Sminshall quit(); 29631457Sminshall } else if (length == 0) { 29731457Sminshall return; 29831457Sminshall } 29931457Sminshall freestorage(); 30031457Sminshall memcpy((char *)storage, local, length); 30131457Sminshall storage_length = length; 30231463Sminshall storage_location = di; 30331457Sminshall storage_must_send = 1; 30431457Sminshall } 30531457Sminshall 30631457Sminshall 30731457Sminshall char * 30831457Sminshall access_api(location, length) 30931457Sminshall int 31031457Sminshall location, 31131457Sminshall length; 31231457Sminshall { 31331457Sminshall if (storage_accessed) { 31431457Sminshall fprintf(stderr, "Internal error - storage accessed twice\n"); 31531457Sminshall fprintf(stderr, "(Encountered in file %s, line %s.)\n", 31631457Sminshall __FILE__, __LINE__); 31731457Sminshall quit(); 31831457Sminshall } else if (length != 0) { 31931457Sminshall storage_accessed = 1; 32031457Sminshall freestorage(); 32131457Sminshall getstorage(location, length); 32231457Sminshall } 32331457Sminshall return (char *) storage; 32431457Sminshall } 32531457Sminshall 32631457Sminshall unaccess_api(location, local, length) 32731457Sminshall int location; 32831457Sminshall char *local; 32931457Sminshall int length; 33031457Sminshall { 33131457Sminshall if (storage_accessed == 0) { 33231457Sminshall fprintf(stderr, "Internal error - unnecessary unaccess_api call.\n"); 33331457Sminshall fprintf(stderr, "(Encountered in file %s, line %s.)\n", 33431457Sminshall __FILE__, __LINE__); 33531457Sminshall quit(); 33631457Sminshall } 33731457Sminshall storage_accessed = 0; 33831457Sminshall storage_must_send = 1; /* Needs to go back */ 33931457Sminshall } 34031457Sminshall 34131465Sminshall /* 34231465Sminshall * Accept a connection from an API client, aborting if the child dies. 34331465Sminshall */ 34431457Sminshall 34531465Sminshall static int 34631465Sminshall doconnect() 34731465Sminshall { 34831465Sminshall fd_set fdset; 34931465Sminshall int i; 35031465Sminshall 35131465Sminshall sock = -1; 35231465Sminshall FD_ZERO(&fdset); 35331465Sminshall while (shell_active && (sock == -1)) { 35431465Sminshall FD_SET(serversock, &fdset); 35531465Sminshall if ((i = select(serversock+1, &fdset, 0, 0, 0)) < 0) { 35631465Sminshall if (errno = EINTR) { 35731465Sminshall continue; 35831465Sminshall } else { 35931465Sminshall perror("in select waiting for API connection"); 36031465Sminshall return -1; 36131465Sminshall } 36231465Sminshall } else { 36331465Sminshall i = accept(serversock, 0, 0); 36431465Sminshall if (i == -1) { 36531465Sminshall perror("accepting API connection"); 36631465Sminshall return -1; 36731465Sminshall } 36831465Sminshall sock = i; 36931465Sminshall } 37031465Sminshall } 37131465Sminshall /* If the process has already exited, we may need to close */ 37231465Sminshall if ((shell_active == 0) && (sock != -1)) { 37331465Sminshall (void) close(sock); 37431465Sminshall sock = -1; 37531465Sminshall setcommandmode(); /* In case child_died sneaked in */ 37631465Sminshall } 37731465Sminshall } 37831465Sminshall 37931457Sminshall /* 38031455Sminshall * shell_continue() actually runs the command, and looks for API 38131455Sminshall * requests coming back in. 38231455Sminshall * 38331455Sminshall * We are called from the main loop in telnet.c. 38431455Sminshall */ 38531455Sminshall 38631455Sminshall int 38731455Sminshall shell_continue() 38831455Sminshall { 38931457Sminshall switch (state) { 39031457Sminshall case DEAD: 39131457Sminshall pause(); /* Nothing to do */ 39231457Sminshall break; 39331457Sminshall case UNCONNECTED: 39431465Sminshall if (doconnect() == -1) { 39531457Sminshall kill_connection(); 39631465Sminshall return -1; 39731465Sminshall } 39831465Sminshall if (api_exch_init(sock, "client") == -1) { 39931465Sminshall return -1; 40031465Sminshall } 40131465Sminshall while (state == UNCONNECTED) { 40231465Sminshall if (api_exch_incommand(EXCH_ASSOCIATE) == -1) { 40331457Sminshall kill_connection(); 40431465Sminshall return -1; 40531465Sminshall } else { 40631465Sminshall switch (doassociate()) { 40731465Sminshall case -1: 40831465Sminshall kill_connection(); 40931465Sminshall return -1; 41031465Sminshall case 0: 41131465Sminshall break; 41231465Sminshall case 1: 41331465Sminshall state = CONNECTED; 41431465Sminshall } 41531457Sminshall } 41631457Sminshall } 41731457Sminshall break; 41831457Sminshall case CONNECTED: 41931463Sminshall if (api_exch_incommand(EXCH_REQUEST) == -1) { 42031463Sminshall kill_connection(); 421*31471Sminshall } else if (api_exch_intype(EXCH_TYPE_REGS, sizeof inputRegs, 42231463Sminshall (char *)&inputRegs) == -1) { 42331463Sminshall kill_connection(); 424*31471Sminshall } else if (api_exch_intype(EXCH_TYPE_SREGS, sizeof inputSregs, 42531463Sminshall (char *)&inputSregs) == -1) { 42631463Sminshall kill_connection(); 42731463Sminshall } else if (nextstore() == -1) { 42831463Sminshall kill_connection(); 42931463Sminshall } else { 43031457Sminshall handle_api(&inputRegs, &inputSregs); 43131463Sminshall freestorage(); /* Send any storage back */ 43231463Sminshall if (api_exch_outcommand(EXCH_REPLY) == -1) { 43331463Sminshall kill_connection(); 434*31471Sminshall } else if (api_exch_outtype(EXCH_TYPE_REGS, sizeof inputRegs, 43531463Sminshall (char *)&inputRegs) == -1) { 43631463Sminshall kill_connection(); 437*31471Sminshall } else if (api_exch_outtype(EXCH_TYPE_SREGS, sizeof inputSregs, 43831463Sminshall (char *)&inputSregs) == -1) { 43931463Sminshall kill_connection(); 44031463Sminshall } 44131463Sminshall /* Done, and it all worked! */ 44231457Sminshall } 44331457Sminshall } 44431455Sminshall return shell_active; 44531455Sminshall } 44631455Sminshall 44731455Sminshall 44831463Sminshall static int 44931463Sminshall child_died() 45031463Sminshall { 45131463Sminshall union wait *status; 45231463Sminshall register int pid; 45331463Sminshall 45431463Sminshall while ((pid = wait3(&status, WNOHANG, 0)) > 0) { 45531463Sminshall if (pid == shell_pid) { 45631463Sminshall char inputbuffer[100]; 45731463Sminshall 45831463Sminshall shell_active = 0; 45931463Sminshall if (sock != -1) { 46031463Sminshall (void) close(sock); 46131463Sminshall sock = -1; 46231463Sminshall } 463*31471Sminshall printf("[Hit return to continue]"); 464*31471Sminshall fflush(stdout); 465*31471Sminshall (void) gets(inputbuffer); 46631465Sminshall setconnmode(); 46731465Sminshall ConnectScreen(); /* Turn screen on (if need be) */ 46831465Sminshall (void) close(serversock); 46931463Sminshall } 47031463Sminshall } 47131463Sminshall signal(SIGCHLD, child_died); 47231463Sminshall } 47331463Sminshall 47431463Sminshall 47531455Sminshall /* 47631455Sminshall * Called from telnet.c to fork a lower command.com. We 47731455Sminshall * use the spint... routines so that we can pick up 47831455Sminshall * interrupts generated by application programs. 47931455Sminshall */ 48031455Sminshall 48131455Sminshall 48231455Sminshall int 48331455Sminshall shell(argc,argv) 48431455Sminshall int argc; 48531455Sminshall char *argv[]; 48631455Sminshall { 48731465Sminshall int length; 48831457Sminshall struct sockaddr_in server; 48931457Sminshall char sockNAME[100]; 49031457Sminshall static char **whereAPI = 0; 49131457Sminshall 49231457Sminshall /* First, create the socket which will be connected to */ 49331457Sminshall serversock = socket(AF_INET, SOCK_STREAM, 0); 49431457Sminshall if (serversock < 0) { 49531457Sminshall perror("opening API socket"); 49631457Sminshall return 0; 49731457Sminshall } 49831457Sminshall server.sin_family = AF_INET; 49931457Sminshall server.sin_addr.s_addr = INADDR_ANY; 50031457Sminshall server.sin_port = 0; 50131457Sminshall if (bind(serversock, &server, sizeof server) < 0) { 50231457Sminshall perror("binding API socket"); 50331457Sminshall return 0; 50431457Sminshall } 50531457Sminshall length = sizeof server; 50631457Sminshall if (getsockname(serversock, &server, &length) < 0) { 50731457Sminshall perror("getting API socket name"); 50831457Sminshall (void) close(serversock); 50931457Sminshall } 51031457Sminshall listen(serversock, 1); 51131457Sminshall /* Get name to advertise in address list */ 51231457Sminshall strcpy(sockNAME, "API3270="); 51331457Sminshall gethostname(sockNAME+strlen(sockNAME), sizeof sockNAME-strlen(sockNAME)); 51431457Sminshall if (strlen(sockNAME) > (sizeof sockNAME-10)) { 51531457Sminshall fprintf(stderr, "Local hostname too large; using 'localhost'.\n"); 51631457Sminshall strcpy(sockNAME, "localhost"); 51731457Sminshall } 51831457Sminshall sprintf(sockNAME+strlen(sockNAME), ":%d", ntohs(server.sin_port)); 51931457Sminshall 52031457Sminshall if (whereAPI == 0) { 52131457Sminshall char **ptr, **nextenv; 52231457Sminshall extern char **environ; 52331457Sminshall 52431457Sminshall ptr = environ; 52531457Sminshall nextenv = ourENVlist; 52631457Sminshall while (*ptr) { 52731457Sminshall if (nextenv >= &ourENVlist[highestof(ourENVlist)-1]) { 52831457Sminshall fprintf(stderr, "Too many environmental variables\n"); 52931457Sminshall break; 53031457Sminshall } 53131457Sminshall *nextenv++ = *ptr++; 53231457Sminshall } 53331457Sminshall whereAPI = nextenv++; 53431457Sminshall *nextenv++ = 0; 53531457Sminshall environ = ourENVlist; /* New environment */ 53631457Sminshall } 53731457Sminshall *whereAPI = sockNAME; 53831457Sminshall 53931457Sminshall child_died(); /* Start up signal handler */ 54031457Sminshall shell_active = 1; /* We are running down below */ 54131457Sminshall if (shell_pid = vfork()) { 54231457Sminshall if (shell_pid == -1) { 54331457Sminshall perror("vfork"); 54431457Sminshall (void) close(serversock); 54531457Sminshall } else { 54631465Sminshall state = UNCONNECTED; 54731457Sminshall } 54831455Sminshall } else { /* New process */ 54931455Sminshall register int i; 55031455Sminshall 55131455Sminshall for (i = 3; i < 30; i++) { 55231455Sminshall (void) close(i); 55331455Sminshall } 55431455Sminshall if (argc == 1) { /* Just get a shell */ 55531455Sminshall char *cmdname; 55631457Sminshall extern char *getenv(); 55731455Sminshall 55831455Sminshall cmdname = getenv("SHELL"); 55931455Sminshall execlp(cmdname, cmdname, 0); 56031455Sminshall perror("Exec'ing new shell...\n"); 56131455Sminshall exit(1); 56231455Sminshall } else { 56331455Sminshall execvp(argv[1], &argv[1]); 56431455Sminshall perror("Exec'ing command.\n"); 56531455Sminshall exit(1); 56631455Sminshall } 56731455Sminshall /*NOTREACHED*/ 56831455Sminshall } 56931457Sminshall return shell_active; /* Go back to main loop */ 57031455Sminshall } 571