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 */
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>
3330949fd4SBrian Somers #include <sys/socket.h>
34565e35e5SBrian Somers #include <sys/un.h>
3585b542cfSBrian Somers
36833882f7SBrian Somers #include <errno.h>
3785b542cfSBrian Somers #include <stdarg.h>
3885b542cfSBrian Somers #include <stdio.h>
39b6217683SBrian Somers #include <stdlib.h>
40b6217683SBrian Somers #include <string.h>
4185b542cfSBrian Somers #include <sys/fcntl.h>
4285b542cfSBrian Somers #include <termios.h>
4385b542cfSBrian Somers #include <unistd.h>
4485b542cfSBrian Somers
455d9e6103SBrian Somers #include "layer.h"
4685b542cfSBrian Somers #include "defs.h"
4785b542cfSBrian Somers #include "timer.h"
4885b542cfSBrian Somers #include "command.h"
4985b542cfSBrian Somers #include "log.h"
5085b542cfSBrian Somers #include "descriptor.h"
5185b542cfSBrian Somers #include "prompt.h"
5285b542cfSBrian Somers #include "fsm.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"
601038894eSBrian Somers #include "lcp.h"
6130949fd4SBrian Somers #include "ncpaddr.h"
625a72b6edSBrian Somers #include "ipcp.h"
635a72b6edSBrian Somers #include "filter.h"
643006ec67SBrian Somers #include "async.h"
653b0f8d2eSBrian Somers #include "ccp.h"
663006ec67SBrian Somers #include "link.h"
673006ec67SBrian Somers #include "physical.h"
683b0f8d2eSBrian Somers #include "mp.h"
69972a1bcfSBrian Somers #ifndef NORADIUS
70972a1bcfSBrian Somers #include "radius.h"
71972a1bcfSBrian Somers #endif
7230949fd4SBrian Somers #include "ipv6cp.h"
7330949fd4SBrian Somers #include "ncp.h"
743b0f8d2eSBrian Somers #include "bundle.h"
75c5a5a6caSBrian Somers #include "chat.h"
76e2ebb036SBrian Somers #include "chap.h"
7792b09558SBrian Somers #include "cbcp.h"
78c5a5a6caSBrian Somers #include "datalink.h"
79b6217683SBrian Somers #include "server.h"
809dae3e8dSBrian Somers #include "main.h"
8185b542cfSBrian Somers
82b6217683SBrian Somers static void
prompt_Display(struct prompt * p)83b6217683SBrian Somers prompt_Display(struct prompt *p)
84b6217683SBrian Somers {
85d93d3a9cSBrian Somers /* XXX: See Index2Nam() - should we only figure this out once ? */
8626e6a622SBrian Somers static char shostname[MAXHOSTNAMELEN];
87b6217683SBrian Somers const char *pconnect, *pauth;
88b6217683SBrian Somers
89b6217683SBrian Somers if (p->TermMode || !p->needprompt)
90b6217683SBrian Somers return;
91b6217683SBrian Somers
92b6217683SBrian Somers p->needprompt = 0;
93b6217683SBrian Somers
94b6217683SBrian Somers if (p->nonewline)
95b6217683SBrian Somers p->nonewline = 0;
96b6217683SBrian Somers else
97b6217683SBrian Somers fprintf(p->Term, "\n");
98b6217683SBrian Somers
99b6217683SBrian Somers if (p->auth == LOCAL_AUTH)
100b6217683SBrian Somers pauth = " ON ";
101b6217683SBrian Somers else
102b6217683SBrian Somers pauth = " on ";
103b6217683SBrian Somers
104b6217683SBrian Somers if (p->bundle->ncp.ipcp.fsm.state == ST_OPENED)
105b6217683SBrian Somers pconnect = "PPP";
106bbdd2707SHajimu UMEMOTO #ifndef NOINET6
107bbdd2707SHajimu UMEMOTO else if (!Enabled(p->bundle, OPT_IPCP) &&
108bbdd2707SHajimu UMEMOTO p->bundle->ncp.ipv6cp.fsm.state == ST_OPENED)
109bbdd2707SHajimu UMEMOTO pconnect = "PPP";
110bbdd2707SHajimu UMEMOTO #endif
111b6217683SBrian Somers else if (bundle_Phase(p->bundle) == PHASE_NETWORK)
112b6217683SBrian Somers pconnect = "PPp";
113b6217683SBrian Somers else if (bundle_Phase(p->bundle) == PHASE_AUTHENTICATE)
114b6217683SBrian Somers pconnect = "Ppp";
115b6217683SBrian Somers else
116b6217683SBrian Somers pconnect = "ppp";
117b6217683SBrian Somers
118b6217683SBrian Somers if (*shostname == '\0') {
119cdbbb6b5SBrian Somers char *dot;
120b6217683SBrian Somers
12152847614SBrian Somers if (gethostname(shostname, sizeof shostname) || *shostname == '\0')
122b6217683SBrian Somers strcpy(shostname, "localhost");
123cdbbb6b5SBrian Somers else if ((dot = strchr(shostname, '.')))
124cdbbb6b5SBrian Somers *dot = '\0';
125b6217683SBrian Somers }
126b6217683SBrian Somers
127b6217683SBrian Somers fprintf(p->Term, "%s%s%s> ", pconnect, pauth, shostname);
128b6217683SBrian Somers fflush(p->Term);
129b6217683SBrian Somers }
13085b542cfSBrian Somers
13185b542cfSBrian Somers static int
prompt_UpdateSet(struct fdescriptor * d,fd_set * r,fd_set * w __unused,fd_set * e,int * n)132057f1760SBrian Somers prompt_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w __unused,
133057f1760SBrian Somers fd_set *e, int *n)
13485b542cfSBrian Somers {
13585b542cfSBrian Somers struct prompt *p = descriptor2prompt(d);
136b6dec9f0SBrian Somers int sets;
13785b542cfSBrian Somers
138b6dec9f0SBrian Somers sets = 0;
139f91ad6b0SBrian Somers
140f91ad6b0SBrian Somers if (!p->active)
141f91ad6b0SBrian Somers return sets;
142f91ad6b0SBrian Somers
14385b542cfSBrian Somers if (p->fd_in >= 0) {
144b6dec9f0SBrian Somers if (r) {
14585b542cfSBrian Somers FD_SET(p->fd_in, r);
14624989c68SBrian Somers log_Printf(LogTIMER, "prompt %s: fdset(r) %d\n", p->src.from, p->fd_in);
147b6dec9f0SBrian Somers sets++;
148b6dec9f0SBrian Somers }
149b6dec9f0SBrian Somers if (e) {
15085b542cfSBrian Somers FD_SET(p->fd_in, e);
15124989c68SBrian Somers log_Printf(LogTIMER, "prompt %s: fdset(e) %d\n", p->src.from, p->fd_in);
152b6dec9f0SBrian Somers sets++;
153b6dec9f0SBrian Somers }
154b6dec9f0SBrian Somers if (sets && *n < p->fd_in + 1)
155b6dec9f0SBrian Somers *n = p->fd_in + 1;
15685b542cfSBrian Somers }
15785b542cfSBrian Somers
158b6217683SBrian Somers prompt_Display(p);
159b6217683SBrian Somers
160b6dec9f0SBrian Somers return sets;
16185b542cfSBrian Somers }
16285b542cfSBrian Somers
16385b542cfSBrian Somers static int
prompt_IsSet(struct fdescriptor * d,const fd_set * fdset)164f013f33eSBrian Somers prompt_IsSet(struct fdescriptor *d, const fd_set *fdset)
16585b542cfSBrian Somers {
16685b542cfSBrian Somers struct prompt *p = descriptor2prompt(d);
16785b542cfSBrian Somers return p->fd_in >= 0 && FD_ISSET(p->fd_in, fdset);
16885b542cfSBrian Somers }
16985b542cfSBrian Somers
17085b542cfSBrian Somers
17185b542cfSBrian Somers static void
prompt_ShowHelp(struct prompt * p)17285b542cfSBrian Somers prompt_ShowHelp(struct prompt *p)
17385b542cfSBrian Somers {
174f7704be7SBrian Somers prompt_Printf(p, "The following commands are available:\n");
175f7704be7SBrian Somers prompt_Printf(p, " ~p\tEnter Packet mode\n");
176f7704be7SBrian Somers prompt_Printf(p, " ~t\tShow timers\n");
177f7704be7SBrian Somers prompt_Printf(p, " ~m\tShow memory map\n");
178f7704be7SBrian Somers prompt_Printf(p, " ~.\tTerminate program\n");
179f7704be7SBrian Somers prompt_Printf(p, " ~?\tThis help\n");
18085b542cfSBrian Somers }
18185b542cfSBrian Somers
18285b542cfSBrian Somers static void
prompt_Read(struct fdescriptor * d,struct bundle * bundle,const fd_set * fdset __unused)183057f1760SBrian Somers prompt_Read(struct fdescriptor *d, struct bundle *bundle,
184057f1760SBrian Somers const fd_set *fdset __unused)
18585b542cfSBrian Somers {
18685b542cfSBrian Somers struct prompt *p = descriptor2prompt(d);
187b4f63b0bSBrian Somers struct prompt *op;
18885b542cfSBrian Somers int n;
18985b542cfSBrian Somers char ch;
19085b542cfSBrian Somers char linebuff[LINE_LEN];
19185b542cfSBrian Somers
1921b35f8f7SBrian Somers if (p->TermMode == NULL) {
19385b542cfSBrian Somers n = read(p->fd_in, linebuff, sizeof linebuff - 1);
19485b542cfSBrian Somers if (n > 0) {
19585b542cfSBrian Somers if (linebuff[n-1] == '\n')
19685b542cfSBrian Somers linebuff[--n] = '\0';
19785b542cfSBrian Somers else
19885b542cfSBrian Somers linebuff[n] = '\0';
199dd7e2610SBrian Somers p->nonewline = 1; /* Maybe command_Decode does a prompt */
200b6217683SBrian Somers prompt_Required(p);
201b4f63b0bSBrian Somers if (n) {
202b4f63b0bSBrian Somers if ((op = log_PromptContext) == NULL)
203b4f63b0bSBrian Somers log_PromptContext = p;
204c39aa54eSBrian Somers if (!command_Decode(bundle, linebuff, n, p, p->src.from))
205c39aa54eSBrian Somers prompt_Printf(p, "Syntax error\n");
206b4f63b0bSBrian Somers log_PromptContext = op;
207b4f63b0bSBrian Somers }
20885b542cfSBrian Somers } else if (n <= 0) {
2090f2f3eb3SBrian Somers log_Printf(LogPHASE, "%s: Client connection closed.\n", p->src.from);
2109dae3e8dSBrian Somers if (!p->owner)
211057f1760SBrian Somers Cleanup();
212b6217683SBrian Somers prompt_Destroy(p, 0);
21385b542cfSBrian Somers }
21485b542cfSBrian Somers return;
21585b542cfSBrian Somers }
21685b542cfSBrian Somers
217c7cc5030SBrian Somers switch (p->TermMode->state) {
218c7cc5030SBrian Somers case DATALINK_CLOSED:
219c7cc5030SBrian Somers prompt_Printf(p, "Link lost, terminal mode.\n");
220b6217683SBrian Somers prompt_TtyCommandMode(p);
221b6217683SBrian Somers p->nonewline = 0;
222b6217683SBrian Somers prompt_Required(p);
223c7cc5030SBrian Somers return;
224c7cc5030SBrian Somers
225c7cc5030SBrian Somers case DATALINK_READY:
226c7cc5030SBrian Somers break;
227c7cc5030SBrian Somers
228c7cc5030SBrian Somers case DATALINK_OPEN:
229c7cc5030SBrian Somers prompt_Printf(p, "\nPacket mode detected.\n");
230b6217683SBrian Somers prompt_TtyCommandMode(p);
231b6217683SBrian Somers p->nonewline = 0;
232c7cc5030SBrian Somers /* We'll get a prompt because of our status change */
233f0067240SPhilippe Charnier /* FALLTHROUGH */
234c7cc5030SBrian Somers
235c7cc5030SBrian Somers default:
236c7cc5030SBrian Somers /* Wait 'till we're in a state we care about */
237c7cc5030SBrian Somers return;
238c7cc5030SBrian Somers }
239c7cc5030SBrian Somers
24085b542cfSBrian Somers /*
24185b542cfSBrian Somers * We are in terminal mode, decode special sequences
24285b542cfSBrian Somers */
24385b542cfSBrian Somers n = read(p->fd_in, &ch, 1);
244dd7e2610SBrian Somers log_Printf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n);
24585b542cfSBrian Somers
24685b542cfSBrian Somers if (n > 0) {
247d93d3a9cSBrian Somers switch (p->readtilde) {
24885b542cfSBrian Somers case 0:
24985b542cfSBrian Somers if (ch == '~')
250d93d3a9cSBrian Somers p->readtilde = 1;
25185b542cfSBrian Somers else
252dd7e2610SBrian Somers if (physical_Write(p->TermMode->physical, &ch, n) < 0) {
253a33b2ef7SBrian Somers log_Printf(LogWARN, "error writing to modem: %s\n", strerror(errno));
254833882f7SBrian Somers prompt_TtyCommandMode(p);
255833882f7SBrian Somers }
25685b542cfSBrian Somers break;
25785b542cfSBrian Somers case 1:
25885b542cfSBrian Somers switch (ch) {
25985b542cfSBrian Somers case '?':
26085b542cfSBrian Somers prompt_ShowHelp(p);
26185b542cfSBrian Somers break;
26285b542cfSBrian Somers case 'p':
263c7cc5030SBrian Somers datalink_Up(p->TermMode, 0, 1);
264c7cc5030SBrian Somers prompt_Printf(p, "\nPacket mode.\n");
265b6217683SBrian Somers prompt_TtyCommandMode(p);
26685b542cfSBrian Somers break;
26785b542cfSBrian Somers case '.':
268b6217683SBrian Somers prompt_TtyCommandMode(p);
269b6217683SBrian Somers p->nonewline = 0;
270b6217683SBrian Somers prompt_Required(p);
27185b542cfSBrian Somers break;
27285b542cfSBrian Somers case 't':
273dd7e2610SBrian Somers timer_Show(0, p);
27485b542cfSBrian Somers break;
27585b542cfSBrian Somers case 'm':
276f7704be7SBrian Somers {
277f7704be7SBrian Somers struct cmdargs arg;
278f7704be7SBrian Somers
279f7704be7SBrian Somers arg.cmdtab = NULL;
280f7704be7SBrian Somers arg.cmd = NULL;
281f7704be7SBrian Somers arg.argc = 0;
282f7704be7SBrian Somers arg.argn = 0;
283f7704be7SBrian Somers arg.argv = NULL;
284f7704be7SBrian Somers arg.bundle = bundle;
285f7704be7SBrian Somers arg.cx = p->TermMode;
286f7704be7SBrian Somers arg.prompt = p;
287f7704be7SBrian Somers
288f7704be7SBrian Somers mbuf_Show(&arg);
289f7704be7SBrian Somers }
29085b542cfSBrian Somers break;
29185b542cfSBrian Somers default:
292dd7e2610SBrian Somers if (physical_Write(p->TermMode->physical, &ch, n) < 0) {
293a33b2ef7SBrian Somers log_Printf(LogWARN, "error writing to modem: %s\n", strerror(errno));
294833882f7SBrian Somers prompt_TtyCommandMode(p);
295833882f7SBrian Somers }
29685b542cfSBrian Somers break;
29785b542cfSBrian Somers }
298d93d3a9cSBrian Somers p->readtilde = 0;
29985b542cfSBrian Somers break;
30085b542cfSBrian Somers }
30185b542cfSBrian Somers }
30285b542cfSBrian Somers }
30385b542cfSBrian Somers
3041af29a6eSBrian Somers static int
prompt_Write(struct fdescriptor * d __unused,struct bundle * bundle __unused,const fd_set * fdset __unused)305057f1760SBrian Somers prompt_Write(struct fdescriptor *d __unused, struct bundle *bundle __unused,
306057f1760SBrian Somers const fd_set *fdset __unused)
30785b542cfSBrian Somers {
308f4768038SBrian Somers /* We never want to write here ! */
309a33b2ef7SBrian Somers log_Printf(LogALERT, "prompt_Write: Internal error: Bad call !\n");
3101af29a6eSBrian Somers return 0;
31185b542cfSBrian Somers }
31285b542cfSBrian Somers
313b6217683SBrian Somers struct prompt *
prompt_Create(struct server * s,struct bundle * bundle,int fd)314b6217683SBrian Somers prompt_Create(struct server *s, struct bundle *bundle, int fd)
31585b542cfSBrian Somers {
316b6217683SBrian Somers struct prompt *p = (struct prompt *)malloc(sizeof(struct prompt));
31785b542cfSBrian Somers
318b6217683SBrian Somers if (p != NULL) {
319b6217683SBrian Somers p->desc.type = PROMPT_DESCRIPTOR;
320b6217683SBrian Somers p->desc.UpdateSet = prompt_UpdateSet;
321b6217683SBrian Somers p->desc.IsSet = prompt_IsSet;
322b6217683SBrian Somers p->desc.Read = prompt_Read;
323b6217683SBrian Somers p->desc.Write = prompt_Write;
32485b542cfSBrian Somers
325b6217683SBrian Somers if (fd == PROMPT_STD) {
3260f78c7a7SBrian Somers char *tty = ttyname(STDIN_FILENO);
3270f78c7a7SBrian Somers
3280f78c7a7SBrian Somers if (!tty) {
3290f78c7a7SBrian Somers free(p);
3300f78c7a7SBrian Somers return NULL;
3310f78c7a7SBrian Somers }
33285b542cfSBrian Somers p->fd_in = STDIN_FILENO;
33385b542cfSBrian Somers p->fd_out = STDOUT_FILENO;
33485b542cfSBrian Somers p->Term = stdout;
335b6217683SBrian Somers p->owner = NULL;
336b6217683SBrian Somers p->auth = LOCAL_AUTH;
337565e35e5SBrian Somers p->src.type = "Controller";
3380f78c7a7SBrian Somers strncpy(p->src.from, tty, sizeof p->src.from - 1);
339565e35e5SBrian Somers p->src.from[sizeof p->src.from - 1] = '\0';
340b6217683SBrian Somers tcgetattr(p->fd_in, &p->oldtio); /* Save original tty mode */
34185b542cfSBrian Somers } else {
34285b542cfSBrian Somers p->fd_in = p->fd_out = fd;
34385b542cfSBrian Somers p->Term = fdopen(fd, "a+");
344b6217683SBrian Somers p->owner = s;
34574457d3dSBrian Somers p->auth = *s->cfg.passwd ? LOCAL_NO_AUTH : LOCAL_AUTH;
346565e35e5SBrian Somers p->src.type = "unknown";
347565e35e5SBrian Somers *p->src.from = '\0';
34885b542cfSBrian Somers }
3491b35f8f7SBrian Somers p->TermMode = NULL;
350b6217683SBrian Somers p->nonewline = 1;
351b6217683SBrian Somers p->needprompt = 1;
352d93d3a9cSBrian Somers p->readtilde = 0;
353b6217683SBrian Somers p->bundle = bundle;
354b6217683SBrian Somers log_RegisterPrompt(p);
355b6217683SBrian Somers }
35685b542cfSBrian Somers
357b6217683SBrian Somers return p;
35885b542cfSBrian Somers }
35985b542cfSBrian Somers
3603006ec67SBrian Somers void
prompt_Destroy(struct prompt * p,int verbose)361b6217683SBrian Somers prompt_Destroy(struct prompt *p, int verbose)
36285b542cfSBrian Somers {
3630f78c7a7SBrian Somers if (p) {
364b6217683SBrian Somers if (p->Term != stdout) {
365b6217683SBrian Somers fclose(p->Term);
36685b542cfSBrian Somers close(p->fd_in);
36785b542cfSBrian Somers if (p->fd_out != p->fd_in)
36885b542cfSBrian Somers close(p->fd_out);
36985b542cfSBrian Somers if (verbose)
3700f2f3eb3SBrian Somers log_Printf(LogPHASE, "%s: Client connection dropped.\n", p->src.from);
371b6217683SBrian Somers } else
372b6217683SBrian Somers prompt_TtyOldMode(p);
373b6217683SBrian Somers
374565e35e5SBrian Somers log_UnRegisterPrompt(p);
375565e35e5SBrian Somers free(p);
37685b542cfSBrian Somers }
3770f78c7a7SBrian Somers }
37885b542cfSBrian Somers
37985b542cfSBrian Somers void
prompt_Printf(struct prompt * p,const char * fmt,...)38085b542cfSBrian Somers prompt_Printf(struct prompt *p, const char *fmt,...)
38185b542cfSBrian Somers {
382f91ad6b0SBrian Somers if (p && p->active) {
38385b542cfSBrian Somers va_list ap;
384f7704be7SBrian Somers
38585b542cfSBrian Somers va_start(ap, fmt);
386f7704be7SBrian Somers prompt_vPrintf(p, fmt, ap);
38785b542cfSBrian Somers va_end(ap);
38885b542cfSBrian Somers }
38985b542cfSBrian Somers }
39085b542cfSBrian Somers
39185b542cfSBrian Somers void
prompt_vPrintf(struct prompt * p,const char * fmt,va_list ap)39285b542cfSBrian Somers prompt_vPrintf(struct prompt *p, const char *fmt, va_list ap)
39385b542cfSBrian Somers {
394f91ad6b0SBrian Somers if (p && p->active) {
395f7704be7SBrian Somers char nfmt[LINE_LEN];
396f7704be7SBrian Somers const char *pfmt;
397f7704be7SBrian Somers
398f7704be7SBrian Somers if (p->TermMode) {
399f7704be7SBrian Somers /* Stuff '\r' in front of '\n' 'cos we're in raw mode */
400057f1760SBrian Somers size_t len = strlen(fmt);
401f7704be7SBrian Somers
402e3044845SBrian Somers if (len && len < sizeof nfmt - 1 && fmt[len-1] == '\n' &&
403e3044845SBrian Somers (len == 1 || fmt[len-2] != '\r')) {
404f7704be7SBrian Somers strcpy(nfmt, fmt);
405f7704be7SBrian Somers strcpy(nfmt + len - 1, "\r\n");
406f7704be7SBrian Somers pfmt = nfmt;
407f7704be7SBrian Somers } else
408f7704be7SBrian Somers pfmt = fmt;
409f7704be7SBrian Somers } else
410f7704be7SBrian Somers pfmt = fmt;
411f7704be7SBrian Somers vfprintf(p->Term, pfmt, ap);
41285b542cfSBrian Somers fflush(p->Term);
413c06d604bSBrian Somers p->nonewline = 1;
41485b542cfSBrian Somers }
41585b542cfSBrian Somers }
41685b542cfSBrian Somers
41785b542cfSBrian Somers void
prompt_TtyInit(struct prompt * p)418565e35e5SBrian Somers prompt_TtyInit(struct prompt *p)
41985b542cfSBrian Somers {
420565e35e5SBrian Somers int stat, fd = p ? p->fd_in : STDIN_FILENO;
421b6217683SBrian Somers struct termios newtio;
422b6217683SBrian Somers
423565e35e5SBrian Somers stat = fcntl(fd, F_GETFL, 0);
424565e35e5SBrian Somers if (stat > 0) {
425565e35e5SBrian Somers stat |= O_NONBLOCK;
426565e35e5SBrian Somers fcntl(fd, F_SETFL, stat);
427565e35e5SBrian Somers }
428565e35e5SBrian Somers
429565e35e5SBrian Somers if (p)
43085b542cfSBrian Somers newtio = p->oldtio;
431565e35e5SBrian Somers else
432565e35e5SBrian Somers tcgetattr(fd, &newtio);
433565e35e5SBrian Somers
43485b542cfSBrian Somers newtio.c_lflag &= ~(ECHO | ISIG | ICANON);
43585b542cfSBrian Somers newtio.c_iflag = 0;
43685b542cfSBrian Somers newtio.c_oflag &= ~OPOST;
437565e35e5SBrian Somers if (!p)
43885b542cfSBrian Somers newtio.c_cc[VINTR] = _POSIX_VDISABLE;
43985b542cfSBrian Somers newtio.c_cc[VMIN] = 1;
44085b542cfSBrian Somers newtio.c_cc[VTIME] = 0;
44185b542cfSBrian Somers newtio.c_cflag |= CS8;
442565e35e5SBrian Somers tcsetattr(fd, TCSANOW, &newtio);
443565e35e5SBrian Somers if (p)
44485b542cfSBrian Somers p->comtio = newtio;
44585b542cfSBrian Somers }
44685b542cfSBrian Somers
44785b542cfSBrian Somers /*
44885b542cfSBrian Somers * Set tty into command mode. We allow canonical input and echo processing.
44985b542cfSBrian Somers */
45085b542cfSBrian Somers void
prompt_TtyCommandMode(struct prompt * p)45185b542cfSBrian Somers prompt_TtyCommandMode(struct prompt *p)
45285b542cfSBrian Somers {
45385b542cfSBrian Somers struct termios newtio;
45485b542cfSBrian Somers int stat;
45585b542cfSBrian Somers
45685b542cfSBrian Somers tcgetattr(p->fd_in, &newtio);
45785b542cfSBrian Somers newtio.c_lflag |= (ECHO | ISIG | ICANON);
45885b542cfSBrian Somers newtio.c_iflag = p->oldtio.c_iflag;
45985b542cfSBrian Somers newtio.c_oflag |= OPOST;
46085b542cfSBrian Somers tcsetattr(p->fd_in, TCSADRAIN, &newtio);
461b6217683SBrian Somers
46285b542cfSBrian Somers stat = fcntl(p->fd_in, F_GETFL, 0);
46385b542cfSBrian Somers if (stat > 0) {
46485b542cfSBrian Somers stat |= O_NONBLOCK;
465b6217683SBrian Somers fcntl(p->fd_in, F_SETFL, stat);
46685b542cfSBrian Somers }
467b6217683SBrian Somers
4681b35f8f7SBrian Somers p->TermMode = NULL;
46985b542cfSBrian Somers }
47085b542cfSBrian Somers
47185b542cfSBrian Somers /*
47285b542cfSBrian Somers * Set tty into terminal mode which is used while we invoke term command.
47385b542cfSBrian Somers */
47485b542cfSBrian Somers void
prompt_TtyTermMode(struct prompt * p,struct datalink * dl)4751b35f8f7SBrian Somers prompt_TtyTermMode(struct prompt *p, struct datalink *dl)
47685b542cfSBrian Somers {
47785b542cfSBrian Somers int stat;
47885b542cfSBrian Somers
479b6217683SBrian Somers if (p->Term == stdout)
48085b542cfSBrian Somers tcsetattr(p->fd_in, TCSADRAIN, &p->comtio);
481b6217683SBrian Somers
48285b542cfSBrian Somers stat = fcntl(p->fd_in, F_GETFL, 0);
48385b542cfSBrian Somers if (stat > 0) {
48485b542cfSBrian Somers stat &= ~O_NONBLOCK;
485b6217683SBrian Somers fcntl(p->fd_in, F_SETFL, stat);
48685b542cfSBrian Somers }
4871b35f8f7SBrian Somers p->TermMode = dl;
48885b542cfSBrian Somers }
48985b542cfSBrian Somers
49085b542cfSBrian Somers void
prompt_TtyOldMode(struct prompt * p)49185b542cfSBrian Somers prompt_TtyOldMode(struct prompt *p)
49285b542cfSBrian Somers {
49385b542cfSBrian Somers int stat;
49485b542cfSBrian Somers
49585b542cfSBrian Somers stat = fcntl(p->fd_in, F_GETFL, 0);
49685b542cfSBrian Somers if (stat > 0) {
49785b542cfSBrian Somers stat &= ~O_NONBLOCK;
498b6217683SBrian Somers fcntl(p->fd_in, F_SETFL, stat);
49985b542cfSBrian Somers }
500b6217683SBrian Somers
501b6217683SBrian Somers if (p->Term == stdout)
50285b542cfSBrian Somers tcsetattr(p->fd_in, TCSADRAIN, &p->oldtio);
50385b542cfSBrian Somers }
50485b542cfSBrian Somers
50585b542cfSBrian Somers pid_t
prompt_pgrp(struct prompt * p)50685b542cfSBrian Somers prompt_pgrp(struct prompt *p)
50785b542cfSBrian Somers {
508b6217683SBrian Somers return tcgetpgrp(p->fd_in);
509b6217683SBrian Somers }
510b6217683SBrian Somers
511b6217683SBrian Somers int
PasswdCommand(struct cmdargs const * arg)512b6217683SBrian Somers PasswdCommand(struct cmdargs const *arg)
513b6217683SBrian Somers {
514b6217683SBrian Somers const char *pass;
515b6217683SBrian Somers
516b6217683SBrian Somers if (!arg->prompt) {
517dd7e2610SBrian Somers log_Printf(LogWARN, "passwd: Cannot specify without a prompt\n");
518b6217683SBrian Somers return 0;
519b6217683SBrian Somers }
520b6217683SBrian Somers
521b6217683SBrian Somers if (arg->prompt->owner == NULL) {
522dd7e2610SBrian Somers log_Printf(LogWARN, "passwd: Not required\n");
523b6217683SBrian Somers return 0;
524b6217683SBrian Somers }
525b6217683SBrian Somers
52625092092SBrian Somers if (arg->argc == arg->argn)
527b6217683SBrian Somers pass = "";
52825092092SBrian Somers else if (arg->argc > arg->argn+1)
529b6217683SBrian Somers return -1;
530b6217683SBrian Somers else
53125092092SBrian Somers pass = arg->argv[arg->argn];
532b6217683SBrian Somers
53374457d3dSBrian Somers if (!strcmp(arg->prompt->owner->cfg.passwd, pass))
534b6217683SBrian Somers arg->prompt->auth = LOCAL_AUTH;
535b6217683SBrian Somers else
536b6217683SBrian Somers arg->prompt->auth = LOCAL_NO_AUTH;
537b6217683SBrian Somers
538b6217683SBrian Somers return 0;
53985b542cfSBrian Somers }
540f91ad6b0SBrian Somers
541f91ad6b0SBrian Somers static struct pppTimer bgtimer;
542f91ad6b0SBrian Somers
543f91ad6b0SBrian Somers static void
prompt_TimedContinue(void * v)544f91ad6b0SBrian Somers prompt_TimedContinue(void *v)
545f91ad6b0SBrian Somers {
546f91ad6b0SBrian Somers prompt_Continue((struct prompt *)v);
547f91ad6b0SBrian Somers }
548f91ad6b0SBrian Somers
549f91ad6b0SBrian Somers void
prompt_Continue(struct prompt * p)550f91ad6b0SBrian Somers prompt_Continue(struct prompt *p)
551f91ad6b0SBrian Somers {
552dd7e2610SBrian Somers timer_Stop(&bgtimer);
553f91ad6b0SBrian Somers if (getpgrp() == prompt_pgrp(p)) {
554f91ad6b0SBrian Somers prompt_TtyCommandMode(p);
555f91ad6b0SBrian Somers p->nonewline = 1;
556f91ad6b0SBrian Somers prompt_Required(p);
5570f2f3eb3SBrian Somers log_ActivatePrompt(p);
558f91ad6b0SBrian Somers } else if (!p->owner) {
559f91ad6b0SBrian Somers bgtimer.func = prompt_TimedContinue;
560f91ad6b0SBrian Somers bgtimer.name = "prompt bg";
561f91ad6b0SBrian Somers bgtimer.load = SECTICKS;
562f91ad6b0SBrian Somers bgtimer.arg = p;
563dd7e2610SBrian Somers timer_Start(&bgtimer);
564f91ad6b0SBrian Somers }
565f91ad6b0SBrian Somers }
566f91ad6b0SBrian Somers
567f91ad6b0SBrian Somers void
prompt_Suspend(struct prompt * p)568f91ad6b0SBrian Somers prompt_Suspend(struct prompt *p)
569f91ad6b0SBrian Somers {
570f91ad6b0SBrian Somers if (getpgrp() == prompt_pgrp(p)) {
571f91ad6b0SBrian Somers prompt_TtyOldMode(p);
5720f2f3eb3SBrian Somers log_DeactivatePrompt(p);
573f91ad6b0SBrian Somers }
574f91ad6b0SBrian Somers }
575