136285Sbrian/*- 236285Sbrian * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> 336285Sbrian * All rights reserved. 436285Sbrian * 536285Sbrian * Redistribution and use in source and binary forms, with or without 636285Sbrian * modification, are permitted provided that the following conditions 736285Sbrian * are met: 836285Sbrian * 1. Redistributions of source code must retain the above copyright 936285Sbrian * notice, this list of conditions and the following disclaimer. 1036285Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1136285Sbrian * notice, this list of conditions and the following disclaimer in the 1236285Sbrian * documentation and/or other materials provided with the distribution. 1336285Sbrian * 1436285Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1536285Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1636285Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1736285Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1836285Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1936285Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2036285Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2136285Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2236285Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2336285Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2436285Sbrian * SUCH DAMAGE. 2536285Sbrian * 2650479Speter * $FreeBSD$ 2736285Sbrian */ 2836285Sbrian 2936285Sbrian#include <sys/param.h> 3036285Sbrian#include <netinet/in.h> 3136285Sbrian#include <netinet/in_systm.h> 3236285Sbrian#include <netinet/ip.h> 3381634Sbrian#include <sys/socket.h> 3436285Sbrian#include <sys/un.h> 3536285Sbrian 3636285Sbrian#include <errno.h> 3736285Sbrian#include <stdarg.h> 3836285Sbrian#include <stdio.h> 3936285Sbrian#include <stdlib.h> 4036285Sbrian#include <string.h> 4136285Sbrian#include <sys/fcntl.h> 4236285Sbrian#include <termios.h> 4336285Sbrian#include <unistd.h> 4436285Sbrian 4546686Sbrian#include "layer.h" 4636285Sbrian#include "defs.h" 4736285Sbrian#include "timer.h" 4836285Sbrian#include "command.h" 4936285Sbrian#include "log.h" 5036285Sbrian#include "descriptor.h" 5136285Sbrian#include "prompt.h" 5236285Sbrian#include "fsm.h" 5336285Sbrian#include "auth.h" 5436285Sbrian#include "iplist.h" 5536285Sbrian#include "throughput.h" 5636285Sbrian#include "slcompress.h" 5738557Sbrian#include "mbuf.h" 5838557Sbrian#include "lqr.h" 5938557Sbrian#include "hdlc.h" 6063484Sbrian#include "lcp.h" 6181634Sbrian#include "ncpaddr.h" 6236285Sbrian#include "ipcp.h" 6336285Sbrian#include "filter.h" 6436285Sbrian#include "async.h" 6536285Sbrian#include "ccp.h" 6636285Sbrian#include "link.h" 6736285Sbrian#include "physical.h" 6836285Sbrian#include "mp.h" 6943313Sbrian#ifndef NORADIUS 7043313Sbrian#include "radius.h" 7143313Sbrian#endif 7281634Sbrian#include "ipv6cp.h" 7381634Sbrian#include "ncp.h" 7436285Sbrian#include "bundle.h" 7536285Sbrian#include "chat.h" 7636285Sbrian#include "chap.h" 7738174Sbrian#include "cbcp.h" 7836285Sbrian#include "datalink.h" 7936285Sbrian#include "server.h" 8037386Sbrian#include "main.h" 8136285Sbrian 8236285Sbrianstatic void 8336285Sbrianprompt_Display(struct prompt *p) 8436285Sbrian{ 8537010Sbrian /* XXX: See Index2Nam() - should we only figure this out once ? */ 8674049Sbrian static char shostname[MAXHOSTNAMELEN]; 8736285Sbrian const char *pconnect, *pauth; 8836285Sbrian 8936285Sbrian if (p->TermMode || !p->needprompt) 9036285Sbrian return; 9136285Sbrian 9236285Sbrian p->needprompt = 0; 9336285Sbrian 9436285Sbrian if (p->nonewline) 9536285Sbrian p->nonewline = 0; 9636285Sbrian else 9736285Sbrian fprintf(p->Term, "\n"); 9836285Sbrian 9936285Sbrian if (p->auth == LOCAL_AUTH) 10036285Sbrian pauth = " ON "; 10136285Sbrian else 10236285Sbrian pauth = " on "; 10336285Sbrian 10436285Sbrian if (p->bundle->ncp.ipcp.fsm.state == ST_OPENED) 10536285Sbrian pconnect = "PPP"; 106112753Sume#ifndef NOINET6 107112753Sume else if (!Enabled(p->bundle, OPT_IPCP) && 108112753Sume p->bundle->ncp.ipv6cp.fsm.state == ST_OPENED) 109112753Sume pconnect = "PPP"; 110112753Sume#endif 11136285Sbrian else if (bundle_Phase(p->bundle) == PHASE_NETWORK) 11236285Sbrian pconnect = "PPp"; 11336285Sbrian else if (bundle_Phase(p->bundle) == PHASE_AUTHENTICATE) 11436285Sbrian pconnect = "Ppp"; 11536285Sbrian else 11636285Sbrian pconnect = "ppp"; 11736285Sbrian 11836285Sbrian if (*shostname == '\0') { 11936285Sbrian char *dot; 12036285Sbrian 12174001Sbrian if (gethostname(shostname, sizeof shostname) || *shostname == '\0') 12236285Sbrian strcpy(shostname, "localhost"); 12336285Sbrian else if ((dot = strchr(shostname, '.'))) 12436285Sbrian *dot = '\0'; 12536285Sbrian } 12636285Sbrian 12736285Sbrian fprintf(p->Term, "%s%s%s> ", pconnect, pauth, shostname); 12836285Sbrian fflush(p->Term); 12936285Sbrian} 13036285Sbrian 13136285Sbrianstatic int 132134789Sbrianprompt_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w __unused, 133134789Sbrian fd_set *e, int *n) 13436285Sbrian{ 13536285Sbrian struct prompt *p = descriptor2prompt(d); 13636285Sbrian int sets; 13736285Sbrian 13836285Sbrian sets = 0; 13936285Sbrian 14036285Sbrian if (!p->active) 14136285Sbrian return sets; 14236285Sbrian 14336285Sbrian if (p->fd_in >= 0) { 14436285Sbrian if (r) { 14536285Sbrian FD_SET(p->fd_in, r); 14636285Sbrian log_Printf(LogTIMER, "prompt %s: fdset(r) %d\n", p->src.from, p->fd_in); 14736285Sbrian sets++; 14836285Sbrian } 14936285Sbrian if (e) { 15036285Sbrian FD_SET(p->fd_in, e); 15136285Sbrian log_Printf(LogTIMER, "prompt %s: fdset(e) %d\n", p->src.from, p->fd_in); 15236285Sbrian sets++; 15336285Sbrian } 15436285Sbrian if (sets && *n < p->fd_in + 1) 15536285Sbrian *n = p->fd_in + 1; 15636285Sbrian } 15736285Sbrian 15836285Sbrian prompt_Display(p); 15936285Sbrian 16036285Sbrian return sets; 16136285Sbrian} 16236285Sbrian 16336285Sbrianstatic int 16458028Sbrianprompt_IsSet(struct fdescriptor *d, const fd_set *fdset) 16536285Sbrian{ 16636285Sbrian struct prompt *p = descriptor2prompt(d); 16736285Sbrian return p->fd_in >= 0 && FD_ISSET(p->fd_in, fdset); 16836285Sbrian} 16936285Sbrian 17036285Sbrian 17136285Sbrianstatic void 17236285Sbrianprompt_ShowHelp(struct prompt *p) 17336285Sbrian{ 17437011Sbrian prompt_Printf(p, "The following commands are available:\n"); 17537011Sbrian prompt_Printf(p, " ~p\tEnter Packet mode\n"); 17637011Sbrian prompt_Printf(p, " ~t\tShow timers\n"); 17737011Sbrian prompt_Printf(p, " ~m\tShow memory map\n"); 17837011Sbrian prompt_Printf(p, " ~.\tTerminate program\n"); 17937011Sbrian prompt_Printf(p, " ~?\tThis help\n"); 18036285Sbrian} 18136285Sbrian 18236285Sbrianstatic void 183134789Sbrianprompt_Read(struct fdescriptor *d, struct bundle *bundle, 184134789Sbrian const fd_set *fdset __unused) 18536285Sbrian{ 18636285Sbrian struct prompt *p = descriptor2prompt(d); 18751005Sbrian struct prompt *op; 18836285Sbrian int n; 18936285Sbrian char ch; 19036285Sbrian char linebuff[LINE_LEN]; 19136285Sbrian 19236285Sbrian if (p->TermMode == NULL) { 19336285Sbrian n = read(p->fd_in, linebuff, sizeof linebuff - 1); 19436285Sbrian if (n > 0) { 19536285Sbrian if (linebuff[n-1] == '\n') 19636285Sbrian linebuff[--n] = '\0'; 19736285Sbrian else 19836285Sbrian linebuff[n] = '\0'; 19936285Sbrian p->nonewline = 1; /* Maybe command_Decode does a prompt */ 20036285Sbrian prompt_Required(p); 20151005Sbrian if (n) { 20251005Sbrian if ((op = log_PromptContext) == NULL) 20351005Sbrian log_PromptContext = p; 20454914Sbrian if (!command_Decode(bundle, linebuff, n, p, p->src.from)) 20554914Sbrian prompt_Printf(p, "Syntax error\n"); 20651005Sbrian log_PromptContext = op; 20751005Sbrian } 20836285Sbrian } else if (n <= 0) { 20936314Sbrian log_Printf(LogPHASE, "%s: Client connection closed.\n", p->src.from); 21037386Sbrian if (!p->owner) 211134789Sbrian Cleanup(); 21236285Sbrian prompt_Destroy(p, 0); 21336285Sbrian } 21436285Sbrian return; 21536285Sbrian } 21636285Sbrian 21736285Sbrian switch (p->TermMode->state) { 21836285Sbrian case DATALINK_CLOSED: 21936285Sbrian prompt_Printf(p, "Link lost, terminal mode.\n"); 22036285Sbrian prompt_TtyCommandMode(p); 22136285Sbrian p->nonewline = 0; 22236285Sbrian prompt_Required(p); 22336285Sbrian return; 22436285Sbrian 22536285Sbrian case DATALINK_READY: 22636285Sbrian break; 22736285Sbrian 22836285Sbrian case DATALINK_OPEN: 22936285Sbrian prompt_Printf(p, "\nPacket mode detected.\n"); 23036285Sbrian prompt_TtyCommandMode(p); 23136285Sbrian p->nonewline = 0; 23236285Sbrian /* We'll get a prompt because of our status change */ 233102413Scharnier /* FALLTHROUGH */ 23436285Sbrian 23536285Sbrian default: 23636285Sbrian /* Wait 'till we're in a state we care about */ 23736285Sbrian return; 23836285Sbrian } 23936285Sbrian 24036285Sbrian /* 24136285Sbrian * We are in terminal mode, decode special sequences 24236285Sbrian */ 24336285Sbrian n = read(p->fd_in, &ch, 1); 24436285Sbrian log_Printf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n); 24536285Sbrian 24636285Sbrian if (n > 0) { 24737010Sbrian switch (p->readtilde) { 24836285Sbrian case 0: 24936285Sbrian if (ch == '~') 25037010Sbrian p->readtilde = 1; 25136285Sbrian else 25236285Sbrian if (physical_Write(p->TermMode->physical, &ch, n) < 0) { 25337019Sbrian log_Printf(LogWARN, "error writing to modem: %s\n", strerror(errno)); 25436285Sbrian prompt_TtyCommandMode(p); 25536285Sbrian } 25636285Sbrian break; 25736285Sbrian case 1: 25836285Sbrian switch (ch) { 25936285Sbrian case '?': 26036285Sbrian prompt_ShowHelp(p); 26136285Sbrian break; 26236285Sbrian case 'p': 26336285Sbrian datalink_Up(p->TermMode, 0, 1); 26436285Sbrian prompt_Printf(p, "\nPacket mode.\n"); 26536285Sbrian prompt_TtyCommandMode(p); 26636285Sbrian break; 26736285Sbrian case '.': 26836285Sbrian prompt_TtyCommandMode(p); 26936285Sbrian p->nonewline = 0; 27036285Sbrian prompt_Required(p); 27136285Sbrian break; 27236285Sbrian case 't': 27336285Sbrian timer_Show(0, p); 27436285Sbrian break; 27536285Sbrian case 'm': 27637011Sbrian { 27737011Sbrian struct cmdargs arg; 27837011Sbrian 27937011Sbrian arg.cmdtab = NULL; 28037011Sbrian arg.cmd = NULL; 28137011Sbrian arg.argc = 0; 28237011Sbrian arg.argn = 0; 28337011Sbrian arg.argv = NULL; 28437011Sbrian arg.bundle = bundle; 28537011Sbrian arg.cx = p->TermMode; 28637011Sbrian arg.prompt = p; 28798243Sbrian 28837011Sbrian mbuf_Show(&arg); 28937011Sbrian } 29036285Sbrian break; 29136285Sbrian default: 29236285Sbrian if (physical_Write(p->TermMode->physical, &ch, n) < 0) { 29337019Sbrian log_Printf(LogWARN, "error writing to modem: %s\n", strerror(errno)); 29436285Sbrian prompt_TtyCommandMode(p); 29536285Sbrian } 29636285Sbrian break; 29736285Sbrian } 29837010Sbrian p->readtilde = 0; 29936285Sbrian break; 30036285Sbrian } 30136285Sbrian } 30236285Sbrian} 30336285Sbrian 30437141Sbrianstatic int 305134789Sbrianprompt_Write(struct fdescriptor *d __unused, struct bundle *bundle __unused, 306134789Sbrian const fd_set *fdset __unused) 30736285Sbrian{ 30836285Sbrian /* We never want to write here ! */ 30937019Sbrian log_Printf(LogALERT, "prompt_Write: Internal error: Bad call !\n"); 31037141Sbrian return 0; 31136285Sbrian} 31236285Sbrian 31336285Sbrianstruct prompt * 31436285Sbrianprompt_Create(struct server *s, struct bundle *bundle, int fd) 31536285Sbrian{ 31636285Sbrian struct prompt *p = (struct prompt *)malloc(sizeof(struct prompt)); 31736285Sbrian 31836285Sbrian if (p != NULL) { 31936285Sbrian p->desc.type = PROMPT_DESCRIPTOR; 32036285Sbrian p->desc.UpdateSet = prompt_UpdateSet; 32136285Sbrian p->desc.IsSet = prompt_IsSet; 32236285Sbrian p->desc.Read = prompt_Read; 32336285Sbrian p->desc.Write = prompt_Write; 32436285Sbrian 32536285Sbrian if (fd == PROMPT_STD) { 32636431Sbrian char *tty = ttyname(STDIN_FILENO); 32736431Sbrian 32836431Sbrian if (!tty) { 32936431Sbrian free(p); 33036431Sbrian return NULL; 33136431Sbrian } 33236285Sbrian p->fd_in = STDIN_FILENO; 33336285Sbrian p->fd_out = STDOUT_FILENO; 33436285Sbrian p->Term = stdout; 33536285Sbrian p->owner = NULL; 33636285Sbrian p->auth = LOCAL_AUTH; 33736285Sbrian p->src.type = "Controller"; 33836431Sbrian strncpy(p->src.from, tty, sizeof p->src.from - 1); 33936285Sbrian p->src.from[sizeof p->src.from - 1] = '\0'; 34036285Sbrian tcgetattr(p->fd_in, &p->oldtio); /* Save original tty mode */ 34136285Sbrian } else { 34236285Sbrian p->fd_in = p->fd_out = fd; 34336285Sbrian p->Term = fdopen(fd, "a+"); 34436285Sbrian p->owner = s; 34571657Sbrian p->auth = *s->cfg.passwd ? LOCAL_NO_AUTH : LOCAL_AUTH; 34636285Sbrian p->src.type = "unknown"; 34736285Sbrian *p->src.from = '\0'; 34836285Sbrian } 34936285Sbrian p->TermMode = NULL; 35036285Sbrian p->nonewline = 1; 35136285Sbrian p->needprompt = 1; 35237010Sbrian p->readtilde = 0; 35336285Sbrian p->bundle = bundle; 35436285Sbrian log_RegisterPrompt(p); 35536285Sbrian } 35636285Sbrian 35736285Sbrian return p; 35836285Sbrian} 35936285Sbrian 36036285Sbrianvoid 36136285Sbrianprompt_Destroy(struct prompt *p, int verbose) 36236285Sbrian{ 36336431Sbrian if (p) { 36436431Sbrian if (p->Term != stdout) { 36536431Sbrian fclose(p->Term); 36636431Sbrian close(p->fd_in); 36736431Sbrian if (p->fd_out != p->fd_in) 36836431Sbrian close(p->fd_out); 36936431Sbrian if (verbose) 37036431Sbrian log_Printf(LogPHASE, "%s: Client connection dropped.\n", p->src.from); 37136431Sbrian } else 37236431Sbrian prompt_TtyOldMode(p); 37336285Sbrian 37436431Sbrian log_UnRegisterPrompt(p); 37536431Sbrian free(p); 37636431Sbrian } 37736285Sbrian} 37836285Sbrian 37936285Sbrianvoid 38036285Sbrianprompt_Printf(struct prompt *p, const char *fmt,...) 38136285Sbrian{ 38236285Sbrian if (p && p->active) { 38336285Sbrian va_list ap; 38437011Sbrian 38536285Sbrian va_start(ap, fmt); 38637011Sbrian prompt_vPrintf(p, fmt, ap); 38736285Sbrian va_end(ap); 38836285Sbrian } 38936285Sbrian} 39036285Sbrian 39136285Sbrianvoid 39236285Sbrianprompt_vPrintf(struct prompt *p, const char *fmt, va_list ap) 39336285Sbrian{ 39436285Sbrian if (p && p->active) { 39537011Sbrian char nfmt[LINE_LEN]; 39637011Sbrian const char *pfmt; 39737011Sbrian 39837011Sbrian if (p->TermMode) { 39937011Sbrian /* Stuff '\r' in front of '\n' 'cos we're in raw mode */ 400134789Sbrian size_t len = strlen(fmt); 40137011Sbrian 40245264Sbrian if (len && len < sizeof nfmt - 1 && fmt[len-1] == '\n' && 40345264Sbrian (len == 1 || fmt[len-2] != '\r')) { 40437011Sbrian strcpy(nfmt, fmt); 40537011Sbrian strcpy(nfmt + len - 1, "\r\n"); 40637011Sbrian pfmt = nfmt; 40737011Sbrian } else 40837011Sbrian pfmt = fmt; 40937011Sbrian } else 41037011Sbrian pfmt = fmt; 41137011Sbrian vfprintf(p->Term, pfmt, ap); 41236285Sbrian fflush(p->Term); 41336285Sbrian p->nonewline = 1; 41436285Sbrian } 41536285Sbrian} 41636285Sbrian 41736285Sbrianvoid 41836285Sbrianprompt_TtyInit(struct prompt *p) 41936285Sbrian{ 42036285Sbrian int stat, fd = p ? p->fd_in : STDIN_FILENO; 42136285Sbrian struct termios newtio; 42236285Sbrian 42336285Sbrian stat = fcntl(fd, F_GETFL, 0); 42436285Sbrian if (stat > 0) { 42536285Sbrian stat |= O_NONBLOCK; 42636285Sbrian fcntl(fd, F_SETFL, stat); 42736285Sbrian } 42836285Sbrian 42936285Sbrian if (p) 43036285Sbrian newtio = p->oldtio; 43136285Sbrian else 43236285Sbrian tcgetattr(fd, &newtio); 43336285Sbrian 43436285Sbrian newtio.c_lflag &= ~(ECHO | ISIG | ICANON); 43536285Sbrian newtio.c_iflag = 0; 43636285Sbrian newtio.c_oflag &= ~OPOST; 43736285Sbrian if (!p) 43836285Sbrian newtio.c_cc[VINTR] = _POSIX_VDISABLE; 43936285Sbrian newtio.c_cc[VMIN] = 1; 44036285Sbrian newtio.c_cc[VTIME] = 0; 44136285Sbrian newtio.c_cflag |= CS8; 44236285Sbrian tcsetattr(fd, TCSANOW, &newtio); 44336285Sbrian if (p) 44436285Sbrian p->comtio = newtio; 44536285Sbrian} 44636285Sbrian 44736285Sbrian/* 44836285Sbrian * Set tty into command mode. We allow canonical input and echo processing. 44936285Sbrian */ 45036285Sbrianvoid 45136285Sbrianprompt_TtyCommandMode(struct prompt *p) 45236285Sbrian{ 45336285Sbrian struct termios newtio; 45436285Sbrian int stat; 45536285Sbrian 45636285Sbrian tcgetattr(p->fd_in, &newtio); 45736285Sbrian newtio.c_lflag |= (ECHO | ISIG | ICANON); 45836285Sbrian newtio.c_iflag = p->oldtio.c_iflag; 45936285Sbrian newtio.c_oflag |= OPOST; 46036285Sbrian tcsetattr(p->fd_in, TCSADRAIN, &newtio); 46136285Sbrian 46236285Sbrian stat = fcntl(p->fd_in, F_GETFL, 0); 46336285Sbrian if (stat > 0) { 46436285Sbrian stat |= O_NONBLOCK; 46536285Sbrian fcntl(p->fd_in, F_SETFL, stat); 46636285Sbrian } 46736285Sbrian 46836285Sbrian p->TermMode = NULL; 46936285Sbrian} 47036285Sbrian 47136285Sbrian/* 47236285Sbrian * Set tty into terminal mode which is used while we invoke term command. 47336285Sbrian */ 47436285Sbrianvoid 47536285Sbrianprompt_TtyTermMode(struct prompt *p, struct datalink *dl) 47636285Sbrian{ 47736285Sbrian int stat; 47836285Sbrian 47936285Sbrian if (p->Term == stdout) 48036285Sbrian tcsetattr(p->fd_in, TCSADRAIN, &p->comtio); 48136285Sbrian 48236285Sbrian stat = fcntl(p->fd_in, F_GETFL, 0); 48336285Sbrian if (stat > 0) { 48436285Sbrian stat &= ~O_NONBLOCK; 48536285Sbrian fcntl(p->fd_in, F_SETFL, stat); 48636285Sbrian } 48736285Sbrian p->TermMode = dl; 48836285Sbrian} 48936285Sbrian 49036285Sbrianvoid 49136285Sbrianprompt_TtyOldMode(struct prompt *p) 49236285Sbrian{ 49336285Sbrian int stat; 49436285Sbrian 49536285Sbrian stat = fcntl(p->fd_in, F_GETFL, 0); 49636285Sbrian if (stat > 0) { 49736285Sbrian stat &= ~O_NONBLOCK; 49836285Sbrian fcntl(p->fd_in, F_SETFL, stat); 49936285Sbrian } 50036285Sbrian 50136285Sbrian if (p->Term == stdout) 50236285Sbrian tcsetattr(p->fd_in, TCSADRAIN, &p->oldtio); 50336285Sbrian} 50436285Sbrian 50536285Sbrianpid_t 50636285Sbrianprompt_pgrp(struct prompt *p) 50736285Sbrian{ 50836285Sbrian return tcgetpgrp(p->fd_in); 50936285Sbrian} 51036285Sbrian 51136285Sbrianint 51236285SbrianPasswdCommand(struct cmdargs const *arg) 51336285Sbrian{ 51436285Sbrian const char *pass; 51536285Sbrian 51636285Sbrian if (!arg->prompt) { 51736285Sbrian log_Printf(LogWARN, "passwd: Cannot specify without a prompt\n"); 51836285Sbrian return 0; 51936285Sbrian } 52036285Sbrian 52136285Sbrian if (arg->prompt->owner == NULL) { 52236285Sbrian log_Printf(LogWARN, "passwd: Not required\n"); 52336285Sbrian return 0; 52436285Sbrian } 52536285Sbrian 52636285Sbrian if (arg->argc == arg->argn) 52736285Sbrian pass = ""; 52836285Sbrian else if (arg->argc > arg->argn+1) 52936285Sbrian return -1; 53036285Sbrian else 53136285Sbrian pass = arg->argv[arg->argn]; 53236285Sbrian 53371657Sbrian if (!strcmp(arg->prompt->owner->cfg.passwd, pass)) 53436285Sbrian arg->prompt->auth = LOCAL_AUTH; 53536285Sbrian else 53636285Sbrian arg->prompt->auth = LOCAL_NO_AUTH; 53736285Sbrian 53836285Sbrian return 0; 53936285Sbrian} 54036285Sbrian 54136285Sbrianstatic struct pppTimer bgtimer; 54236285Sbrian 54336285Sbrianstatic void 54436285Sbrianprompt_TimedContinue(void *v) 54536285Sbrian{ 54636285Sbrian prompt_Continue((struct prompt *)v); 54736285Sbrian} 54836285Sbrian 54936285Sbrianvoid 55036285Sbrianprompt_Continue(struct prompt *p) 55136285Sbrian{ 55236285Sbrian timer_Stop(&bgtimer); 55336285Sbrian if (getpgrp() == prompt_pgrp(p)) { 55436285Sbrian prompt_TtyCommandMode(p); 55536285Sbrian p->nonewline = 1; 55636285Sbrian prompt_Required(p); 55736314Sbrian log_ActivatePrompt(p); 55836285Sbrian } else if (!p->owner) { 55936285Sbrian bgtimer.func = prompt_TimedContinue; 56036285Sbrian bgtimer.name = "prompt bg"; 56136285Sbrian bgtimer.load = SECTICKS; 56236285Sbrian bgtimer.arg = p; 56336285Sbrian timer_Start(&bgtimer); 56436285Sbrian } 56536285Sbrian} 56636285Sbrian 56736285Sbrianvoid 56836285Sbrianprompt_Suspend(struct prompt *p) 56936285Sbrian{ 57036285Sbrian if (getpgrp() == prompt_pgrp(p)) { 57136285Sbrian prompt_TtyOldMode(p); 57236314Sbrian log_DeactivatePrompt(p); 57336285Sbrian } 57436285Sbrian} 575