185b542cfSBrian Somers /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 31de7b4b8SPedro F. Giffuni * 485b542cfSBrian Somers * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> 585b542cfSBrian Somers * All rights reserved. 685b542cfSBrian Somers * 785b542cfSBrian Somers * Redistribution and use in source and binary forms, with or without 885b542cfSBrian Somers * modification, are permitted provided that the following conditions 985b542cfSBrian Somers * are met: 1085b542cfSBrian Somers * 1. Redistributions of source code must retain the above copyright 1185b542cfSBrian Somers * notice, this list of conditions and the following disclaimer. 1285b542cfSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright 1385b542cfSBrian Somers * notice, this list of conditions and the following disclaimer in the 1485b542cfSBrian Somers * documentation and/or other materials provided with the distribution. 1585b542cfSBrian Somers * 1685b542cfSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1785b542cfSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1885b542cfSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1985b542cfSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2085b542cfSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2185b542cfSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2285b542cfSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2385b542cfSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2485b542cfSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2585b542cfSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2685b542cfSBrian Somers * SUCH DAMAGE. 2785b542cfSBrian Somers * 2897d92980SPeter Wemm * $FreeBSD$ 2985b542cfSBrian Somers */ 3085b542cfSBrian Somers 3185b542cfSBrian Somers #include <sys/param.h> 3285b542cfSBrian Somers #include <netinet/in.h> 33eaa4df37SBrian Somers #include <netinet/in_systm.h> 34eaa4df37SBrian Somers #include <netinet/ip.h> 3530949fd4SBrian Somers #include <sys/socket.h> 36565e35e5SBrian Somers #include <sys/un.h> 3785b542cfSBrian Somers 38833882f7SBrian Somers #include <errno.h> 3985b542cfSBrian Somers #include <stdarg.h> 4085b542cfSBrian Somers #include <stdio.h> 41b6217683SBrian Somers #include <stdlib.h> 42b6217683SBrian Somers #include <string.h> 4385b542cfSBrian Somers #include <sys/fcntl.h> 4485b542cfSBrian Somers #include <termios.h> 4585b542cfSBrian Somers #include <unistd.h> 4685b542cfSBrian Somers 475d9e6103SBrian Somers #include "layer.h" 4885b542cfSBrian Somers #include "defs.h" 4985b542cfSBrian Somers #include "timer.h" 5085b542cfSBrian Somers #include "command.h" 5185b542cfSBrian Somers #include "log.h" 5285b542cfSBrian Somers #include "descriptor.h" 5385b542cfSBrian Somers #include "prompt.h" 5485b542cfSBrian Somers #include "fsm.h" 5585b542cfSBrian Somers #include "auth.h" 5685b542cfSBrian Somers #include "iplist.h" 5785b542cfSBrian Somers #include "throughput.h" 58eaa4df37SBrian Somers #include "slcompress.h" 595a72b6edSBrian Somers #include "mbuf.h" 60879ed6faSBrian Somers #include "lqr.h" 613006ec67SBrian Somers #include "hdlc.h" 621038894eSBrian Somers #include "lcp.h" 6330949fd4SBrian Somers #include "ncpaddr.h" 645a72b6edSBrian Somers #include "ipcp.h" 655a72b6edSBrian Somers #include "filter.h" 663006ec67SBrian Somers #include "async.h" 673b0f8d2eSBrian Somers #include "ccp.h" 683006ec67SBrian Somers #include "link.h" 693006ec67SBrian Somers #include "physical.h" 703b0f8d2eSBrian Somers #include "mp.h" 71972a1bcfSBrian Somers #ifndef NORADIUS 72972a1bcfSBrian Somers #include "radius.h" 73972a1bcfSBrian Somers #endif 7430949fd4SBrian Somers #include "ipv6cp.h" 7530949fd4SBrian Somers #include "ncp.h" 763b0f8d2eSBrian Somers #include "bundle.h" 77c5a5a6caSBrian Somers #include "chat.h" 78e2ebb036SBrian Somers #include "chap.h" 7992b09558SBrian Somers #include "cbcp.h" 80c5a5a6caSBrian Somers #include "datalink.h" 81b6217683SBrian Somers #include "server.h" 829dae3e8dSBrian Somers #include "main.h" 8385b542cfSBrian Somers 84b6217683SBrian Somers static void 85b6217683SBrian Somers prompt_Display(struct prompt *p) 86b6217683SBrian Somers { 87d93d3a9cSBrian Somers /* XXX: See Index2Nam() - should we only figure this out once ? */ 8826e6a622SBrian Somers static char shostname[MAXHOSTNAMELEN]; 89b6217683SBrian Somers const char *pconnect, *pauth; 90b6217683SBrian Somers 91b6217683SBrian Somers if (p->TermMode || !p->needprompt) 92b6217683SBrian Somers return; 93b6217683SBrian Somers 94b6217683SBrian Somers p->needprompt = 0; 95b6217683SBrian Somers 96b6217683SBrian Somers if (p->nonewline) 97b6217683SBrian Somers p->nonewline = 0; 98b6217683SBrian Somers else 99b6217683SBrian Somers fprintf(p->Term, "\n"); 100b6217683SBrian Somers 101b6217683SBrian Somers if (p->auth == LOCAL_AUTH) 102b6217683SBrian Somers pauth = " ON "; 103b6217683SBrian Somers else 104b6217683SBrian Somers pauth = " on "; 105b6217683SBrian Somers 106b6217683SBrian Somers if (p->bundle->ncp.ipcp.fsm.state == ST_OPENED) 107b6217683SBrian Somers pconnect = "PPP"; 108bbdd2707SHajimu UMEMOTO #ifndef NOINET6 109bbdd2707SHajimu UMEMOTO else if (!Enabled(p->bundle, OPT_IPCP) && 110bbdd2707SHajimu UMEMOTO p->bundle->ncp.ipv6cp.fsm.state == ST_OPENED) 111bbdd2707SHajimu UMEMOTO pconnect = "PPP"; 112bbdd2707SHajimu UMEMOTO #endif 113b6217683SBrian Somers else if (bundle_Phase(p->bundle) == PHASE_NETWORK) 114b6217683SBrian Somers pconnect = "PPp"; 115b6217683SBrian Somers else if (bundle_Phase(p->bundle) == PHASE_AUTHENTICATE) 116b6217683SBrian Somers pconnect = "Ppp"; 117b6217683SBrian Somers else 118b6217683SBrian Somers pconnect = "ppp"; 119b6217683SBrian Somers 120b6217683SBrian Somers if (*shostname == '\0') { 121cdbbb6b5SBrian Somers char *dot; 122b6217683SBrian Somers 12352847614SBrian Somers if (gethostname(shostname, sizeof shostname) || *shostname == '\0') 124b6217683SBrian Somers strcpy(shostname, "localhost"); 125cdbbb6b5SBrian Somers else if ((dot = strchr(shostname, '.'))) 126cdbbb6b5SBrian Somers *dot = '\0'; 127b6217683SBrian Somers } 128b6217683SBrian Somers 129b6217683SBrian Somers fprintf(p->Term, "%s%s%s> ", pconnect, pauth, shostname); 130b6217683SBrian Somers fflush(p->Term); 131b6217683SBrian Somers } 13285b542cfSBrian Somers 13385b542cfSBrian Somers static int 134057f1760SBrian Somers prompt_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w __unused, 135057f1760SBrian Somers fd_set *e, int *n) 13685b542cfSBrian Somers { 13785b542cfSBrian Somers struct prompt *p = descriptor2prompt(d); 138b6dec9f0SBrian Somers int sets; 13985b542cfSBrian Somers 140b6dec9f0SBrian Somers sets = 0; 141f91ad6b0SBrian Somers 142f91ad6b0SBrian Somers if (!p->active) 143f91ad6b0SBrian Somers return sets; 144f91ad6b0SBrian Somers 14585b542cfSBrian Somers if (p->fd_in >= 0) { 146b6dec9f0SBrian Somers if (r) { 14785b542cfSBrian Somers FD_SET(p->fd_in, r); 14824989c68SBrian Somers log_Printf(LogTIMER, "prompt %s: fdset(r) %d\n", p->src.from, p->fd_in); 149b6dec9f0SBrian Somers sets++; 150b6dec9f0SBrian Somers } 151b6dec9f0SBrian Somers if (e) { 15285b542cfSBrian Somers FD_SET(p->fd_in, e); 15324989c68SBrian Somers log_Printf(LogTIMER, "prompt %s: fdset(e) %d\n", p->src.from, p->fd_in); 154b6dec9f0SBrian Somers sets++; 155b6dec9f0SBrian Somers } 156b6dec9f0SBrian Somers if (sets && *n < p->fd_in + 1) 157b6dec9f0SBrian Somers *n = p->fd_in + 1; 15885b542cfSBrian Somers } 15985b542cfSBrian Somers 160b6217683SBrian Somers prompt_Display(p); 161b6217683SBrian Somers 162b6dec9f0SBrian Somers return sets; 16385b542cfSBrian Somers } 16485b542cfSBrian Somers 16585b542cfSBrian Somers static int 166f013f33eSBrian Somers prompt_IsSet(struct fdescriptor *d, const fd_set *fdset) 16785b542cfSBrian Somers { 16885b542cfSBrian Somers struct prompt *p = descriptor2prompt(d); 16985b542cfSBrian Somers return p->fd_in >= 0 && FD_ISSET(p->fd_in, fdset); 17085b542cfSBrian Somers } 17185b542cfSBrian Somers 17285b542cfSBrian Somers 17385b542cfSBrian Somers static void 17485b542cfSBrian Somers prompt_ShowHelp(struct prompt *p) 17585b542cfSBrian Somers { 176f7704be7SBrian Somers prompt_Printf(p, "The following commands are available:\n"); 177f7704be7SBrian Somers prompt_Printf(p, " ~p\tEnter Packet mode\n"); 178f7704be7SBrian Somers prompt_Printf(p, " ~t\tShow timers\n"); 179f7704be7SBrian Somers prompt_Printf(p, " ~m\tShow memory map\n"); 180f7704be7SBrian Somers prompt_Printf(p, " ~.\tTerminate program\n"); 181f7704be7SBrian Somers prompt_Printf(p, " ~?\tThis help\n"); 18285b542cfSBrian Somers } 18385b542cfSBrian Somers 18485b542cfSBrian Somers static void 185057f1760SBrian Somers prompt_Read(struct fdescriptor *d, struct bundle *bundle, 186057f1760SBrian Somers const fd_set *fdset __unused) 18785b542cfSBrian Somers { 18885b542cfSBrian Somers struct prompt *p = descriptor2prompt(d); 189b4f63b0bSBrian Somers struct prompt *op; 19085b542cfSBrian Somers int n; 19185b542cfSBrian Somers char ch; 19285b542cfSBrian Somers char linebuff[LINE_LEN]; 19385b542cfSBrian Somers 1941b35f8f7SBrian Somers if (p->TermMode == NULL) { 19585b542cfSBrian Somers n = read(p->fd_in, linebuff, sizeof linebuff - 1); 19685b542cfSBrian Somers if (n > 0) { 19785b542cfSBrian Somers if (linebuff[n-1] == '\n') 19885b542cfSBrian Somers linebuff[--n] = '\0'; 19985b542cfSBrian Somers else 20085b542cfSBrian Somers linebuff[n] = '\0'; 201dd7e2610SBrian Somers p->nonewline = 1; /* Maybe command_Decode does a prompt */ 202b6217683SBrian Somers prompt_Required(p); 203b4f63b0bSBrian Somers if (n) { 204b4f63b0bSBrian Somers if ((op = log_PromptContext) == NULL) 205b4f63b0bSBrian Somers log_PromptContext = p; 206c39aa54eSBrian Somers if (!command_Decode(bundle, linebuff, n, p, p->src.from)) 207c39aa54eSBrian Somers prompt_Printf(p, "Syntax error\n"); 208b4f63b0bSBrian Somers log_PromptContext = op; 209b4f63b0bSBrian Somers } 21085b542cfSBrian Somers } else if (n <= 0) { 2110f2f3eb3SBrian Somers log_Printf(LogPHASE, "%s: Client connection closed.\n", p->src.from); 2129dae3e8dSBrian Somers if (!p->owner) 213057f1760SBrian Somers Cleanup(); 214b6217683SBrian Somers prompt_Destroy(p, 0); 21585b542cfSBrian Somers } 21685b542cfSBrian Somers return; 21785b542cfSBrian Somers } 21885b542cfSBrian Somers 219c7cc5030SBrian Somers switch (p->TermMode->state) { 220c7cc5030SBrian Somers case DATALINK_CLOSED: 221c7cc5030SBrian Somers prompt_Printf(p, "Link lost, terminal mode.\n"); 222b6217683SBrian Somers prompt_TtyCommandMode(p); 223b6217683SBrian Somers p->nonewline = 0; 224b6217683SBrian Somers prompt_Required(p); 225c7cc5030SBrian Somers return; 226c7cc5030SBrian Somers 227c7cc5030SBrian Somers case DATALINK_READY: 228c7cc5030SBrian Somers break; 229c7cc5030SBrian Somers 230c7cc5030SBrian Somers case DATALINK_OPEN: 231c7cc5030SBrian Somers prompt_Printf(p, "\nPacket mode detected.\n"); 232b6217683SBrian Somers prompt_TtyCommandMode(p); 233b6217683SBrian Somers p->nonewline = 0; 234c7cc5030SBrian Somers /* We'll get a prompt because of our status change */ 235f0067240SPhilippe Charnier /* FALLTHROUGH */ 236c7cc5030SBrian Somers 237c7cc5030SBrian Somers default: 238c7cc5030SBrian Somers /* Wait 'till we're in a state we care about */ 239c7cc5030SBrian Somers return; 240c7cc5030SBrian Somers } 241c7cc5030SBrian Somers 24285b542cfSBrian Somers /* 24385b542cfSBrian Somers * We are in terminal mode, decode special sequences 24485b542cfSBrian Somers */ 24585b542cfSBrian Somers n = read(p->fd_in, &ch, 1); 246dd7e2610SBrian Somers log_Printf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n); 24785b542cfSBrian Somers 24885b542cfSBrian Somers if (n > 0) { 249d93d3a9cSBrian Somers switch (p->readtilde) { 25085b542cfSBrian Somers case 0: 25185b542cfSBrian Somers if (ch == '~') 252d93d3a9cSBrian Somers p->readtilde = 1; 25385b542cfSBrian Somers else 254dd7e2610SBrian Somers if (physical_Write(p->TermMode->physical, &ch, n) < 0) { 255a33b2ef7SBrian Somers log_Printf(LogWARN, "error writing to modem: %s\n", strerror(errno)); 256833882f7SBrian Somers prompt_TtyCommandMode(p); 257833882f7SBrian Somers } 25885b542cfSBrian Somers break; 25985b542cfSBrian Somers case 1: 26085b542cfSBrian Somers switch (ch) { 26185b542cfSBrian Somers case '?': 26285b542cfSBrian Somers prompt_ShowHelp(p); 26385b542cfSBrian Somers break; 26485b542cfSBrian Somers case 'p': 265c7cc5030SBrian Somers datalink_Up(p->TermMode, 0, 1); 266c7cc5030SBrian Somers prompt_Printf(p, "\nPacket mode.\n"); 267b6217683SBrian Somers prompt_TtyCommandMode(p); 26885b542cfSBrian Somers break; 26985b542cfSBrian Somers case '.': 270b6217683SBrian Somers prompt_TtyCommandMode(p); 271b6217683SBrian Somers p->nonewline = 0; 272b6217683SBrian Somers prompt_Required(p); 27385b542cfSBrian Somers break; 27485b542cfSBrian Somers case 't': 275dd7e2610SBrian Somers timer_Show(0, p); 27685b542cfSBrian Somers break; 27785b542cfSBrian Somers case 'm': 278f7704be7SBrian Somers { 279f7704be7SBrian Somers struct cmdargs arg; 280f7704be7SBrian Somers 281f7704be7SBrian Somers arg.cmdtab = NULL; 282f7704be7SBrian Somers arg.cmd = NULL; 283f7704be7SBrian Somers arg.argc = 0; 284f7704be7SBrian Somers arg.argn = 0; 285f7704be7SBrian Somers arg.argv = NULL; 286f7704be7SBrian Somers arg.bundle = bundle; 287f7704be7SBrian Somers arg.cx = p->TermMode; 288f7704be7SBrian Somers arg.prompt = p; 289f7704be7SBrian Somers 290f7704be7SBrian Somers mbuf_Show(&arg); 291f7704be7SBrian Somers } 29285b542cfSBrian Somers break; 29385b542cfSBrian Somers default: 294dd7e2610SBrian Somers if (physical_Write(p->TermMode->physical, &ch, n) < 0) { 295a33b2ef7SBrian Somers log_Printf(LogWARN, "error writing to modem: %s\n", strerror(errno)); 296833882f7SBrian Somers prompt_TtyCommandMode(p); 297833882f7SBrian Somers } 29885b542cfSBrian Somers break; 29985b542cfSBrian Somers } 300d93d3a9cSBrian Somers p->readtilde = 0; 30185b542cfSBrian Somers break; 30285b542cfSBrian Somers } 30385b542cfSBrian Somers } 30485b542cfSBrian Somers } 30585b542cfSBrian Somers 3061af29a6eSBrian Somers static int 307057f1760SBrian Somers prompt_Write(struct fdescriptor *d __unused, struct bundle *bundle __unused, 308057f1760SBrian Somers const fd_set *fdset __unused) 30985b542cfSBrian Somers { 310f4768038SBrian Somers /* We never want to write here ! */ 311a33b2ef7SBrian Somers log_Printf(LogALERT, "prompt_Write: Internal error: Bad call !\n"); 3121af29a6eSBrian Somers return 0; 31385b542cfSBrian Somers } 31485b542cfSBrian Somers 315b6217683SBrian Somers struct prompt * 316b6217683SBrian Somers prompt_Create(struct server *s, struct bundle *bundle, int fd) 31785b542cfSBrian Somers { 318b6217683SBrian Somers struct prompt *p = (struct prompt *)malloc(sizeof(struct prompt)); 31985b542cfSBrian Somers 320b6217683SBrian Somers if (p != NULL) { 321b6217683SBrian Somers p->desc.type = PROMPT_DESCRIPTOR; 322b6217683SBrian Somers p->desc.UpdateSet = prompt_UpdateSet; 323b6217683SBrian Somers p->desc.IsSet = prompt_IsSet; 324b6217683SBrian Somers p->desc.Read = prompt_Read; 325b6217683SBrian Somers p->desc.Write = prompt_Write; 32685b542cfSBrian Somers 327b6217683SBrian Somers if (fd == PROMPT_STD) { 3280f78c7a7SBrian Somers char *tty = ttyname(STDIN_FILENO); 3290f78c7a7SBrian Somers 3300f78c7a7SBrian Somers if (!tty) { 3310f78c7a7SBrian Somers free(p); 3320f78c7a7SBrian Somers return NULL; 3330f78c7a7SBrian Somers } 33485b542cfSBrian Somers p->fd_in = STDIN_FILENO; 33585b542cfSBrian Somers p->fd_out = STDOUT_FILENO; 33685b542cfSBrian Somers p->Term = stdout; 337b6217683SBrian Somers p->owner = NULL; 338b6217683SBrian Somers p->auth = LOCAL_AUTH; 339565e35e5SBrian Somers p->src.type = "Controller"; 3400f78c7a7SBrian Somers strncpy(p->src.from, tty, sizeof p->src.from - 1); 341565e35e5SBrian Somers p->src.from[sizeof p->src.from - 1] = '\0'; 342b6217683SBrian Somers tcgetattr(p->fd_in, &p->oldtio); /* Save original tty mode */ 34385b542cfSBrian Somers } else { 34485b542cfSBrian Somers p->fd_in = p->fd_out = fd; 34585b542cfSBrian Somers p->Term = fdopen(fd, "a+"); 346b6217683SBrian Somers p->owner = s; 34774457d3dSBrian Somers p->auth = *s->cfg.passwd ? LOCAL_NO_AUTH : LOCAL_AUTH; 348565e35e5SBrian Somers p->src.type = "unknown"; 349565e35e5SBrian Somers *p->src.from = '\0'; 35085b542cfSBrian Somers } 3511b35f8f7SBrian Somers p->TermMode = NULL; 352b6217683SBrian Somers p->nonewline = 1; 353b6217683SBrian Somers p->needprompt = 1; 354d93d3a9cSBrian Somers p->readtilde = 0; 355b6217683SBrian Somers p->bundle = bundle; 356b6217683SBrian Somers log_RegisterPrompt(p); 357b6217683SBrian Somers } 35885b542cfSBrian Somers 359b6217683SBrian Somers return p; 36085b542cfSBrian Somers } 36185b542cfSBrian Somers 3623006ec67SBrian Somers void 363b6217683SBrian Somers prompt_Destroy(struct prompt *p, int verbose) 36485b542cfSBrian Somers { 3650f78c7a7SBrian Somers if (p) { 366b6217683SBrian Somers if (p->Term != stdout) { 367b6217683SBrian Somers fclose(p->Term); 36885b542cfSBrian Somers close(p->fd_in); 36985b542cfSBrian Somers if (p->fd_out != p->fd_in) 37085b542cfSBrian Somers close(p->fd_out); 37185b542cfSBrian Somers if (verbose) 3720f2f3eb3SBrian Somers log_Printf(LogPHASE, "%s: Client connection dropped.\n", p->src.from); 373b6217683SBrian Somers } else 374b6217683SBrian Somers prompt_TtyOldMode(p); 375b6217683SBrian Somers 376565e35e5SBrian Somers log_UnRegisterPrompt(p); 377565e35e5SBrian Somers free(p); 37885b542cfSBrian Somers } 3790f78c7a7SBrian Somers } 38085b542cfSBrian Somers 38185b542cfSBrian Somers void 38285b542cfSBrian Somers prompt_Printf(struct prompt *p, const char *fmt,...) 38385b542cfSBrian Somers { 384f91ad6b0SBrian Somers if (p && p->active) { 38585b542cfSBrian Somers va_list ap; 386f7704be7SBrian Somers 38785b542cfSBrian Somers va_start(ap, fmt); 388f7704be7SBrian Somers prompt_vPrintf(p, fmt, ap); 38985b542cfSBrian Somers va_end(ap); 39085b542cfSBrian Somers } 39185b542cfSBrian Somers } 39285b542cfSBrian Somers 39385b542cfSBrian Somers void 39485b542cfSBrian Somers prompt_vPrintf(struct prompt *p, const char *fmt, va_list ap) 39585b542cfSBrian Somers { 396f91ad6b0SBrian Somers if (p && p->active) { 397f7704be7SBrian Somers char nfmt[LINE_LEN]; 398f7704be7SBrian Somers const char *pfmt; 399f7704be7SBrian Somers 400f7704be7SBrian Somers if (p->TermMode) { 401f7704be7SBrian Somers /* Stuff '\r' in front of '\n' 'cos we're in raw mode */ 402057f1760SBrian Somers size_t len = strlen(fmt); 403f7704be7SBrian Somers 404e3044845SBrian Somers if (len && len < sizeof nfmt - 1 && fmt[len-1] == '\n' && 405e3044845SBrian Somers (len == 1 || fmt[len-2] != '\r')) { 406f7704be7SBrian Somers strcpy(nfmt, fmt); 407f7704be7SBrian Somers strcpy(nfmt + len - 1, "\r\n"); 408f7704be7SBrian Somers pfmt = nfmt; 409f7704be7SBrian Somers } else 410f7704be7SBrian Somers pfmt = fmt; 411f7704be7SBrian Somers } else 412f7704be7SBrian Somers pfmt = fmt; 413f7704be7SBrian Somers vfprintf(p->Term, pfmt, ap); 41485b542cfSBrian Somers fflush(p->Term); 415c06d604bSBrian Somers p->nonewline = 1; 41685b542cfSBrian Somers } 41785b542cfSBrian Somers } 41885b542cfSBrian Somers 41985b542cfSBrian Somers void 420565e35e5SBrian Somers prompt_TtyInit(struct prompt *p) 42185b542cfSBrian Somers { 422565e35e5SBrian Somers int stat, fd = p ? p->fd_in : STDIN_FILENO; 423b6217683SBrian Somers struct termios newtio; 424b6217683SBrian Somers 425565e35e5SBrian Somers stat = fcntl(fd, F_GETFL, 0); 426565e35e5SBrian Somers if (stat > 0) { 427565e35e5SBrian Somers stat |= O_NONBLOCK; 428565e35e5SBrian Somers fcntl(fd, F_SETFL, stat); 429565e35e5SBrian Somers } 430565e35e5SBrian Somers 431565e35e5SBrian Somers if (p) 43285b542cfSBrian Somers newtio = p->oldtio; 433565e35e5SBrian Somers else 434565e35e5SBrian Somers tcgetattr(fd, &newtio); 435565e35e5SBrian Somers 43685b542cfSBrian Somers newtio.c_lflag &= ~(ECHO | ISIG | ICANON); 43785b542cfSBrian Somers newtio.c_iflag = 0; 43885b542cfSBrian Somers newtio.c_oflag &= ~OPOST; 439565e35e5SBrian Somers if (!p) 44085b542cfSBrian Somers newtio.c_cc[VINTR] = _POSIX_VDISABLE; 44185b542cfSBrian Somers newtio.c_cc[VMIN] = 1; 44285b542cfSBrian Somers newtio.c_cc[VTIME] = 0; 44385b542cfSBrian Somers newtio.c_cflag |= CS8; 444565e35e5SBrian Somers tcsetattr(fd, TCSANOW, &newtio); 445565e35e5SBrian Somers if (p) 44685b542cfSBrian Somers p->comtio = newtio; 44785b542cfSBrian Somers } 44885b542cfSBrian Somers 44985b542cfSBrian Somers /* 45085b542cfSBrian Somers * Set tty into command mode. We allow canonical input and echo processing. 45185b542cfSBrian Somers */ 45285b542cfSBrian Somers void 45385b542cfSBrian Somers prompt_TtyCommandMode(struct prompt *p) 45485b542cfSBrian Somers { 45585b542cfSBrian Somers struct termios newtio; 45685b542cfSBrian Somers int stat; 45785b542cfSBrian Somers 45885b542cfSBrian Somers tcgetattr(p->fd_in, &newtio); 45985b542cfSBrian Somers newtio.c_lflag |= (ECHO | ISIG | ICANON); 46085b542cfSBrian Somers newtio.c_iflag = p->oldtio.c_iflag; 46185b542cfSBrian Somers newtio.c_oflag |= OPOST; 46285b542cfSBrian Somers tcsetattr(p->fd_in, TCSADRAIN, &newtio); 463b6217683SBrian Somers 46485b542cfSBrian Somers stat = fcntl(p->fd_in, F_GETFL, 0); 46585b542cfSBrian Somers if (stat > 0) { 46685b542cfSBrian Somers stat |= O_NONBLOCK; 467b6217683SBrian Somers fcntl(p->fd_in, F_SETFL, stat); 46885b542cfSBrian Somers } 469b6217683SBrian Somers 4701b35f8f7SBrian Somers p->TermMode = NULL; 47185b542cfSBrian Somers } 47285b542cfSBrian Somers 47385b542cfSBrian Somers /* 47485b542cfSBrian Somers * Set tty into terminal mode which is used while we invoke term command. 47585b542cfSBrian Somers */ 47685b542cfSBrian Somers void 4771b35f8f7SBrian Somers prompt_TtyTermMode(struct prompt *p, struct datalink *dl) 47885b542cfSBrian Somers { 47985b542cfSBrian Somers int stat; 48085b542cfSBrian Somers 481b6217683SBrian Somers if (p->Term == stdout) 48285b542cfSBrian Somers tcsetattr(p->fd_in, TCSADRAIN, &p->comtio); 483b6217683SBrian Somers 48485b542cfSBrian Somers stat = fcntl(p->fd_in, F_GETFL, 0); 48585b542cfSBrian Somers if (stat > 0) { 48685b542cfSBrian Somers stat &= ~O_NONBLOCK; 487b6217683SBrian Somers fcntl(p->fd_in, F_SETFL, stat); 48885b542cfSBrian Somers } 4891b35f8f7SBrian Somers p->TermMode = dl; 49085b542cfSBrian Somers } 49185b542cfSBrian Somers 49285b542cfSBrian Somers void 49385b542cfSBrian Somers prompt_TtyOldMode(struct prompt *p) 49485b542cfSBrian Somers { 49585b542cfSBrian Somers int stat; 49685b542cfSBrian Somers 49785b542cfSBrian Somers stat = fcntl(p->fd_in, F_GETFL, 0); 49885b542cfSBrian Somers if (stat > 0) { 49985b542cfSBrian Somers stat &= ~O_NONBLOCK; 500b6217683SBrian Somers fcntl(p->fd_in, F_SETFL, stat); 50185b542cfSBrian Somers } 502b6217683SBrian Somers 503b6217683SBrian Somers if (p->Term == stdout) 50485b542cfSBrian Somers tcsetattr(p->fd_in, TCSADRAIN, &p->oldtio); 50585b542cfSBrian Somers } 50685b542cfSBrian Somers 50785b542cfSBrian Somers pid_t 50885b542cfSBrian Somers prompt_pgrp(struct prompt *p) 50985b542cfSBrian Somers { 510b6217683SBrian Somers return tcgetpgrp(p->fd_in); 511b6217683SBrian Somers } 512b6217683SBrian Somers 513b6217683SBrian Somers int 514b6217683SBrian Somers PasswdCommand(struct cmdargs const *arg) 515b6217683SBrian Somers { 516b6217683SBrian Somers const char *pass; 517b6217683SBrian Somers 518b6217683SBrian Somers if (!arg->prompt) { 519dd7e2610SBrian Somers log_Printf(LogWARN, "passwd: Cannot specify without a prompt\n"); 520b6217683SBrian Somers return 0; 521b6217683SBrian Somers } 522b6217683SBrian Somers 523b6217683SBrian Somers if (arg->prompt->owner == NULL) { 524dd7e2610SBrian Somers log_Printf(LogWARN, "passwd: Not required\n"); 525b6217683SBrian Somers return 0; 526b6217683SBrian Somers } 527b6217683SBrian Somers 52825092092SBrian Somers if (arg->argc == arg->argn) 529b6217683SBrian Somers pass = ""; 53025092092SBrian Somers else if (arg->argc > arg->argn+1) 531b6217683SBrian Somers return -1; 532b6217683SBrian Somers else 53325092092SBrian Somers pass = arg->argv[arg->argn]; 534b6217683SBrian Somers 53574457d3dSBrian Somers if (!strcmp(arg->prompt->owner->cfg.passwd, pass)) 536b6217683SBrian Somers arg->prompt->auth = LOCAL_AUTH; 537b6217683SBrian Somers else 538b6217683SBrian Somers arg->prompt->auth = LOCAL_NO_AUTH; 539b6217683SBrian Somers 540b6217683SBrian Somers return 0; 54185b542cfSBrian Somers } 542f91ad6b0SBrian Somers 543f91ad6b0SBrian Somers static struct pppTimer bgtimer; 544f91ad6b0SBrian Somers 545f91ad6b0SBrian Somers static void 546f91ad6b0SBrian Somers prompt_TimedContinue(void *v) 547f91ad6b0SBrian Somers { 548f91ad6b0SBrian Somers prompt_Continue((struct prompt *)v); 549f91ad6b0SBrian Somers } 550f91ad6b0SBrian Somers 551f91ad6b0SBrian Somers void 552f91ad6b0SBrian Somers prompt_Continue(struct prompt *p) 553f91ad6b0SBrian Somers { 554dd7e2610SBrian Somers timer_Stop(&bgtimer); 555f91ad6b0SBrian Somers if (getpgrp() == prompt_pgrp(p)) { 556f91ad6b0SBrian Somers prompt_TtyCommandMode(p); 557f91ad6b0SBrian Somers p->nonewline = 1; 558f91ad6b0SBrian Somers prompt_Required(p); 5590f2f3eb3SBrian Somers log_ActivatePrompt(p); 560f91ad6b0SBrian Somers } else if (!p->owner) { 561f91ad6b0SBrian Somers bgtimer.func = prompt_TimedContinue; 562f91ad6b0SBrian Somers bgtimer.name = "prompt bg"; 563f91ad6b0SBrian Somers bgtimer.load = SECTICKS; 564f91ad6b0SBrian Somers bgtimer.arg = p; 565dd7e2610SBrian Somers timer_Start(&bgtimer); 566f91ad6b0SBrian Somers } 567f91ad6b0SBrian Somers } 568f91ad6b0SBrian Somers 569f91ad6b0SBrian Somers void 570f91ad6b0SBrian Somers prompt_Suspend(struct prompt *p) 571f91ad6b0SBrian Somers { 572f91ad6b0SBrian Somers if (getpgrp() == prompt_pgrp(p)) { 573f91ad6b0SBrian Somers prompt_TtyOldMode(p); 5740f2f3eb3SBrian Somers log_DeactivatePrompt(p); 575f91ad6b0SBrian Somers } 576f91ad6b0SBrian Somers } 577