xref: /freebsd/usr.sbin/ppp/prompt.c (revision 4d846d260e2b9a3d4d0a701462568268cbfe7a5b)
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