185b542cfSBrian Somers /*- 285b542cfSBrian Somers * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> 385b542cfSBrian Somers * All rights reserved. 485b542cfSBrian Somers * 585b542cfSBrian Somers * Redistribution and use in source and binary forms, with or without 685b542cfSBrian Somers * modification, are permitted provided that the following conditions 785b542cfSBrian Somers * are met: 885b542cfSBrian Somers * 1. Redistributions of source code must retain the above copyright 985b542cfSBrian Somers * notice, this list of conditions and the following disclaimer. 1085b542cfSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright 1185b542cfSBrian Somers * notice, this list of conditions and the following disclaimer in the 1285b542cfSBrian Somers * documentation and/or other materials provided with the distribution. 1385b542cfSBrian Somers * 1485b542cfSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1585b542cfSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1685b542cfSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1785b542cfSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1885b542cfSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1985b542cfSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2085b542cfSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2185b542cfSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2285b542cfSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2385b542cfSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2485b542cfSBrian Somers * SUCH DAMAGE. 2585b542cfSBrian Somers * 26f91ad6b0SBrian Somers * $Id: prompt.c,v 1.1.2.20 1998/04/04 10:34:28 brian Exp $ 2785b542cfSBrian Somers */ 2885b542cfSBrian Somers 2985b542cfSBrian Somers #include <sys/param.h> 3085b542cfSBrian Somers #include <netinet/in.h> 31eaa4df37SBrian Somers #include <netinet/in_systm.h> 32eaa4df37SBrian Somers #include <netinet/ip.h> 3385b542cfSBrian Somers 34833882f7SBrian Somers #include <errno.h> 3585b542cfSBrian Somers #include <stdarg.h> 3685b542cfSBrian Somers #include <stdio.h> 37b6217683SBrian Somers #include <stdlib.h> 38b6217683SBrian Somers #include <string.h> 3985b542cfSBrian Somers #include <sys/fcntl.h> 4085b542cfSBrian Somers #include <sys/stat.h> 4185b542cfSBrian Somers #include <termios.h> 4285b542cfSBrian Somers #include <unistd.h> 4385b542cfSBrian Somers 4485b542cfSBrian Somers #include "defs.h" 4585b542cfSBrian Somers #include "timer.h" 4685b542cfSBrian Somers #include "command.h" 4785b542cfSBrian Somers #include "log.h" 4885b542cfSBrian Somers #include "descriptor.h" 4985b542cfSBrian Somers #include "prompt.h" 5085b542cfSBrian Somers #include "fsm.h" 5185b542cfSBrian Somers #include "lcp.h" 5285b542cfSBrian Somers #include "auth.h" 5385b542cfSBrian Somers #include "loadalias.h" 5485b542cfSBrian Somers #include "vars.h" 5585b542cfSBrian Somers #include "main.h" 5685b542cfSBrian Somers #include "iplist.h" 5785b542cfSBrian Somers #include "throughput.h" 58eaa4df37SBrian Somers #include "slcompress.h" 5985b542cfSBrian Somers #include "ipcp.h" 605ca5389aSBrian Somers #include "filter.h" 61879ed6faSBrian Somers #include "lqr.h" 623006ec67SBrian Somers #include "hdlc.h" 633006ec67SBrian Somers #include "async.h" 643006ec67SBrian Somers #include "mbuf.h" 653b0f8d2eSBrian Somers #include "ccp.h" 663006ec67SBrian Somers #include "link.h" 673006ec67SBrian Somers #include "physical.h" 683b0f8d2eSBrian Somers #include "mp.h" 693b0f8d2eSBrian Somers #include "bundle.h" 70c5a5a6caSBrian Somers #include "chat.h" 71e2ebb036SBrian Somers #include "chap.h" 72c5a5a6caSBrian Somers #include "datalink.h" 73b6217683SBrian Somers #include "server.h" 7485b542cfSBrian Somers 75b6217683SBrian Somers static void 76b6217683SBrian Somers prompt_Display(struct prompt *p) 77b6217683SBrian Somers { 78b6217683SBrian Somers static char shostname[MAXHOSTNAMELEN]; 79b6217683SBrian Somers const char *pconnect, *pauth; 80b6217683SBrian Somers 81b6217683SBrian Somers if (p->TermMode || !p->needprompt) 82b6217683SBrian Somers return; 83b6217683SBrian Somers 84b6217683SBrian Somers p->needprompt = 0; 85b6217683SBrian Somers 86b6217683SBrian Somers if (p->nonewline) 87b6217683SBrian Somers p->nonewline = 0; 88b6217683SBrian Somers else 89b6217683SBrian Somers fprintf(p->Term, "\n"); 90b6217683SBrian Somers 91b6217683SBrian Somers if (p->auth == LOCAL_AUTH) 92b6217683SBrian Somers pauth = " ON "; 93b6217683SBrian Somers else 94b6217683SBrian Somers pauth = " on "; 95b6217683SBrian Somers 96b6217683SBrian Somers if (p->bundle->ncp.ipcp.fsm.state == ST_OPENED) 97b6217683SBrian Somers pconnect = "PPP"; 98b6217683SBrian Somers else if (bundle_Phase(p->bundle) == PHASE_NETWORK) 99b6217683SBrian Somers pconnect = "PPp"; 100b6217683SBrian Somers else if (bundle_Phase(p->bundle) == PHASE_AUTHENTICATE) 101b6217683SBrian Somers pconnect = "Ppp"; 102b6217683SBrian Somers else 103b6217683SBrian Somers pconnect = "ppp"; 104b6217683SBrian Somers 105b6217683SBrian Somers if (*shostname == '\0') { 106b6217683SBrian Somers char *p; 107b6217683SBrian Somers 108b6217683SBrian Somers if (gethostname(shostname, sizeof shostname)) 109b6217683SBrian Somers strcpy(shostname, "localhost"); 110b6217683SBrian Somers else if ((p = strchr(shostname, '.'))) 111b6217683SBrian Somers *p = '\0'; 112b6217683SBrian Somers } 113b6217683SBrian Somers 114b6217683SBrian Somers fprintf(p->Term, "%s%s%s> ", pconnect, pauth, shostname); 115b6217683SBrian Somers fflush(p->Term); 116b6217683SBrian Somers } 11785b542cfSBrian Somers 11885b542cfSBrian Somers static int 11985b542cfSBrian Somers prompt_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 12085b542cfSBrian Somers { 12185b542cfSBrian Somers struct prompt *p = descriptor2prompt(d); 122b6dec9f0SBrian Somers int sets; 12385b542cfSBrian Somers 124b6dec9f0SBrian Somers sets = 0; 125f91ad6b0SBrian Somers 126f91ad6b0SBrian Somers if (!p->active) 127f91ad6b0SBrian Somers return sets; 128f91ad6b0SBrian Somers 12985b542cfSBrian Somers if (p->fd_in >= 0) { 130b6dec9f0SBrian Somers if (r) { 13185b542cfSBrian Somers FD_SET(p->fd_in, r); 132b6dec9f0SBrian Somers sets++; 133b6dec9f0SBrian Somers } 134b6dec9f0SBrian Somers if (e) { 13585b542cfSBrian Somers FD_SET(p->fd_in, e); 136b6dec9f0SBrian Somers sets++; 137b6dec9f0SBrian Somers } 138b6dec9f0SBrian Somers if (sets && *n < p->fd_in + 1) 139b6dec9f0SBrian Somers *n = p->fd_in + 1; 14085b542cfSBrian Somers } 14185b542cfSBrian Somers 142b6217683SBrian Somers prompt_Display(p); 143b6217683SBrian Somers 144b6dec9f0SBrian Somers return sets; 14585b542cfSBrian Somers } 14685b542cfSBrian Somers 14785b542cfSBrian Somers static int 1482f786681SBrian Somers prompt_IsSet(struct descriptor *d, const fd_set *fdset) 14985b542cfSBrian Somers { 15085b542cfSBrian Somers struct prompt *p = descriptor2prompt(d); 15185b542cfSBrian Somers return p->fd_in >= 0 && FD_ISSET(p->fd_in, fdset); 15285b542cfSBrian Somers } 15385b542cfSBrian Somers 15485b542cfSBrian Somers 15585b542cfSBrian Somers static void 15685b542cfSBrian Somers prompt_ShowHelp(struct prompt *p) 15785b542cfSBrian Somers { 15885b542cfSBrian Somers prompt_Printf(p, "The following commands are available:\r\n"); 15985b542cfSBrian Somers prompt_Printf(p, " ~p\tEnter Packet mode\r\n"); 16085b542cfSBrian Somers prompt_Printf(p, " ~-\tDecrease log level\r\n"); 16185b542cfSBrian Somers prompt_Printf(p, " ~+\tIncrease log level\r\n"); 1623b0f8d2eSBrian Somers prompt_Printf(p, " ~t\tShow timers\r\n"); 1633b0f8d2eSBrian Somers prompt_Printf(p, " ~m\tShow memory map\r\n"); 16485b542cfSBrian Somers prompt_Printf(p, " ~.\tTerminate program\r\n"); 16585b542cfSBrian Somers prompt_Printf(p, " ~?\tThis help\r\n"); 16685b542cfSBrian Somers } 16785b542cfSBrian Somers 16885b542cfSBrian Somers static void 16985b542cfSBrian Somers prompt_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 17085b542cfSBrian Somers { 17185b542cfSBrian Somers struct prompt *p = descriptor2prompt(d); 17285b542cfSBrian Somers int n; 17385b542cfSBrian Somers char ch; 17485b542cfSBrian Somers static int ttystate; 17585b542cfSBrian Somers char linebuff[LINE_LEN]; 17685b542cfSBrian Somers 1771b35f8f7SBrian Somers LogPrintf(LogDEBUG, "termode = %p, p->fd_in = %d, mode = %d\n", 17885b542cfSBrian Somers p->TermMode, p->fd_in, mode); 17985b542cfSBrian Somers 1801b35f8f7SBrian Somers if (p->TermMode == NULL) { 18185b542cfSBrian Somers n = read(p->fd_in, linebuff, sizeof linebuff - 1); 18285b542cfSBrian Somers if (n > 0) { 18385b542cfSBrian Somers if (linebuff[n-1] == '\n') 18485b542cfSBrian Somers linebuff[--n] = '\0'; 18585b542cfSBrian Somers else 18685b542cfSBrian Somers linebuff[n] = '\0'; 187b6217683SBrian Somers p->nonewline = 1; /* Maybe DecodeCommand does a prompt */ 188b6217683SBrian Somers prompt_Required(p); 18985b542cfSBrian Somers if (n) 190b6217683SBrian Somers DecodeCommand(bundle, linebuff, n, p, 191b6217683SBrian Somers IsInteractive(NULL) ? NULL : "Client"); 19285b542cfSBrian Somers } else if (n <= 0) { 19385b542cfSBrian Somers LogPrintf(LogPHASE, "Client connection closed.\n"); 194b6217683SBrian Somers prompt_Destroy(p, 0); 19585b542cfSBrian Somers } 19685b542cfSBrian Somers return; 19785b542cfSBrian Somers } 19885b542cfSBrian Somers 199c7cc5030SBrian Somers switch (p->TermMode->state) { 200c7cc5030SBrian Somers case DATALINK_CLOSED: 201c7cc5030SBrian Somers prompt_Printf(p, "Link lost, terminal mode.\n"); 202b6217683SBrian Somers prompt_TtyCommandMode(p); 203b6217683SBrian Somers p->nonewline = 0; 204b6217683SBrian Somers prompt_Required(p); 205c7cc5030SBrian Somers return; 206c7cc5030SBrian Somers 207c7cc5030SBrian Somers case DATALINK_READY: 208c7cc5030SBrian Somers break; 209c7cc5030SBrian Somers 210c7cc5030SBrian Somers case DATALINK_OPEN: 211c7cc5030SBrian Somers prompt_Printf(p, "\nPacket mode detected.\n"); 212b6217683SBrian Somers prompt_TtyCommandMode(p); 213b6217683SBrian Somers p->nonewline = 0; 214c7cc5030SBrian Somers /* We'll get a prompt because of our status change */ 215c7cc5030SBrian Somers /* Fall through */ 216c7cc5030SBrian Somers 217c7cc5030SBrian Somers default: 218c7cc5030SBrian Somers /* Wait 'till we're in a state we care about */ 219c7cc5030SBrian Somers return; 220c7cc5030SBrian Somers } 221c7cc5030SBrian Somers 22285b542cfSBrian Somers /* 22385b542cfSBrian Somers * We are in terminal mode, decode special sequences 22485b542cfSBrian Somers */ 22585b542cfSBrian Somers n = read(p->fd_in, &ch, 1); 22685b542cfSBrian Somers LogPrintf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n); 22785b542cfSBrian Somers 22885b542cfSBrian Somers if (n > 0) { 22985b542cfSBrian Somers switch (ttystate) { 23085b542cfSBrian Somers case 0: 23185b542cfSBrian Somers if (ch == '~') 23285b542cfSBrian Somers ttystate++; 23385b542cfSBrian Somers else 234833882f7SBrian Somers if (Physical_Write(p->TermMode->physical, &ch, n) < 0) { 235833882f7SBrian Somers LogPrintf(LogERROR, "error writing to modem: %s\n", strerror(errno)); 236833882f7SBrian Somers prompt_TtyCommandMode(p); 237833882f7SBrian Somers } 23885b542cfSBrian Somers break; 23985b542cfSBrian Somers case 1: 24085b542cfSBrian Somers switch (ch) { 24185b542cfSBrian Somers case '?': 24285b542cfSBrian Somers prompt_ShowHelp(p); 24385b542cfSBrian Somers break; 24485b542cfSBrian Somers case 'p': 245c7cc5030SBrian Somers datalink_Up(p->TermMode, 0, 1); 246c7cc5030SBrian Somers prompt_Printf(p, "\nPacket mode.\n"); 247b6217683SBrian Somers prompt_TtyCommandMode(p); 24885b542cfSBrian Somers break; 24985b542cfSBrian Somers case '.': 250b6217683SBrian Somers prompt_TtyCommandMode(p); 251b6217683SBrian Somers p->nonewline = 0; 252b6217683SBrian Somers prompt_Required(p); 25385b542cfSBrian Somers break; 25485b542cfSBrian Somers case 't': 255b6217683SBrian Somers ShowTimers(0, p); 25685b542cfSBrian Somers break; 25785b542cfSBrian Somers case 'm': 25885b542cfSBrian Somers ShowMemMap(NULL); 25985b542cfSBrian Somers break; 26085b542cfSBrian Somers default: 261833882f7SBrian Somers if (Physical_Write(p->TermMode->physical, &ch, n) < 0) { 262833882f7SBrian Somers LogPrintf(LogERROR, "error writing to modem: %s\n", strerror(errno)); 263833882f7SBrian Somers prompt_TtyCommandMode(p); 264833882f7SBrian Somers } 26585b542cfSBrian Somers break; 26685b542cfSBrian Somers } 26785b542cfSBrian Somers ttystate = 0; 26885b542cfSBrian Somers break; 26985b542cfSBrian Somers } 27085b542cfSBrian Somers } 27185b542cfSBrian Somers } 27285b542cfSBrian Somers 27385b542cfSBrian Somers static void 274f4768038SBrian Somers prompt_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 27585b542cfSBrian Somers { 276f4768038SBrian Somers /* We never want to write here ! */ 277f4768038SBrian Somers LogPrintf(LogERROR, "prompt_Write: Internal error: Bad call !\n"); 27885b542cfSBrian Somers } 27985b542cfSBrian Somers 280b6217683SBrian Somers struct prompt * 281b6217683SBrian Somers prompt_Create(struct server *s, struct bundle *bundle, int fd) 28285b542cfSBrian Somers { 283b6217683SBrian Somers struct prompt *p = (struct prompt *)malloc(sizeof(struct prompt)); 28485b542cfSBrian Somers 285b6217683SBrian Somers if (p != NULL) { 286b6217683SBrian Somers p->desc.type = PROMPT_DESCRIPTOR; 287b6217683SBrian Somers p->desc.next = NULL; 288b6217683SBrian Somers p->desc.UpdateSet = prompt_UpdateSet; 289b6217683SBrian Somers p->desc.IsSet = prompt_IsSet; 290b6217683SBrian Somers p->desc.Read = prompt_Read; 291b6217683SBrian Somers p->desc.Write = prompt_Write; 29285b542cfSBrian Somers 293b6217683SBrian Somers if (fd == PROMPT_STD) { 29485b542cfSBrian Somers p->fd_in = STDIN_FILENO; 29585b542cfSBrian Somers p->fd_out = STDOUT_FILENO; 29685b542cfSBrian Somers p->Term = stdout; 297b6217683SBrian Somers p->owner = NULL; 298b6217683SBrian Somers p->auth = LOCAL_AUTH; 299b6217683SBrian Somers snprintf(p->who, sizeof p->who, "Controller (%s)", ttyname(p->fd_out)); 300b6217683SBrian Somers tcgetattr(p->fd_in, &p->oldtio); /* Save original tty mode */ 30185b542cfSBrian Somers } else { 30285b542cfSBrian Somers p->fd_in = p->fd_out = fd; 30385b542cfSBrian Somers p->Term = fdopen(fd, "a+"); 304b6217683SBrian Somers p->owner = s; 305b6217683SBrian Somers p->auth = *s->passwd ? LOCAL_NO_AUTH : LOCAL_AUTH; 306b6217683SBrian Somers *p->who = '\0'; 30785b542cfSBrian Somers } 3081b35f8f7SBrian Somers p->TermMode = NULL; 309b6217683SBrian Somers p->nonewline = 1; 310b6217683SBrian Somers p->needprompt = 1; 311f91ad6b0SBrian Somers p->active = 1; 312b6217683SBrian Somers p->bundle = bundle; 313b6217683SBrian Somers if (p->bundle) 314b6217683SBrian Somers bundle_RegisterDescriptor(p->bundle, &p->desc); 315b6217683SBrian Somers log_RegisterPrompt(p); 316cfb7c5ffSBrian Somers LogDiscardAllLocal(&p->logmask); 317b6217683SBrian Somers } 31885b542cfSBrian Somers 319b6217683SBrian Somers return p; 32085b542cfSBrian Somers } 32185b542cfSBrian Somers 3223006ec67SBrian Somers void 323b6217683SBrian Somers prompt_DestroyUnclean(struct prompt *p) 32485b542cfSBrian Somers { 325b6217683SBrian Somers log_UnRegisterPrompt(p); 326b6217683SBrian Somers bundle_UnRegisterDescriptor(p->bundle, &p->desc); 327b6217683SBrian Somers free(p); 32885b542cfSBrian Somers } 32985b542cfSBrian Somers 33085b542cfSBrian Somers void 331b6217683SBrian Somers prompt_Destroy(struct prompt *p, int verbose) 33285b542cfSBrian Somers { 333b6217683SBrian Somers if (p->Term != stdout) { 334b6217683SBrian Somers fclose(p->Term); 33585b542cfSBrian Somers close(p->fd_in); 33685b542cfSBrian Somers if (p->fd_out != p->fd_in) 33785b542cfSBrian Somers close(p->fd_out); 33885b542cfSBrian Somers if (verbose) 33985b542cfSBrian Somers LogPrintf(LogPHASE, "Client connection dropped.\n"); 340b6217683SBrian Somers } else 341b6217683SBrian Somers prompt_TtyOldMode(p); 342b6217683SBrian Somers 343b6217683SBrian Somers prompt_DestroyUnclean(p); 34485b542cfSBrian Somers } 34585b542cfSBrian Somers 34685b542cfSBrian Somers void 34785b542cfSBrian Somers prompt_Printf(struct prompt *p, const char *fmt,...) 34885b542cfSBrian Somers { 349f91ad6b0SBrian Somers if (p && p->active) { 35085b542cfSBrian Somers va_list ap; 35185b542cfSBrian Somers 35285b542cfSBrian Somers va_start(ap, fmt); 35385b542cfSBrian Somers vfprintf(p->Term, fmt, ap); 35485b542cfSBrian Somers fflush(p->Term); 35585b542cfSBrian Somers va_end(ap); 35685b542cfSBrian Somers } 35785b542cfSBrian Somers } 35885b542cfSBrian Somers 35985b542cfSBrian Somers void 36085b542cfSBrian Somers prompt_vPrintf(struct prompt *p, const char *fmt, va_list ap) 36185b542cfSBrian Somers { 362f91ad6b0SBrian Somers if (p && p->active) { 36385b542cfSBrian Somers vfprintf(p->Term, fmt, ap); 36485b542cfSBrian Somers fflush(p->Term); 36585b542cfSBrian Somers } 36685b542cfSBrian Somers } 36785b542cfSBrian Somers 36885b542cfSBrian Somers void 36985b542cfSBrian Somers prompt_TtyInit(struct prompt *p, int DontWantInt) 37085b542cfSBrian Somers { 37185b542cfSBrian Somers int stat; 37285b542cfSBrian Somers 37385b542cfSBrian Somers stat = fcntl(p->fd_in, F_GETFL, 0); 37485b542cfSBrian Somers if (stat > 0) { 37585b542cfSBrian Somers stat |= O_NONBLOCK; 376b6217683SBrian Somers fcntl(p->fd_in, F_SETFL, stat); 37785b542cfSBrian Somers } 378b6217683SBrian Somers 379b6217683SBrian Somers if (p->Term == stdout) { 380b6217683SBrian Somers struct termios newtio; 381b6217683SBrian Somers 38285b542cfSBrian Somers newtio = p->oldtio; 38385b542cfSBrian Somers newtio.c_lflag &= ~(ECHO | ISIG | ICANON); 38485b542cfSBrian Somers newtio.c_iflag = 0; 38585b542cfSBrian Somers newtio.c_oflag &= ~OPOST; 38685b542cfSBrian Somers newtio.c_cc[VEOF] = _POSIX_VDISABLE; 38785b542cfSBrian Somers if (DontWantInt) 38885b542cfSBrian Somers newtio.c_cc[VINTR] = _POSIX_VDISABLE; 38985b542cfSBrian Somers newtio.c_cc[VMIN] = 1; 39085b542cfSBrian Somers newtio.c_cc[VTIME] = 0; 39185b542cfSBrian Somers newtio.c_cflag |= CS8; 39285b542cfSBrian Somers tcsetattr(p->fd_in, TCSANOW, &newtio); 39385b542cfSBrian Somers p->comtio = newtio; 39485b542cfSBrian Somers } 395b6217683SBrian Somers } 39685b542cfSBrian Somers 39785b542cfSBrian Somers /* 39885b542cfSBrian Somers * Set tty into command mode. We allow canonical input and echo processing. 39985b542cfSBrian Somers */ 40085b542cfSBrian Somers void 40185b542cfSBrian Somers prompt_TtyCommandMode(struct prompt *p) 40285b542cfSBrian Somers { 40385b542cfSBrian Somers struct termios newtio; 40485b542cfSBrian Somers int stat; 40585b542cfSBrian Somers 40685b542cfSBrian Somers tcgetattr(p->fd_in, &newtio); 40785b542cfSBrian Somers newtio.c_lflag |= (ECHO | ISIG | ICANON); 40885b542cfSBrian Somers newtio.c_iflag = p->oldtio.c_iflag; 40985b542cfSBrian Somers newtio.c_oflag |= OPOST; 41085b542cfSBrian Somers tcsetattr(p->fd_in, TCSADRAIN, &newtio); 411b6217683SBrian Somers 41285b542cfSBrian Somers stat = fcntl(p->fd_in, F_GETFL, 0); 41385b542cfSBrian Somers if (stat > 0) { 41485b542cfSBrian Somers stat |= O_NONBLOCK; 415b6217683SBrian Somers fcntl(p->fd_in, F_SETFL, stat); 41685b542cfSBrian Somers } 417b6217683SBrian Somers 4181b35f8f7SBrian Somers p->TermMode = NULL; 41985b542cfSBrian Somers } 42085b542cfSBrian Somers 42185b542cfSBrian Somers /* 42285b542cfSBrian Somers * Set tty into terminal mode which is used while we invoke term command. 42385b542cfSBrian Somers */ 42485b542cfSBrian Somers void 4251b35f8f7SBrian Somers prompt_TtyTermMode(struct prompt *p, struct datalink *dl) 42685b542cfSBrian Somers { 42785b542cfSBrian Somers int stat; 42885b542cfSBrian Somers 429b6217683SBrian Somers prompt_Printf(p, "Entering terminal mode on %s.\n", dl->name); 430b6217683SBrian Somers prompt_Printf(p, "Type `~?' for help.\n"); 431b6217683SBrian Somers 432b6217683SBrian Somers if (p->Term == stdout) 43385b542cfSBrian Somers tcsetattr(p->fd_in, TCSADRAIN, &p->comtio); 434b6217683SBrian Somers 43585b542cfSBrian Somers stat = fcntl(p->fd_in, F_GETFL, 0); 43685b542cfSBrian Somers if (stat > 0) { 43785b542cfSBrian Somers stat &= ~O_NONBLOCK; 438b6217683SBrian Somers fcntl(p->fd_in, F_SETFL, stat); 43985b542cfSBrian Somers } 4401b35f8f7SBrian Somers p->TermMode = dl; 44185b542cfSBrian Somers } 44285b542cfSBrian Somers 44385b542cfSBrian Somers void 44485b542cfSBrian Somers prompt_TtyOldMode(struct prompt *p) 44585b542cfSBrian Somers { 44685b542cfSBrian Somers int stat; 44785b542cfSBrian Somers 44885b542cfSBrian Somers stat = fcntl(p->fd_in, F_GETFL, 0); 44985b542cfSBrian Somers if (stat > 0) { 45085b542cfSBrian Somers stat &= ~O_NONBLOCK; 451b6217683SBrian Somers fcntl(p->fd_in, F_SETFL, stat); 45285b542cfSBrian Somers } 453b6217683SBrian Somers 454b6217683SBrian Somers if (p->Term == stdout) 45585b542cfSBrian Somers tcsetattr(p->fd_in, TCSADRAIN, &p->oldtio); 45685b542cfSBrian Somers } 45785b542cfSBrian Somers 45885b542cfSBrian Somers pid_t 45985b542cfSBrian Somers prompt_pgrp(struct prompt *p) 46085b542cfSBrian Somers { 461b6217683SBrian Somers return tcgetpgrp(p->fd_in); 462b6217683SBrian Somers } 463b6217683SBrian Somers 464b6217683SBrian Somers int 465b6217683SBrian Somers PasswdCommand(struct cmdargs const *arg) 466b6217683SBrian Somers { 467b6217683SBrian Somers const char *pass; 468b6217683SBrian Somers 469b6217683SBrian Somers if (!arg->prompt) { 470b6217683SBrian Somers LogPrintf(LogWARN, "passwd: Cannot specify without a prompt\n"); 471b6217683SBrian Somers return 0; 472b6217683SBrian Somers } 473b6217683SBrian Somers 474b6217683SBrian Somers if (arg->prompt->owner == NULL) { 475b6217683SBrian Somers LogPrintf(LogWARN, "passwd: Not required\n"); 476b6217683SBrian Somers return 0; 477b6217683SBrian Somers } 478b6217683SBrian Somers 479b6217683SBrian Somers if (arg->argc == 0) 480b6217683SBrian Somers pass = ""; 481b6217683SBrian Somers else if (arg->argc > 1) 482b6217683SBrian Somers return -1; 483b6217683SBrian Somers else 484b6217683SBrian Somers pass = *arg->argv; 485b6217683SBrian Somers 486b6217683SBrian Somers if (!strcmp(arg->prompt->owner->passwd, pass)) 487b6217683SBrian Somers arg->prompt->auth = LOCAL_AUTH; 488b6217683SBrian Somers else 489b6217683SBrian Somers arg->prompt->auth = LOCAL_NO_AUTH; 490b6217683SBrian Somers 491b6217683SBrian Somers return 0; 49285b542cfSBrian Somers } 493f91ad6b0SBrian Somers 494f91ad6b0SBrian Somers static struct pppTimer bgtimer; 495f91ad6b0SBrian Somers 496f91ad6b0SBrian Somers static void 497f91ad6b0SBrian Somers prompt_TimedContinue(void *v) 498f91ad6b0SBrian Somers { 499f91ad6b0SBrian Somers prompt_Continue((struct prompt *)v); 500f91ad6b0SBrian Somers } 501f91ad6b0SBrian Somers 502f91ad6b0SBrian Somers void 503f91ad6b0SBrian Somers prompt_Continue(struct prompt *p) 504f91ad6b0SBrian Somers { 505f91ad6b0SBrian Somers StopTimer(&bgtimer); 506f91ad6b0SBrian Somers if (getpgrp() == prompt_pgrp(p)) { 507f91ad6b0SBrian Somers prompt_TtyCommandMode(p); 508f91ad6b0SBrian Somers p->nonewline = 1; 509f91ad6b0SBrian Somers prompt_Required(p); 510f91ad6b0SBrian Somers p->active = 1; 511f91ad6b0SBrian Somers } else if (!p->owner) { 512f91ad6b0SBrian Somers bgtimer.func = prompt_TimedContinue; 513f91ad6b0SBrian Somers bgtimer.name = "prompt bg"; 514f91ad6b0SBrian Somers bgtimer.load = SECTICKS; 515f91ad6b0SBrian Somers bgtimer.state = TIMER_STOPPED; 516f91ad6b0SBrian Somers bgtimer.arg = p; 517f91ad6b0SBrian Somers StartTimer(&bgtimer); 518f91ad6b0SBrian Somers } 519f91ad6b0SBrian Somers } 520f91ad6b0SBrian Somers 521f91ad6b0SBrian Somers void 522f91ad6b0SBrian Somers prompt_Suspend(struct prompt *p) 523f91ad6b0SBrian Somers { 524f91ad6b0SBrian Somers if (getpgrp() == prompt_pgrp(p)) { 525f91ad6b0SBrian Somers prompt_TtyOldMode(p); 526f91ad6b0SBrian Somers p->active = 0; 527f91ad6b0SBrian Somers } 528f91ad6b0SBrian Somers } 529