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 * 2697d92980SPeter Wemm * $FreeBSD$ 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> 33565e35e5SBrian Somers #include <sys/un.h> 3485b542cfSBrian Somers 35833882f7SBrian Somers #include <errno.h> 3685b542cfSBrian Somers #include <stdarg.h> 3785b542cfSBrian Somers #include <stdio.h> 38b6217683SBrian Somers #include <stdlib.h> 39b6217683SBrian Somers #include <string.h> 4085b542cfSBrian Somers #include <sys/fcntl.h> 4185b542cfSBrian Somers #include <termios.h> 4285b542cfSBrian Somers #include <unistd.h> 4385b542cfSBrian Somers 445d9e6103SBrian Somers #include "layer.h" 4585b542cfSBrian Somers #include "defs.h" 4685b542cfSBrian Somers #include "timer.h" 4785b542cfSBrian Somers #include "command.h" 4885b542cfSBrian Somers #include "log.h" 4985b542cfSBrian Somers #include "descriptor.h" 5085b542cfSBrian Somers #include "prompt.h" 5185b542cfSBrian Somers #include "fsm.h" 5285b542cfSBrian Somers #include "lcp.h" 5385b542cfSBrian Somers #include "auth.h" 5485b542cfSBrian Somers #include "iplist.h" 5585b542cfSBrian Somers #include "throughput.h" 56eaa4df37SBrian Somers #include "slcompress.h" 575a72b6edSBrian Somers #include "mbuf.h" 58879ed6faSBrian Somers #include "lqr.h" 593006ec67SBrian Somers #include "hdlc.h" 605a72b6edSBrian Somers #include "ipcp.h" 615a72b6edSBrian Somers #include "filter.h" 623006ec67SBrian Somers #include "async.h" 633b0f8d2eSBrian Somers #include "ccp.h" 643006ec67SBrian Somers #include "link.h" 653006ec67SBrian Somers #include "physical.h" 663b0f8d2eSBrian Somers #include "mp.h" 67972a1bcfSBrian Somers #ifndef NORADIUS 68972a1bcfSBrian Somers #include "radius.h" 69972a1bcfSBrian Somers #endif 703b0f8d2eSBrian Somers #include "bundle.h" 71c5a5a6caSBrian Somers #include "chat.h" 72e2ebb036SBrian Somers #include "chap.h" 7392b09558SBrian Somers #include "cbcp.h" 74c5a5a6caSBrian Somers #include "datalink.h" 75b6217683SBrian Somers #include "server.h" 769dae3e8dSBrian Somers #include "main.h" 7785b542cfSBrian Somers 78b6217683SBrian Somers static void 79b6217683SBrian Somers prompt_Display(struct prompt *p) 80b6217683SBrian Somers { 81d93d3a9cSBrian Somers /* XXX: See Index2Nam() - should we only figure this out once ? */ 82b6217683SBrian Somers static char shostname[MAXHOSTNAMELEN]; 83b6217683SBrian Somers const char *pconnect, *pauth; 84b6217683SBrian Somers 85b6217683SBrian Somers if (p->TermMode || !p->needprompt) 86b6217683SBrian Somers return; 87b6217683SBrian Somers 88b6217683SBrian Somers p->needprompt = 0; 89b6217683SBrian Somers 90b6217683SBrian Somers if (p->nonewline) 91b6217683SBrian Somers p->nonewline = 0; 92b6217683SBrian Somers else 93b6217683SBrian Somers fprintf(p->Term, "\n"); 94b6217683SBrian Somers 95b6217683SBrian Somers if (p->auth == LOCAL_AUTH) 96b6217683SBrian Somers pauth = " ON "; 97b6217683SBrian Somers else 98b6217683SBrian Somers pauth = " on "; 99b6217683SBrian Somers 100b6217683SBrian Somers if (p->bundle->ncp.ipcp.fsm.state == ST_OPENED) 101b6217683SBrian Somers pconnect = "PPP"; 102b6217683SBrian Somers else if (bundle_Phase(p->bundle) == PHASE_NETWORK) 103b6217683SBrian Somers pconnect = "PPp"; 104b6217683SBrian Somers else if (bundle_Phase(p->bundle) == PHASE_AUTHENTICATE) 105b6217683SBrian Somers pconnect = "Ppp"; 106b6217683SBrian Somers else 107b6217683SBrian Somers pconnect = "ppp"; 108b6217683SBrian Somers 109b6217683SBrian Somers if (*shostname == '\0') { 110cdbbb6b5SBrian Somers char *dot; 111b6217683SBrian Somers 112b6217683SBrian Somers if (gethostname(shostname, sizeof shostname)) 113b6217683SBrian Somers strcpy(shostname, "localhost"); 114cdbbb6b5SBrian Somers else if ((dot = strchr(shostname, '.'))) 115cdbbb6b5SBrian Somers *dot = '\0'; 116b6217683SBrian Somers } 117b6217683SBrian Somers 118b6217683SBrian Somers fprintf(p->Term, "%s%s%s> ", pconnect, pauth, shostname); 119b6217683SBrian Somers fflush(p->Term); 120b6217683SBrian Somers } 12185b542cfSBrian Somers 12285b542cfSBrian Somers static int 123f013f33eSBrian Somers prompt_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 12485b542cfSBrian Somers { 12585b542cfSBrian Somers struct prompt *p = descriptor2prompt(d); 126b6dec9f0SBrian Somers int sets; 12785b542cfSBrian Somers 128b6dec9f0SBrian Somers sets = 0; 129f91ad6b0SBrian Somers 130f91ad6b0SBrian Somers if (!p->active) 131f91ad6b0SBrian Somers return sets; 132f91ad6b0SBrian Somers 13385b542cfSBrian Somers if (p->fd_in >= 0) { 134b6dec9f0SBrian Somers if (r) { 13585b542cfSBrian Somers FD_SET(p->fd_in, r); 13624989c68SBrian Somers log_Printf(LogTIMER, "prompt %s: fdset(r) %d\n", p->src.from, p->fd_in); 137b6dec9f0SBrian Somers sets++; 138b6dec9f0SBrian Somers } 139b6dec9f0SBrian Somers if (e) { 14085b542cfSBrian Somers FD_SET(p->fd_in, e); 14124989c68SBrian Somers log_Printf(LogTIMER, "prompt %s: fdset(e) %d\n", p->src.from, p->fd_in); 142b6dec9f0SBrian Somers sets++; 143b6dec9f0SBrian Somers } 144b6dec9f0SBrian Somers if (sets && *n < p->fd_in + 1) 145b6dec9f0SBrian Somers *n = p->fd_in + 1; 14685b542cfSBrian Somers } 14785b542cfSBrian Somers 148b6217683SBrian Somers prompt_Display(p); 149b6217683SBrian Somers 150b6dec9f0SBrian Somers return sets; 15185b542cfSBrian Somers } 15285b542cfSBrian Somers 15385b542cfSBrian Somers static int 154f013f33eSBrian Somers prompt_IsSet(struct fdescriptor *d, const fd_set *fdset) 15585b542cfSBrian Somers { 15685b542cfSBrian Somers struct prompt *p = descriptor2prompt(d); 15785b542cfSBrian Somers return p->fd_in >= 0 && FD_ISSET(p->fd_in, fdset); 15885b542cfSBrian Somers } 15985b542cfSBrian Somers 16085b542cfSBrian Somers 16185b542cfSBrian Somers static void 16285b542cfSBrian Somers prompt_ShowHelp(struct prompt *p) 16385b542cfSBrian Somers { 164f7704be7SBrian Somers prompt_Printf(p, "The following commands are available:\n"); 165f7704be7SBrian Somers prompt_Printf(p, " ~p\tEnter Packet mode\n"); 166f7704be7SBrian Somers prompt_Printf(p, " ~t\tShow timers\n"); 167f7704be7SBrian Somers prompt_Printf(p, " ~m\tShow memory map\n"); 168f7704be7SBrian Somers prompt_Printf(p, " ~.\tTerminate program\n"); 169f7704be7SBrian Somers prompt_Printf(p, " ~?\tThis help\n"); 17085b542cfSBrian Somers } 17185b542cfSBrian Somers 17285b542cfSBrian Somers static void 173f013f33eSBrian Somers prompt_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 17485b542cfSBrian Somers { 17585b542cfSBrian Somers struct prompt *p = descriptor2prompt(d); 176b4f63b0bSBrian Somers struct prompt *op; 17785b542cfSBrian Somers int n; 17885b542cfSBrian Somers char ch; 17985b542cfSBrian Somers char linebuff[LINE_LEN]; 18085b542cfSBrian Somers 1811b35f8f7SBrian Somers if (p->TermMode == NULL) { 18285b542cfSBrian Somers n = read(p->fd_in, linebuff, sizeof linebuff - 1); 18385b542cfSBrian Somers if (n > 0) { 18485b542cfSBrian Somers if (linebuff[n-1] == '\n') 18585b542cfSBrian Somers linebuff[--n] = '\0'; 18685b542cfSBrian Somers else 18785b542cfSBrian Somers linebuff[n] = '\0'; 188dd7e2610SBrian Somers p->nonewline = 1; /* Maybe command_Decode does a prompt */ 189b6217683SBrian Somers prompt_Required(p); 190b4f63b0bSBrian Somers if (n) { 191b4f63b0bSBrian Somers if ((op = log_PromptContext) == NULL) 192b4f63b0bSBrian Somers log_PromptContext = p; 193c39aa54eSBrian Somers if (!command_Decode(bundle, linebuff, n, p, p->src.from)) 194c39aa54eSBrian Somers prompt_Printf(p, "Syntax error\n"); 195b4f63b0bSBrian Somers log_PromptContext = op; 196b4f63b0bSBrian Somers } 19785b542cfSBrian Somers } else if (n <= 0) { 1980f2f3eb3SBrian Somers log_Printf(LogPHASE, "%s: Client connection closed.\n", p->src.from); 1999dae3e8dSBrian Somers if (!p->owner) 2009dae3e8dSBrian Somers Cleanup(EX_NORMAL); 201b6217683SBrian Somers prompt_Destroy(p, 0); 20285b542cfSBrian Somers } 20385b542cfSBrian Somers return; 20485b542cfSBrian Somers } 20585b542cfSBrian Somers 206c7cc5030SBrian Somers switch (p->TermMode->state) { 207c7cc5030SBrian Somers case DATALINK_CLOSED: 208c7cc5030SBrian Somers prompt_Printf(p, "Link lost, terminal mode.\n"); 209b6217683SBrian Somers prompt_TtyCommandMode(p); 210b6217683SBrian Somers p->nonewline = 0; 211b6217683SBrian Somers prompt_Required(p); 212c7cc5030SBrian Somers return; 213c7cc5030SBrian Somers 214c7cc5030SBrian Somers case DATALINK_READY: 215c7cc5030SBrian Somers break; 216c7cc5030SBrian Somers 217c7cc5030SBrian Somers case DATALINK_OPEN: 218c7cc5030SBrian Somers prompt_Printf(p, "\nPacket mode detected.\n"); 219b6217683SBrian Somers prompt_TtyCommandMode(p); 220b6217683SBrian Somers p->nonewline = 0; 221c7cc5030SBrian Somers /* We'll get a prompt because of our status change */ 222c7cc5030SBrian Somers /* Fall through */ 223c7cc5030SBrian Somers 224c7cc5030SBrian Somers default: 225c7cc5030SBrian Somers /* Wait 'till we're in a state we care about */ 226c7cc5030SBrian Somers return; 227c7cc5030SBrian Somers } 228c7cc5030SBrian Somers 22985b542cfSBrian Somers /* 23085b542cfSBrian Somers * We are in terminal mode, decode special sequences 23185b542cfSBrian Somers */ 23285b542cfSBrian Somers n = read(p->fd_in, &ch, 1); 233dd7e2610SBrian Somers log_Printf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n); 23485b542cfSBrian Somers 23585b542cfSBrian Somers if (n > 0) { 236d93d3a9cSBrian Somers switch (p->readtilde) { 23785b542cfSBrian Somers case 0: 23885b542cfSBrian Somers if (ch == '~') 239d93d3a9cSBrian Somers p->readtilde = 1; 24085b542cfSBrian Somers else 241dd7e2610SBrian Somers if (physical_Write(p->TermMode->physical, &ch, n) < 0) { 242a33b2ef7SBrian Somers log_Printf(LogWARN, "error writing to modem: %s\n", strerror(errno)); 243833882f7SBrian Somers prompt_TtyCommandMode(p); 244833882f7SBrian Somers } 24585b542cfSBrian Somers break; 24685b542cfSBrian Somers case 1: 24785b542cfSBrian Somers switch (ch) { 24885b542cfSBrian Somers case '?': 24985b542cfSBrian Somers prompt_ShowHelp(p); 25085b542cfSBrian Somers break; 25185b542cfSBrian Somers case 'p': 252c7cc5030SBrian Somers datalink_Up(p->TermMode, 0, 1); 253c7cc5030SBrian Somers prompt_Printf(p, "\nPacket mode.\n"); 254b6217683SBrian Somers prompt_TtyCommandMode(p); 25585b542cfSBrian Somers break; 25685b542cfSBrian Somers case '.': 257b6217683SBrian Somers prompt_TtyCommandMode(p); 258b6217683SBrian Somers p->nonewline = 0; 259b6217683SBrian Somers prompt_Required(p); 26085b542cfSBrian Somers break; 26185b542cfSBrian Somers case 't': 262dd7e2610SBrian Somers timer_Show(0, p); 26385b542cfSBrian Somers break; 26485b542cfSBrian Somers case 'm': 265f7704be7SBrian Somers { 266f7704be7SBrian Somers struct cmdargs arg; 267f7704be7SBrian Somers 268f7704be7SBrian Somers arg.cmdtab = NULL; 269f7704be7SBrian Somers arg.cmd = NULL; 270f7704be7SBrian Somers arg.argc = 0; 271f7704be7SBrian Somers arg.argn = 0; 272f7704be7SBrian Somers arg.argv = NULL; 273f7704be7SBrian Somers arg.bundle = bundle; 274f7704be7SBrian Somers arg.cx = p->TermMode; 275f7704be7SBrian Somers arg.prompt = p; 276f7704be7SBrian Somers 277f7704be7SBrian Somers mbuf_Show(&arg); 278f7704be7SBrian Somers } 27985b542cfSBrian Somers break; 28085b542cfSBrian Somers default: 281dd7e2610SBrian Somers if (physical_Write(p->TermMode->physical, &ch, n) < 0) { 282a33b2ef7SBrian Somers log_Printf(LogWARN, "error writing to modem: %s\n", strerror(errno)); 283833882f7SBrian Somers prompt_TtyCommandMode(p); 284833882f7SBrian Somers } 28585b542cfSBrian Somers break; 28685b542cfSBrian Somers } 287d93d3a9cSBrian Somers p->readtilde = 0; 28885b542cfSBrian Somers break; 28985b542cfSBrian Somers } 29085b542cfSBrian Somers } 29185b542cfSBrian Somers } 29285b542cfSBrian Somers 2931af29a6eSBrian Somers static int 294f013f33eSBrian Somers prompt_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 29585b542cfSBrian Somers { 296f4768038SBrian Somers /* We never want to write here ! */ 297a33b2ef7SBrian Somers log_Printf(LogALERT, "prompt_Write: Internal error: Bad call !\n"); 2981af29a6eSBrian Somers return 0; 29985b542cfSBrian Somers } 30085b542cfSBrian Somers 301b6217683SBrian Somers struct prompt * 302b6217683SBrian Somers prompt_Create(struct server *s, struct bundle *bundle, int fd) 30385b542cfSBrian Somers { 304b6217683SBrian Somers struct prompt *p = (struct prompt *)malloc(sizeof(struct prompt)); 30585b542cfSBrian Somers 306b6217683SBrian Somers if (p != NULL) { 307b6217683SBrian Somers p->desc.type = PROMPT_DESCRIPTOR; 308b6217683SBrian Somers p->desc.UpdateSet = prompt_UpdateSet; 309b6217683SBrian Somers p->desc.IsSet = prompt_IsSet; 310b6217683SBrian Somers p->desc.Read = prompt_Read; 311b6217683SBrian Somers p->desc.Write = prompt_Write; 31285b542cfSBrian Somers 313b6217683SBrian Somers if (fd == PROMPT_STD) { 3140f78c7a7SBrian Somers char *tty = ttyname(STDIN_FILENO); 3150f78c7a7SBrian Somers 3160f78c7a7SBrian Somers if (!tty) { 3170f78c7a7SBrian Somers free(p); 3180f78c7a7SBrian Somers return NULL; 3190f78c7a7SBrian Somers } 32085b542cfSBrian Somers p->fd_in = STDIN_FILENO; 32185b542cfSBrian Somers p->fd_out = STDOUT_FILENO; 32285b542cfSBrian Somers p->Term = stdout; 323b6217683SBrian Somers p->owner = NULL; 324b6217683SBrian Somers p->auth = LOCAL_AUTH; 325565e35e5SBrian Somers p->src.type = "Controller"; 3260f78c7a7SBrian Somers strncpy(p->src.from, tty, sizeof p->src.from - 1); 327565e35e5SBrian Somers p->src.from[sizeof p->src.from - 1] = '\0'; 328b6217683SBrian Somers tcgetattr(p->fd_in, &p->oldtio); /* Save original tty mode */ 32985b542cfSBrian Somers } else { 33085b542cfSBrian Somers p->fd_in = p->fd_out = fd; 33185b542cfSBrian Somers p->Term = fdopen(fd, "a+"); 332b6217683SBrian Somers p->owner = s; 333b6217683SBrian Somers p->auth = *s->passwd ? LOCAL_NO_AUTH : LOCAL_AUTH; 334565e35e5SBrian Somers p->src.type = "unknown"; 335565e35e5SBrian Somers *p->src.from = '\0'; 33685b542cfSBrian Somers } 3371b35f8f7SBrian Somers p->TermMode = NULL; 338b6217683SBrian Somers p->nonewline = 1; 339b6217683SBrian Somers p->needprompt = 1; 340d93d3a9cSBrian Somers p->readtilde = 0; 341b6217683SBrian Somers p->bundle = bundle; 342b6217683SBrian Somers log_RegisterPrompt(p); 343b6217683SBrian Somers } 34485b542cfSBrian Somers 345b6217683SBrian Somers return p; 34685b542cfSBrian Somers } 34785b542cfSBrian Somers 3483006ec67SBrian Somers void 349b6217683SBrian Somers prompt_Destroy(struct prompt *p, int verbose) 35085b542cfSBrian Somers { 3510f78c7a7SBrian Somers if (p) { 352b6217683SBrian Somers if (p->Term != stdout) { 353b6217683SBrian Somers fclose(p->Term); 35485b542cfSBrian Somers close(p->fd_in); 35585b542cfSBrian Somers if (p->fd_out != p->fd_in) 35685b542cfSBrian Somers close(p->fd_out); 35785b542cfSBrian Somers if (verbose) 3580f2f3eb3SBrian Somers log_Printf(LogPHASE, "%s: Client connection dropped.\n", p->src.from); 359b6217683SBrian Somers } else 360b6217683SBrian Somers prompt_TtyOldMode(p); 361b6217683SBrian Somers 362565e35e5SBrian Somers log_UnRegisterPrompt(p); 363565e35e5SBrian Somers free(p); 36485b542cfSBrian Somers } 3650f78c7a7SBrian Somers } 36685b542cfSBrian Somers 36785b542cfSBrian Somers void 36885b542cfSBrian Somers prompt_Printf(struct prompt *p, const char *fmt,...) 36985b542cfSBrian Somers { 370f91ad6b0SBrian Somers if (p && p->active) { 37185b542cfSBrian Somers va_list ap; 372f7704be7SBrian Somers 37385b542cfSBrian Somers va_start(ap, fmt); 374f7704be7SBrian Somers prompt_vPrintf(p, fmt, ap); 37585b542cfSBrian Somers va_end(ap); 37685b542cfSBrian Somers } 37785b542cfSBrian Somers } 37885b542cfSBrian Somers 37985b542cfSBrian Somers void 38085b542cfSBrian Somers prompt_vPrintf(struct prompt *p, const char *fmt, va_list ap) 38185b542cfSBrian Somers { 382f91ad6b0SBrian Somers if (p && p->active) { 383f7704be7SBrian Somers char nfmt[LINE_LEN]; 384f7704be7SBrian Somers const char *pfmt; 385f7704be7SBrian Somers 386f7704be7SBrian Somers if (p->TermMode) { 387f7704be7SBrian Somers /* Stuff '\r' in front of '\n' 'cos we're in raw mode */ 388f7704be7SBrian Somers int len = strlen(fmt); 389f7704be7SBrian Somers 390e3044845SBrian Somers if (len && len < sizeof nfmt - 1 && fmt[len-1] == '\n' && 391e3044845SBrian Somers (len == 1 || fmt[len-2] != '\r')) { 392f7704be7SBrian Somers strcpy(nfmt, fmt); 393f7704be7SBrian Somers strcpy(nfmt + len - 1, "\r\n"); 394f7704be7SBrian Somers pfmt = nfmt; 395f7704be7SBrian Somers } else 396f7704be7SBrian Somers pfmt = fmt; 397f7704be7SBrian Somers } else 398f7704be7SBrian Somers pfmt = fmt; 399f7704be7SBrian Somers vfprintf(p->Term, pfmt, ap); 40085b542cfSBrian Somers fflush(p->Term); 401c06d604bSBrian Somers p->nonewline = 1; 40285b542cfSBrian Somers } 40385b542cfSBrian Somers } 40485b542cfSBrian Somers 40585b542cfSBrian Somers void 406565e35e5SBrian Somers prompt_TtyInit(struct prompt *p) 40785b542cfSBrian Somers { 408565e35e5SBrian Somers int stat, fd = p ? p->fd_in : STDIN_FILENO; 409b6217683SBrian Somers struct termios newtio; 410b6217683SBrian Somers 411565e35e5SBrian Somers stat = fcntl(fd, F_GETFL, 0); 412565e35e5SBrian Somers if (stat > 0) { 413565e35e5SBrian Somers stat |= O_NONBLOCK; 414565e35e5SBrian Somers fcntl(fd, F_SETFL, stat); 415565e35e5SBrian Somers } 416565e35e5SBrian Somers 417565e35e5SBrian Somers if (p) 41885b542cfSBrian Somers newtio = p->oldtio; 419565e35e5SBrian Somers else 420565e35e5SBrian Somers tcgetattr(fd, &newtio); 421565e35e5SBrian Somers 42285b542cfSBrian Somers newtio.c_lflag &= ~(ECHO | ISIG | ICANON); 42385b542cfSBrian Somers newtio.c_iflag = 0; 42485b542cfSBrian Somers newtio.c_oflag &= ~OPOST; 425565e35e5SBrian Somers if (!p) 42685b542cfSBrian Somers newtio.c_cc[VINTR] = _POSIX_VDISABLE; 42785b542cfSBrian Somers newtio.c_cc[VMIN] = 1; 42885b542cfSBrian Somers newtio.c_cc[VTIME] = 0; 42985b542cfSBrian Somers newtio.c_cflag |= CS8; 430565e35e5SBrian Somers tcsetattr(fd, TCSANOW, &newtio); 431565e35e5SBrian Somers if (p) 43285b542cfSBrian Somers p->comtio = newtio; 43385b542cfSBrian Somers } 43485b542cfSBrian Somers 43585b542cfSBrian Somers /* 43685b542cfSBrian Somers * Set tty into command mode. We allow canonical input and echo processing. 43785b542cfSBrian Somers */ 43885b542cfSBrian Somers void 43985b542cfSBrian Somers prompt_TtyCommandMode(struct prompt *p) 44085b542cfSBrian Somers { 44185b542cfSBrian Somers struct termios newtio; 44285b542cfSBrian Somers int stat; 44385b542cfSBrian Somers 44485b542cfSBrian Somers tcgetattr(p->fd_in, &newtio); 44585b542cfSBrian Somers newtio.c_lflag |= (ECHO | ISIG | ICANON); 44685b542cfSBrian Somers newtio.c_iflag = p->oldtio.c_iflag; 44785b542cfSBrian Somers newtio.c_oflag |= OPOST; 44885b542cfSBrian Somers tcsetattr(p->fd_in, TCSADRAIN, &newtio); 449b6217683SBrian Somers 45085b542cfSBrian Somers stat = fcntl(p->fd_in, F_GETFL, 0); 45185b542cfSBrian Somers if (stat > 0) { 45285b542cfSBrian Somers stat |= O_NONBLOCK; 453b6217683SBrian Somers fcntl(p->fd_in, F_SETFL, stat); 45485b542cfSBrian Somers } 455b6217683SBrian Somers 4561b35f8f7SBrian Somers p->TermMode = NULL; 45785b542cfSBrian Somers } 45885b542cfSBrian Somers 45985b542cfSBrian Somers /* 46085b542cfSBrian Somers * Set tty into terminal mode which is used while we invoke term command. 46185b542cfSBrian Somers */ 46285b542cfSBrian Somers void 4631b35f8f7SBrian Somers prompt_TtyTermMode(struct prompt *p, struct datalink *dl) 46485b542cfSBrian Somers { 46585b542cfSBrian Somers int stat; 46685b542cfSBrian Somers 467b6217683SBrian Somers if (p->Term == stdout) 46885b542cfSBrian Somers tcsetattr(p->fd_in, TCSADRAIN, &p->comtio); 469b6217683SBrian Somers 47085b542cfSBrian Somers stat = fcntl(p->fd_in, F_GETFL, 0); 47185b542cfSBrian Somers if (stat > 0) { 47285b542cfSBrian Somers stat &= ~O_NONBLOCK; 473b6217683SBrian Somers fcntl(p->fd_in, F_SETFL, stat); 47485b542cfSBrian Somers } 4751b35f8f7SBrian Somers p->TermMode = dl; 47685b542cfSBrian Somers } 47785b542cfSBrian Somers 47885b542cfSBrian Somers void 47985b542cfSBrian Somers prompt_TtyOldMode(struct prompt *p) 48085b542cfSBrian Somers { 48185b542cfSBrian Somers int stat; 48285b542cfSBrian Somers 48385b542cfSBrian Somers stat = fcntl(p->fd_in, F_GETFL, 0); 48485b542cfSBrian Somers if (stat > 0) { 48585b542cfSBrian Somers stat &= ~O_NONBLOCK; 486b6217683SBrian Somers fcntl(p->fd_in, F_SETFL, stat); 48785b542cfSBrian Somers } 488b6217683SBrian Somers 489b6217683SBrian Somers if (p->Term == stdout) 49085b542cfSBrian Somers tcsetattr(p->fd_in, TCSADRAIN, &p->oldtio); 49185b542cfSBrian Somers } 49285b542cfSBrian Somers 49385b542cfSBrian Somers pid_t 49485b542cfSBrian Somers prompt_pgrp(struct prompt *p) 49585b542cfSBrian Somers { 496b6217683SBrian Somers return tcgetpgrp(p->fd_in); 497b6217683SBrian Somers } 498b6217683SBrian Somers 499b6217683SBrian Somers int 500b6217683SBrian Somers PasswdCommand(struct cmdargs const *arg) 501b6217683SBrian Somers { 502b6217683SBrian Somers const char *pass; 503b6217683SBrian Somers 504b6217683SBrian Somers if (!arg->prompt) { 505dd7e2610SBrian Somers log_Printf(LogWARN, "passwd: Cannot specify without a prompt\n"); 506b6217683SBrian Somers return 0; 507b6217683SBrian Somers } 508b6217683SBrian Somers 509b6217683SBrian Somers if (arg->prompt->owner == NULL) { 510dd7e2610SBrian Somers log_Printf(LogWARN, "passwd: Not required\n"); 511b6217683SBrian Somers return 0; 512b6217683SBrian Somers } 513b6217683SBrian Somers 51425092092SBrian Somers if (arg->argc == arg->argn) 515b6217683SBrian Somers pass = ""; 51625092092SBrian Somers else if (arg->argc > arg->argn+1) 517b6217683SBrian Somers return -1; 518b6217683SBrian Somers else 51925092092SBrian Somers pass = arg->argv[arg->argn]; 520b6217683SBrian Somers 521b6217683SBrian Somers if (!strcmp(arg->prompt->owner->passwd, pass)) 522b6217683SBrian Somers arg->prompt->auth = LOCAL_AUTH; 523b6217683SBrian Somers else 524b6217683SBrian Somers arg->prompt->auth = LOCAL_NO_AUTH; 525b6217683SBrian Somers 526b6217683SBrian Somers return 0; 52785b542cfSBrian Somers } 528f91ad6b0SBrian Somers 529f91ad6b0SBrian Somers static struct pppTimer bgtimer; 530f91ad6b0SBrian Somers 531f91ad6b0SBrian Somers static void 532f91ad6b0SBrian Somers prompt_TimedContinue(void *v) 533f91ad6b0SBrian Somers { 534f91ad6b0SBrian Somers prompt_Continue((struct prompt *)v); 535f91ad6b0SBrian Somers } 536f91ad6b0SBrian Somers 537f91ad6b0SBrian Somers void 538f91ad6b0SBrian Somers prompt_Continue(struct prompt *p) 539f91ad6b0SBrian Somers { 540dd7e2610SBrian Somers timer_Stop(&bgtimer); 541f91ad6b0SBrian Somers if (getpgrp() == prompt_pgrp(p)) { 542f91ad6b0SBrian Somers prompt_TtyCommandMode(p); 543f91ad6b0SBrian Somers p->nonewline = 1; 544f91ad6b0SBrian Somers prompt_Required(p); 5450f2f3eb3SBrian Somers log_ActivatePrompt(p); 546f91ad6b0SBrian Somers } else if (!p->owner) { 547f91ad6b0SBrian Somers bgtimer.func = prompt_TimedContinue; 548f91ad6b0SBrian Somers bgtimer.name = "prompt bg"; 549f91ad6b0SBrian Somers bgtimer.load = SECTICKS; 550f91ad6b0SBrian Somers bgtimer.arg = p; 551dd7e2610SBrian Somers timer_Start(&bgtimer); 552f91ad6b0SBrian Somers } 553f91ad6b0SBrian Somers } 554f91ad6b0SBrian Somers 555f91ad6b0SBrian Somers void 556f91ad6b0SBrian Somers prompt_Suspend(struct prompt *p) 557f91ad6b0SBrian Somers { 558f91ad6b0SBrian Somers if (getpgrp() == prompt_pgrp(p)) { 559f91ad6b0SBrian Somers prompt_TtyOldMode(p); 5600f2f3eb3SBrian Somers log_DeactivatePrompt(p); 561f91ad6b0SBrian Somers } 562f91ad6b0SBrian Somers } 563