xref: /freebsd/usr.sbin/ppp/prompt.c (revision 92b095588304eafcb4ba45699fe8afec726b5969)
185b542cfSBrian Somers /*-
285b542cfSBrian Somers  * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org>
385b542cfSBrian Somers  * All rights reserved.
485b542cfSBrian Somers  *
585b542cfSBrian Somers  * Redistribution and use in source and binary forms, with or without
685b542cfSBrian Somers  * modification, are permitted provided that the following conditions
785b542cfSBrian Somers  * are met:
885b542cfSBrian Somers  * 1. Redistributions of source code must retain the above copyright
985b542cfSBrian Somers  *    notice, this list of conditions and the following disclaimer.
1085b542cfSBrian Somers  * 2. Redistributions in binary form must reproduce the above copyright
1185b542cfSBrian Somers  *    notice, this list of conditions and the following disclaimer in the
1285b542cfSBrian Somers  *    documentation and/or other materials provided with the distribution.
1385b542cfSBrian Somers  *
1485b542cfSBrian Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1585b542cfSBrian Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1685b542cfSBrian Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1785b542cfSBrian Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1885b542cfSBrian Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1985b542cfSBrian Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2085b542cfSBrian Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2185b542cfSBrian Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2285b542cfSBrian Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2385b542cfSBrian Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2485b542cfSBrian Somers  * SUCH DAMAGE.
2585b542cfSBrian Somers  *
2692b09558SBrian Somers  *	$Id: prompt.c,v 1.9 1998/07/04 22:04:12 brian Exp $
2785b542cfSBrian Somers  */
2885b542cfSBrian Somers 
2985b542cfSBrian Somers #include <sys/param.h>
3085b542cfSBrian Somers #include <netinet/in.h>
31eaa4df37SBrian Somers #include <netinet/in_systm.h>
32eaa4df37SBrian Somers #include <netinet/ip.h>
33565e35e5SBrian Somers #include <sys/un.h>
3485b542cfSBrian Somers 
35833882f7SBrian Somers #include <errno.h>
3685b542cfSBrian Somers #include <stdarg.h>
3785b542cfSBrian Somers #include <stdio.h>
38b6217683SBrian Somers #include <stdlib.h>
39b6217683SBrian Somers #include <string.h>
4085b542cfSBrian Somers #include <sys/fcntl.h>
4185b542cfSBrian Somers #include <termios.h>
4285b542cfSBrian Somers #include <unistd.h>
4385b542cfSBrian Somers 
4485b542cfSBrian Somers #include "defs.h"
4585b542cfSBrian Somers #include "timer.h"
4685b542cfSBrian Somers #include "command.h"
4785b542cfSBrian Somers #include "log.h"
4885b542cfSBrian Somers #include "descriptor.h"
4985b542cfSBrian Somers #include "prompt.h"
5085b542cfSBrian Somers #include "fsm.h"
5185b542cfSBrian Somers #include "lcp.h"
5285b542cfSBrian Somers #include "auth.h"
5385b542cfSBrian Somers #include "iplist.h"
5485b542cfSBrian Somers #include "throughput.h"
55eaa4df37SBrian Somers #include "slcompress.h"
5685b542cfSBrian Somers #include "ipcp.h"
575ca5389aSBrian Somers #include "filter.h"
58879ed6faSBrian Somers #include "lqr.h"
593006ec67SBrian Somers #include "hdlc.h"
603006ec67SBrian Somers #include "async.h"
613006ec67SBrian Somers #include "mbuf.h"
623b0f8d2eSBrian Somers #include "ccp.h"
633006ec67SBrian Somers #include "link.h"
643006ec67SBrian Somers #include "physical.h"
653b0f8d2eSBrian Somers #include "mp.h"
663b0f8d2eSBrian Somers #include "bundle.h"
67c5a5a6caSBrian Somers #include "chat.h"
68e2ebb036SBrian Somers #include "chap.h"
6992b09558SBrian Somers #include "cbcp.h"
70c5a5a6caSBrian Somers #include "datalink.h"
71b6217683SBrian Somers #include "server.h"
729dae3e8dSBrian Somers #include "main.h"
7385b542cfSBrian Somers 
74b6217683SBrian Somers static void
75b6217683SBrian Somers prompt_Display(struct prompt *p)
76b6217683SBrian Somers {
77d93d3a9cSBrian Somers   /* XXX: See Index2Nam() - should we only figure this out once ? */
78b6217683SBrian Somers   static char shostname[MAXHOSTNAMELEN];
79b6217683SBrian Somers   const char *pconnect, *pauth;
80b6217683SBrian Somers 
81b6217683SBrian Somers   if (p->TermMode || !p->needprompt)
82b6217683SBrian Somers     return;
83b6217683SBrian Somers 
84b6217683SBrian Somers   p->needprompt = 0;
85b6217683SBrian Somers 
86b6217683SBrian Somers   if (p->nonewline)
87b6217683SBrian Somers     p->nonewline = 0;
88b6217683SBrian Somers   else
89b6217683SBrian Somers     fprintf(p->Term, "\n");
90b6217683SBrian Somers 
91b6217683SBrian Somers   if (p->auth == LOCAL_AUTH)
92b6217683SBrian Somers     pauth = " ON ";
93b6217683SBrian Somers   else
94b6217683SBrian Somers     pauth = " on ";
95b6217683SBrian Somers 
96b6217683SBrian Somers   if (p->bundle->ncp.ipcp.fsm.state == ST_OPENED)
97b6217683SBrian Somers     pconnect = "PPP";
98b6217683SBrian Somers   else if (bundle_Phase(p->bundle) == PHASE_NETWORK)
99b6217683SBrian Somers     pconnect = "PPp";
100b6217683SBrian Somers   else if (bundle_Phase(p->bundle) == PHASE_AUTHENTICATE)
101b6217683SBrian Somers     pconnect = "Ppp";
102b6217683SBrian Somers   else
103b6217683SBrian Somers     pconnect = "ppp";
104b6217683SBrian Somers 
105b6217683SBrian Somers   if (*shostname == '\0') {
106cdbbb6b5SBrian Somers     char *dot;
107b6217683SBrian Somers 
108b6217683SBrian Somers     if (gethostname(shostname, sizeof shostname))
109b6217683SBrian Somers       strcpy(shostname, "localhost");
110cdbbb6b5SBrian Somers     else if ((dot = strchr(shostname, '.')))
111cdbbb6b5SBrian Somers       *dot = '\0';
112b6217683SBrian Somers   }
113b6217683SBrian Somers 
114b6217683SBrian Somers   fprintf(p->Term, "%s%s%s> ", pconnect, pauth, shostname);
115b6217683SBrian Somers   fflush(p->Term);
116b6217683SBrian Somers }
11785b542cfSBrian Somers 
11885b542cfSBrian Somers static int
11985b542cfSBrian Somers prompt_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
12085b542cfSBrian Somers {
12185b542cfSBrian Somers   struct prompt *p = descriptor2prompt(d);
122b6dec9f0SBrian Somers   int sets;
12385b542cfSBrian Somers 
124b6dec9f0SBrian Somers   sets = 0;
125f91ad6b0SBrian Somers 
126f91ad6b0SBrian Somers   if (!p->active)
127f91ad6b0SBrian Somers     return sets;
128f91ad6b0SBrian Somers 
12985b542cfSBrian Somers   if (p->fd_in >= 0) {
130b6dec9f0SBrian Somers     if (r) {
13185b542cfSBrian Somers       FD_SET(p->fd_in, r);
13224989c68SBrian Somers       log_Printf(LogTIMER, "prompt %s: fdset(r) %d\n", p->src.from, p->fd_in);
133b6dec9f0SBrian Somers       sets++;
134b6dec9f0SBrian Somers     }
135b6dec9f0SBrian Somers     if (e) {
13685b542cfSBrian Somers       FD_SET(p->fd_in, e);
13724989c68SBrian Somers       log_Printf(LogTIMER, "prompt %s: fdset(e) %d\n", p->src.from, p->fd_in);
138b6dec9f0SBrian Somers       sets++;
139b6dec9f0SBrian Somers     }
140b6dec9f0SBrian Somers     if (sets && *n < p->fd_in + 1)
141b6dec9f0SBrian Somers       *n = p->fd_in + 1;
14285b542cfSBrian Somers   }
14385b542cfSBrian Somers 
144b6217683SBrian Somers   prompt_Display(p);
145b6217683SBrian Somers 
146b6dec9f0SBrian Somers   return sets;
14785b542cfSBrian Somers }
14885b542cfSBrian Somers 
14985b542cfSBrian Somers static int
1502f786681SBrian Somers prompt_IsSet(struct descriptor *d, const fd_set *fdset)
15185b542cfSBrian Somers {
15285b542cfSBrian Somers   struct prompt *p = descriptor2prompt(d);
15385b542cfSBrian Somers   return p->fd_in >= 0 && FD_ISSET(p->fd_in, fdset);
15485b542cfSBrian Somers }
15585b542cfSBrian Somers 
15685b542cfSBrian Somers 
15785b542cfSBrian Somers static void
15885b542cfSBrian Somers prompt_ShowHelp(struct prompt *p)
15985b542cfSBrian Somers {
160f7704be7SBrian Somers   prompt_Printf(p, "The following commands are available:\n");
161f7704be7SBrian Somers   prompt_Printf(p, " ~p\tEnter Packet mode\n");
162f7704be7SBrian Somers   prompt_Printf(p, " ~t\tShow timers\n");
163f7704be7SBrian Somers   prompt_Printf(p, " ~m\tShow memory map\n");
164f7704be7SBrian Somers   prompt_Printf(p, " ~.\tTerminate program\n");
165f7704be7SBrian Somers   prompt_Printf(p, " ~?\tThis help\n");
16685b542cfSBrian Somers }
16785b542cfSBrian Somers 
16885b542cfSBrian Somers static void
16985b542cfSBrian Somers prompt_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
17085b542cfSBrian Somers {
17185b542cfSBrian Somers   struct prompt *p = descriptor2prompt(d);
17285b542cfSBrian Somers   int n;
17385b542cfSBrian Somers   char ch;
17485b542cfSBrian Somers   char linebuff[LINE_LEN];
17585b542cfSBrian Somers 
1761b35f8f7SBrian Somers   if (p->TermMode == NULL) {
17785b542cfSBrian Somers     n = read(p->fd_in, linebuff, sizeof linebuff - 1);
17885b542cfSBrian Somers     if (n > 0) {
17985b542cfSBrian Somers       if (linebuff[n-1] == '\n')
18085b542cfSBrian Somers         linebuff[--n] = '\0';
18185b542cfSBrian Somers       else
18285b542cfSBrian Somers         linebuff[n] = '\0';
183dd7e2610SBrian Somers       p->nonewline = 1;		/* Maybe command_Decode does a prompt */
184b6217683SBrian Somers       prompt_Required(p);
18585b542cfSBrian Somers       if (n)
186dd7e2610SBrian Somers         command_Decode(bundle, linebuff, n, p, p->src.from);
18785b542cfSBrian Somers     } else if (n <= 0) {
1880f2f3eb3SBrian Somers       log_Printf(LogPHASE, "%s: Client connection closed.\n", p->src.from);
1899dae3e8dSBrian Somers       if (!p->owner)
1909dae3e8dSBrian Somers         Cleanup(EX_NORMAL);
191b6217683SBrian Somers       prompt_Destroy(p, 0);
19285b542cfSBrian Somers     }
19385b542cfSBrian Somers     return;
19485b542cfSBrian Somers   }
19585b542cfSBrian Somers 
196c7cc5030SBrian Somers   switch (p->TermMode->state) {
197c7cc5030SBrian Somers     case DATALINK_CLOSED:
198c7cc5030SBrian Somers       prompt_Printf(p, "Link lost, terminal mode.\n");
199b6217683SBrian Somers       prompt_TtyCommandMode(p);
200b6217683SBrian Somers       p->nonewline = 0;
201b6217683SBrian Somers       prompt_Required(p);
202c7cc5030SBrian Somers       return;
203c7cc5030SBrian Somers 
204c7cc5030SBrian Somers     case DATALINK_READY:
205c7cc5030SBrian Somers       break;
206c7cc5030SBrian Somers 
207c7cc5030SBrian Somers     case DATALINK_OPEN:
208c7cc5030SBrian Somers       prompt_Printf(p, "\nPacket mode detected.\n");
209b6217683SBrian Somers       prompt_TtyCommandMode(p);
210b6217683SBrian Somers       p->nonewline = 0;
211c7cc5030SBrian Somers       /* We'll get a prompt because of our status change */
212c7cc5030SBrian Somers       /* Fall through */
213c7cc5030SBrian Somers 
214c7cc5030SBrian Somers     default:
215c7cc5030SBrian Somers       /* Wait 'till we're in a state we care about */
216c7cc5030SBrian Somers       return;
217c7cc5030SBrian Somers   }
218c7cc5030SBrian Somers 
21985b542cfSBrian Somers   /*
22085b542cfSBrian Somers    * We are in terminal mode, decode special sequences
22185b542cfSBrian Somers    */
22285b542cfSBrian Somers   n = read(p->fd_in, &ch, 1);
223dd7e2610SBrian Somers   log_Printf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n);
22485b542cfSBrian Somers 
22585b542cfSBrian Somers   if (n > 0) {
226d93d3a9cSBrian Somers     switch (p->readtilde) {
22785b542cfSBrian Somers     case 0:
22885b542cfSBrian Somers       if (ch == '~')
229d93d3a9cSBrian Somers         p->readtilde = 1;
23085b542cfSBrian Somers       else
231dd7e2610SBrian Somers 	if (physical_Write(p->TermMode->physical, &ch, n) < 0) {
232a33b2ef7SBrian Somers 	  log_Printf(LogWARN, "error writing to modem: %s\n", strerror(errno));
233833882f7SBrian Somers           prompt_TtyCommandMode(p);
234833882f7SBrian Somers         }
23585b542cfSBrian Somers       break;
23685b542cfSBrian Somers     case 1:
23785b542cfSBrian Somers       switch (ch) {
23885b542cfSBrian Somers       case '?':
23985b542cfSBrian Somers 	prompt_ShowHelp(p);
24085b542cfSBrian Somers 	break;
24185b542cfSBrian Somers       case 'p':
242c7cc5030SBrian Somers         datalink_Up(p->TermMode, 0, 1);
243c7cc5030SBrian Somers         prompt_Printf(p, "\nPacket mode.\n");
244b6217683SBrian Somers 	prompt_TtyCommandMode(p);
24585b542cfSBrian Somers         break;
24685b542cfSBrian Somers       case '.':
247b6217683SBrian Somers 	prompt_TtyCommandMode(p);
248b6217683SBrian Somers         p->nonewline = 0;
249b6217683SBrian Somers         prompt_Required(p);
25085b542cfSBrian Somers 	break;
25185b542cfSBrian Somers       case 't':
252dd7e2610SBrian Somers 	timer_Show(0, p);
25385b542cfSBrian Somers 	break;
25485b542cfSBrian Somers       case 'm':
255f7704be7SBrian Somers         {
256f7704be7SBrian Somers           struct cmdargs arg;
257f7704be7SBrian Somers 
258f7704be7SBrian Somers           arg.cmdtab = NULL;
259f7704be7SBrian Somers           arg.cmd = NULL;
260f7704be7SBrian Somers           arg.argc = 0;
261f7704be7SBrian Somers           arg.argn = 0;
262f7704be7SBrian Somers           arg.argv = NULL;
263f7704be7SBrian Somers           arg.bundle = bundle;
264f7704be7SBrian Somers           arg.cx = p->TermMode;
265f7704be7SBrian Somers           arg.prompt = p;
266f7704be7SBrian Somers 
267f7704be7SBrian Somers 	  mbuf_Show(&arg);
268f7704be7SBrian Somers         }
26985b542cfSBrian Somers 	break;
27085b542cfSBrian Somers       default:
271dd7e2610SBrian Somers 	if (physical_Write(p->TermMode->physical, &ch, n) < 0) {
272a33b2ef7SBrian Somers 	  log_Printf(LogWARN, "error writing to modem: %s\n", strerror(errno));
273833882f7SBrian Somers           prompt_TtyCommandMode(p);
274833882f7SBrian Somers         }
27585b542cfSBrian Somers 	break;
27685b542cfSBrian Somers       }
277d93d3a9cSBrian Somers       p->readtilde = 0;
27885b542cfSBrian Somers       break;
27985b542cfSBrian Somers     }
28085b542cfSBrian Somers   }
28185b542cfSBrian Somers }
28285b542cfSBrian Somers 
2831af29a6eSBrian Somers static int
284f4768038SBrian Somers prompt_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
28585b542cfSBrian Somers {
286f4768038SBrian Somers   /* We never want to write here ! */
287a33b2ef7SBrian Somers   log_Printf(LogALERT, "prompt_Write: Internal error: Bad call !\n");
2881af29a6eSBrian Somers   return 0;
28985b542cfSBrian Somers }
29085b542cfSBrian Somers 
291b6217683SBrian Somers struct prompt *
292b6217683SBrian Somers prompt_Create(struct server *s, struct bundle *bundle, int fd)
29385b542cfSBrian Somers {
294b6217683SBrian Somers   struct prompt *p = (struct prompt *)malloc(sizeof(struct prompt));
29585b542cfSBrian Somers 
296b6217683SBrian Somers   if (p != NULL) {
297b6217683SBrian Somers     p->desc.type = PROMPT_DESCRIPTOR;
298b6217683SBrian Somers     p->desc.UpdateSet = prompt_UpdateSet;
299b6217683SBrian Somers     p->desc.IsSet = prompt_IsSet;
300b6217683SBrian Somers     p->desc.Read = prompt_Read;
301b6217683SBrian Somers     p->desc.Write = prompt_Write;
30285b542cfSBrian Somers 
303b6217683SBrian Somers     if (fd == PROMPT_STD) {
3040f78c7a7SBrian Somers       char *tty = ttyname(STDIN_FILENO);
3050f78c7a7SBrian Somers 
3060f78c7a7SBrian Somers       if (!tty) {
3070f78c7a7SBrian Somers         free(p);
3080f78c7a7SBrian Somers         return NULL;
3090f78c7a7SBrian Somers       }
31085b542cfSBrian Somers       p->fd_in = STDIN_FILENO;
31185b542cfSBrian Somers       p->fd_out = STDOUT_FILENO;
31285b542cfSBrian Somers       p->Term = stdout;
313b6217683SBrian Somers       p->owner = NULL;
314b6217683SBrian Somers       p->auth = LOCAL_AUTH;
315565e35e5SBrian Somers       p->src.type = "Controller";
3160f78c7a7SBrian Somers       strncpy(p->src.from, tty, sizeof p->src.from - 1);
317565e35e5SBrian Somers       p->src.from[sizeof p->src.from - 1] = '\0';
318b6217683SBrian Somers       tcgetattr(p->fd_in, &p->oldtio);	/* Save original tty mode */
31985b542cfSBrian Somers     } else {
32085b542cfSBrian Somers       p->fd_in = p->fd_out = fd;
32185b542cfSBrian Somers       p->Term = fdopen(fd, "a+");
322b6217683SBrian Somers       p->owner = s;
323b6217683SBrian Somers       p->auth = *s->passwd ? LOCAL_NO_AUTH : LOCAL_AUTH;
324565e35e5SBrian Somers       p->src.type = "unknown";
325565e35e5SBrian Somers       *p->src.from = '\0';
32685b542cfSBrian Somers     }
3271b35f8f7SBrian Somers     p->TermMode = NULL;
328b6217683SBrian Somers     p->nonewline = 1;
329b6217683SBrian Somers     p->needprompt = 1;
330d93d3a9cSBrian Somers     p->readtilde = 0;
331b6217683SBrian Somers     p->bundle = bundle;
332b6217683SBrian Somers     log_RegisterPrompt(p);
333b6217683SBrian Somers   }
33485b542cfSBrian Somers 
335b6217683SBrian Somers   return p;
33685b542cfSBrian Somers }
33785b542cfSBrian Somers 
3383006ec67SBrian Somers void
339b6217683SBrian Somers prompt_Destroy(struct prompt *p, int verbose)
34085b542cfSBrian Somers {
3410f78c7a7SBrian Somers   if (p) {
342b6217683SBrian Somers     if (p->Term != stdout) {
343b6217683SBrian Somers       fclose(p->Term);
34485b542cfSBrian Somers       close(p->fd_in);
34585b542cfSBrian Somers       if (p->fd_out != p->fd_in)
34685b542cfSBrian Somers         close(p->fd_out);
34785b542cfSBrian Somers       if (verbose)
3480f2f3eb3SBrian Somers         log_Printf(LogPHASE, "%s: Client connection dropped.\n", p->src.from);
349b6217683SBrian Somers     } else
350b6217683SBrian Somers       prompt_TtyOldMode(p);
351b6217683SBrian Somers 
352565e35e5SBrian Somers     log_UnRegisterPrompt(p);
353565e35e5SBrian Somers     free(p);
35485b542cfSBrian Somers   }
3550f78c7a7SBrian Somers }
35685b542cfSBrian Somers 
35785b542cfSBrian Somers void
35885b542cfSBrian Somers prompt_Printf(struct prompt *p, const char *fmt,...)
35985b542cfSBrian Somers {
360f91ad6b0SBrian Somers   if (p && p->active) {
36185b542cfSBrian Somers     va_list ap;
362f7704be7SBrian Somers 
36385b542cfSBrian Somers     va_start(ap, fmt);
364f7704be7SBrian Somers     prompt_vPrintf(p, fmt, ap);
36585b542cfSBrian Somers     va_end(ap);
36685b542cfSBrian Somers   }
36785b542cfSBrian Somers }
36885b542cfSBrian Somers 
36985b542cfSBrian Somers void
37085b542cfSBrian Somers prompt_vPrintf(struct prompt *p, const char *fmt, va_list ap)
37185b542cfSBrian Somers {
372f91ad6b0SBrian Somers   if (p && p->active) {
373f7704be7SBrian Somers     char nfmt[LINE_LEN];
374f7704be7SBrian Somers     const char *pfmt;
375f7704be7SBrian Somers 
376f7704be7SBrian Somers     if (p->TermMode) {
377f7704be7SBrian Somers       /* Stuff '\r' in front of '\n' 'cos we're in raw mode */
378f7704be7SBrian Somers       int len = strlen(fmt);
379f7704be7SBrian Somers 
380f7704be7SBrian Somers       if (len && len < sizeof nfmt - 1 && fmt[len-1] == '\n') {
381f7704be7SBrian Somers         strcpy(nfmt, fmt);
382f7704be7SBrian Somers         strcpy(nfmt + len - 1, "\r\n");
383f7704be7SBrian Somers         pfmt = nfmt;
384f7704be7SBrian Somers       } else
385f7704be7SBrian Somers         pfmt = fmt;
386f7704be7SBrian Somers     } else
387f7704be7SBrian Somers       pfmt = fmt;
388f7704be7SBrian Somers     vfprintf(p->Term, pfmt, ap);
38985b542cfSBrian Somers     fflush(p->Term);
390c06d604bSBrian Somers     p->nonewline = 1;
39185b542cfSBrian Somers   }
39285b542cfSBrian Somers }
39385b542cfSBrian Somers 
39485b542cfSBrian Somers void
395565e35e5SBrian Somers prompt_TtyInit(struct prompt *p)
39685b542cfSBrian Somers {
397565e35e5SBrian Somers   int stat, fd = p ? p->fd_in : STDIN_FILENO;
398b6217683SBrian Somers   struct termios newtio;
399b6217683SBrian Somers 
400565e35e5SBrian Somers   stat = fcntl(fd, F_GETFL, 0);
401565e35e5SBrian Somers   if (stat > 0) {
402565e35e5SBrian Somers     stat |= O_NONBLOCK;
403565e35e5SBrian Somers     fcntl(fd, F_SETFL, stat);
404565e35e5SBrian Somers   }
405565e35e5SBrian Somers 
406565e35e5SBrian Somers   if (p)
40785b542cfSBrian Somers     newtio = p->oldtio;
408565e35e5SBrian Somers   else
409565e35e5SBrian Somers     tcgetattr(fd, &newtio);
410565e35e5SBrian Somers 
41185b542cfSBrian Somers   newtio.c_lflag &= ~(ECHO | ISIG | ICANON);
41285b542cfSBrian Somers   newtio.c_iflag = 0;
41385b542cfSBrian Somers   newtio.c_oflag &= ~OPOST;
414565e35e5SBrian Somers   if (!p)
41585b542cfSBrian Somers     newtio.c_cc[VINTR] = _POSIX_VDISABLE;
41685b542cfSBrian Somers   newtio.c_cc[VMIN] = 1;
41785b542cfSBrian Somers   newtio.c_cc[VTIME] = 0;
41885b542cfSBrian Somers   newtio.c_cflag |= CS8;
419565e35e5SBrian Somers   tcsetattr(fd, TCSANOW, &newtio);
420565e35e5SBrian Somers   if (p)
42185b542cfSBrian Somers     p->comtio = newtio;
42285b542cfSBrian Somers }
42385b542cfSBrian Somers 
42485b542cfSBrian Somers /*
42585b542cfSBrian Somers  *  Set tty into command mode. We allow canonical input and echo processing.
42685b542cfSBrian Somers  */
42785b542cfSBrian Somers void
42885b542cfSBrian Somers prompt_TtyCommandMode(struct prompt *p)
42985b542cfSBrian Somers {
43085b542cfSBrian Somers   struct termios newtio;
43185b542cfSBrian Somers   int stat;
43285b542cfSBrian Somers 
43385b542cfSBrian Somers   tcgetattr(p->fd_in, &newtio);
43485b542cfSBrian Somers   newtio.c_lflag |= (ECHO | ISIG | ICANON);
43585b542cfSBrian Somers   newtio.c_iflag = p->oldtio.c_iflag;
43685b542cfSBrian Somers   newtio.c_oflag |= OPOST;
43785b542cfSBrian Somers   tcsetattr(p->fd_in, TCSADRAIN, &newtio);
438b6217683SBrian Somers 
43985b542cfSBrian Somers   stat = fcntl(p->fd_in, F_GETFL, 0);
44085b542cfSBrian Somers   if (stat > 0) {
44185b542cfSBrian Somers     stat |= O_NONBLOCK;
442b6217683SBrian Somers     fcntl(p->fd_in, F_SETFL, stat);
44385b542cfSBrian Somers   }
444b6217683SBrian Somers 
4451b35f8f7SBrian Somers   p->TermMode = NULL;
44685b542cfSBrian Somers }
44785b542cfSBrian Somers 
44885b542cfSBrian Somers /*
44985b542cfSBrian Somers  * Set tty into terminal mode which is used while we invoke term command.
45085b542cfSBrian Somers  */
45185b542cfSBrian Somers void
4521b35f8f7SBrian Somers prompt_TtyTermMode(struct prompt *p, struct datalink *dl)
45385b542cfSBrian Somers {
45485b542cfSBrian Somers   int stat;
45585b542cfSBrian Somers 
456b6217683SBrian Somers   prompt_Printf(p, "Entering terminal mode on %s.\n", dl->name);
457b6217683SBrian Somers   prompt_Printf(p, "Type `~?' for help.\n");
458b6217683SBrian Somers 
459b6217683SBrian Somers   if (p->Term == stdout)
46085b542cfSBrian Somers     tcsetattr(p->fd_in, TCSADRAIN, &p->comtio);
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   }
4671b35f8f7SBrian Somers   p->TermMode = dl;
46885b542cfSBrian Somers }
46985b542cfSBrian Somers 
47085b542cfSBrian Somers void
47185b542cfSBrian Somers prompt_TtyOldMode(struct prompt *p)
47285b542cfSBrian Somers {
47385b542cfSBrian Somers   int stat;
47485b542cfSBrian Somers 
47585b542cfSBrian Somers   stat = fcntl(p->fd_in, F_GETFL, 0);
47685b542cfSBrian Somers   if (stat > 0) {
47785b542cfSBrian Somers     stat &= ~O_NONBLOCK;
478b6217683SBrian Somers     fcntl(p->fd_in, F_SETFL, stat);
47985b542cfSBrian Somers   }
480b6217683SBrian Somers 
481b6217683SBrian Somers   if (p->Term == stdout)
48285b542cfSBrian Somers     tcsetattr(p->fd_in, TCSADRAIN, &p->oldtio);
48385b542cfSBrian Somers }
48485b542cfSBrian Somers 
48585b542cfSBrian Somers pid_t
48685b542cfSBrian Somers prompt_pgrp(struct prompt *p)
48785b542cfSBrian Somers {
488b6217683SBrian Somers   return tcgetpgrp(p->fd_in);
489b6217683SBrian Somers }
490b6217683SBrian Somers 
491b6217683SBrian Somers int
492b6217683SBrian Somers PasswdCommand(struct cmdargs const *arg)
493b6217683SBrian Somers {
494b6217683SBrian Somers   const char *pass;
495b6217683SBrian Somers 
496b6217683SBrian Somers   if (!arg->prompt) {
497dd7e2610SBrian Somers     log_Printf(LogWARN, "passwd: Cannot specify without a prompt\n");
498b6217683SBrian Somers     return 0;
499b6217683SBrian Somers   }
500b6217683SBrian Somers 
501b6217683SBrian Somers   if (arg->prompt->owner == NULL) {
502dd7e2610SBrian Somers     log_Printf(LogWARN, "passwd: Not required\n");
503b6217683SBrian Somers     return 0;
504b6217683SBrian Somers   }
505b6217683SBrian Somers 
50625092092SBrian Somers   if (arg->argc == arg->argn)
507b6217683SBrian Somers     pass = "";
50825092092SBrian Somers   else if (arg->argc > arg->argn+1)
509b6217683SBrian Somers     return -1;
510b6217683SBrian Somers   else
51125092092SBrian Somers     pass = arg->argv[arg->argn];
512b6217683SBrian Somers 
513b6217683SBrian Somers   if (!strcmp(arg->prompt->owner->passwd, pass))
514b6217683SBrian Somers     arg->prompt->auth = LOCAL_AUTH;
515b6217683SBrian Somers   else
516b6217683SBrian Somers     arg->prompt->auth = LOCAL_NO_AUTH;
517b6217683SBrian Somers 
518b6217683SBrian Somers   return 0;
51985b542cfSBrian Somers }
520f91ad6b0SBrian Somers 
521f91ad6b0SBrian Somers static struct pppTimer bgtimer;
522f91ad6b0SBrian Somers 
523f91ad6b0SBrian Somers static void
524f91ad6b0SBrian Somers prompt_TimedContinue(void *v)
525f91ad6b0SBrian Somers {
526f91ad6b0SBrian Somers   prompt_Continue((struct prompt *)v);
527f91ad6b0SBrian Somers }
528f91ad6b0SBrian Somers 
529f91ad6b0SBrian Somers void
530f91ad6b0SBrian Somers prompt_Continue(struct prompt *p)
531f91ad6b0SBrian Somers {
532dd7e2610SBrian Somers   timer_Stop(&bgtimer);
533f91ad6b0SBrian Somers   if (getpgrp() == prompt_pgrp(p)) {
534f91ad6b0SBrian Somers     prompt_TtyCommandMode(p);
535f91ad6b0SBrian Somers     p->nonewline = 1;
536f91ad6b0SBrian Somers     prompt_Required(p);
5370f2f3eb3SBrian Somers     log_ActivatePrompt(p);
538f91ad6b0SBrian Somers   } else if (!p->owner) {
539f91ad6b0SBrian Somers     bgtimer.func = prompt_TimedContinue;
540f91ad6b0SBrian Somers     bgtimer.name = "prompt bg";
541f91ad6b0SBrian Somers     bgtimer.load = SECTICKS;
542f91ad6b0SBrian Somers     bgtimer.arg = p;
543dd7e2610SBrian Somers     timer_Start(&bgtimer);
544f91ad6b0SBrian Somers   }
545f91ad6b0SBrian Somers }
546f91ad6b0SBrian Somers 
547f91ad6b0SBrian Somers void
548f91ad6b0SBrian Somers prompt_Suspend(struct prompt *p)
549f91ad6b0SBrian Somers {
550f91ad6b0SBrian Somers   if (getpgrp() == prompt_pgrp(p)) {
551f91ad6b0SBrian Somers     prompt_TtyOldMode(p);
5520f2f3eb3SBrian Somers     log_DeactivatePrompt(p);
553f91ad6b0SBrian Somers   }
554f91ad6b0SBrian Somers }
555