xref: /freebsd/usr.sbin/ppp/command.c (revision 33b77e2decd50e53798014b70bf7ca3bdc4c0c7e)
1 /*
2  *		PPP User command processing module
3  *
4  *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5  *
6  *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7  *
8  * Redistribution and use in source and binary forms are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by the Internet Initiative Japan, Inc.  The name of the
14  * IIJ may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  *
20  * $Id: command.c,v 1.126 1998/01/10 21:51:31 brian Exp $
21  *
22  */
23 #include <sys/param.h>
24 #include <netinet/in_systm.h>
25 #include <netinet/in.h>
26 #include <netinet/ip.h>
27 #include <arpa/inet.h>
28 #include <sys/socket.h>
29 #include <net/route.h>
30 #include <netdb.h>
31 
32 #ifndef NOALIAS
33 #include <alias.h>
34 #endif
35 #include <ctype.h>
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <paths.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <sys/stat.h>
43 #include <sys/wait.h>
44 #include <termios.h>
45 #include <time.h>
46 #include <unistd.h>
47 
48 #include "command.h"
49 #include "mbuf.h"
50 #include "log.h"
51 #include "defs.h"
52 #include "timer.h"
53 #include "fsm.h"
54 #include "phase.h"
55 #include "lcp.h"
56 #include "iplist.h"
57 #include "ipcp.h"
58 #include "modem.h"
59 #include "filter.h"
60 #ifndef NOALIAS
61 #include "alias_cmd.h"
62 #endif
63 #include "hdlc.h"
64 #include "loadalias.h"
65 #include "vars.h"
66 #include "systems.h"
67 #include "chat.h"
68 #include "os.h"
69 #include "server.h"
70 #include "main.h"
71 #include "route.h"
72 #include "ccp.h"
73 #include "ip.h"
74 #include "slcompress.h"
75 #include "auth.h"
76 
77 struct in_addr ifnetmask;
78 static const char *HIDDEN = "********";
79 
80 static int ShowCommand(struct cmdargs const *arg);
81 static int TerminalCommand(struct cmdargs const *arg);
82 static int QuitCommand(struct cmdargs const *arg);
83 static int CloseCommand(struct cmdargs const *arg);
84 static int DialCommand(struct cmdargs const *arg);
85 static int DownCommand(struct cmdargs const *arg);
86 static int AllowCommand(struct cmdargs const *arg);
87 static int SetCommand(struct cmdargs const *arg);
88 static int AddCommand(struct cmdargs const *arg);
89 static int DeleteCommand(struct cmdargs const *arg);
90 static int BgShellCommand(struct cmdargs const *arg);
91 static int FgShellCommand(struct cmdargs const *arg);
92 #ifndef NOALIAS
93 static int AliasCommand(struct cmdargs const *arg);
94 static int AliasEnable(struct cmdargs const *arg);
95 static int AliasOption(struct cmdargs const *arg);
96 #endif
97 
98 static int
99 HelpCommand(struct cmdargs const *arg)
100 {
101   struct cmdtab const *cmd;
102   int n, cmax, dmax, cols;
103 
104   if (!VarTerm)
105     return 0;
106 
107   if (arg->argc > 0) {
108     for (cmd = arg->cmd; cmd->name; cmd++)
109       if (strcasecmp(cmd->name, *arg->argv) == 0 &&
110           (cmd->lauth & VarLocalAuth)) {
111 	fprintf(VarTerm, "%s\n", cmd->syntax);
112 	return 0;
113       }
114     return -1;
115   }
116   cmax = dmax = 0;
117   for (cmd = arg->cmd; cmd->func; cmd++)
118     if (cmd->name && (cmd->lauth & VarLocalAuth)) {
119       if ((n = strlen(cmd->name)) > cmax)
120         cmax = n;
121       if ((n = strlen(cmd->helpmes)) > dmax)
122         dmax = n;
123     }
124 
125   cols = 80 / (dmax + cmax + 3);
126   n = 0;
127   for (cmd = arg->cmd; cmd->func; cmd++)
128     if (cmd->name && (cmd->lauth & VarLocalAuth)) {
129       fprintf(VarTerm, " %-*.*s: %-*.*s",
130               cmax, cmax, cmd->name, dmax, dmax, cmd->helpmes);
131       if (++n % cols == 0)
132         fprintf(VarTerm, "\n");
133     }
134   if (n % cols != 0)
135     fprintf(VarTerm, "\n");
136 
137   return 0;
138 }
139 
140 int
141 IsInteractive(int Display)
142 {
143   const char *mes = NULL;
144 
145   if (mode & MODE_DDIAL)
146     mes = "Working in dedicated dial mode.";
147   else if (mode & MODE_BACKGROUND)
148     mes = "Working in background mode.";
149   else if (mode & MODE_AUTO)
150     mes = "Working in auto mode.";
151   else if (mode & MODE_DIRECT)
152     mes = "Working in direct mode.";
153   else if (mode & MODE_DEDICATED)
154     mes = "Working in dedicated mode.";
155   if (mes) {
156     if (Display && VarTerm)
157       fprintf(VarTerm, "%s\n", mes);
158     return 0;
159   }
160   return 1;
161 }
162 
163 static int
164 DialCommand(struct cmdargs const *arg)
165 {
166   int tries;
167   int res;
168 
169   if (LcpFsm.state > ST_CLOSED) {
170     if (VarTerm)
171       fprintf(VarTerm, "LCP state is [%s]\n", StateNames[LcpFsm.state]);
172     return 0;
173   }
174 
175   if (arg->argc > 0 && (res = LoadCommand(arg)) != 0)
176     return res;
177 
178   tries = 0;
179   do {
180     if (tries) {
181       LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n",
182                 VarRedialNextTimeout);
183       nointr_sleep(VarRedialNextTimeout);
184     }
185     if (VarTerm)
186       fprintf(VarTerm, "Dial attempt %u of %d\n", ++tries, VarDialTries);
187     if (OpenModem() < 0) {
188       if (VarTerm)
189 	fprintf(VarTerm, "Failed to open modem.\n");
190       break;
191     }
192     if ((res = DialModem()) == EX_DONE) {
193       nointr_sleep(1);
194       ModemTimeout(NULL);
195       PacketMode();
196       break;
197     } else if (res == EX_SIG)
198       return 1;
199   } while (VarDialTries == 0 || tries < VarDialTries);
200 
201   return 0;
202 }
203 
204 static int
205 SetLoopback(struct cmdargs const *arg)
206 {
207   if (arg->argc == 1)
208     if (!strcasecmp(*arg->argv, "on")) {
209       VarLoopback = 1;
210       return 0;
211     }
212     else if (!strcasecmp(*arg->argv, "off")) {
213       VarLoopback = 0;
214       return 0;
215     }
216   return -1;
217 }
218 
219 static int
220 ShellCommand(struct cmdargs const *arg, int bg)
221 {
222   const char *shell;
223   pid_t shpid;
224   int argc;
225   char *argv[MAXARGS];
226 
227 #ifdef SHELL_ONLY_INTERACTIVELY
228   /* we're only allowed to shell when we run ppp interactively */
229   if (mode != MODE_INTER) {
230     LogPrintf(LogWARN, "Can only start a shell in interactive mode\n");
231     return 1;
232   }
233 #endif
234 #ifdef NO_SHELL_IN_AUTO_INTERACTIVE
235 
236   /*
237    * we want to stop shell commands when we've got a telnet connection to an
238    * auto mode ppp
239    */
240   if (VarTerm && !(mode & MODE_INTER)) {
241     LogPrintf(LogWARN, "Shell is not allowed interactively in auto mode\n");
242     return 1;
243   }
244 #endif
245 
246   if (arg->argc == 0)
247     if (!(mode & MODE_INTER)) {
248       if (VarTerm)
249         LogPrintf(LogWARN, "Can't start an interactive shell from"
250 		  " a telnet session\n");
251       else
252         LogPrintf(LogWARN, "Can only start an interactive shell in"
253 		  " interactive mode\n");
254       return 1;
255     } else if (bg) {
256       LogPrintf(LogWARN, "Can only start an interactive shell in"
257 		" the foreground mode\n");
258       return 1;
259     }
260   if ((shell = getenv("SHELL")) == 0)
261     shell = _PATH_BSHELL;
262 
263   if ((shpid = fork()) == 0) {
264     int dtablesize, i, fd;
265 
266     TermTimerService();
267     signal(SIGINT, SIG_DFL);
268     signal(SIGQUIT, SIG_DFL);
269     signal(SIGTERM, SIG_DFL);
270     signal(SIGHUP, SIG_DFL);
271     signal(SIGALRM, SIG_DFL);
272 
273     if (VarTerm)
274       fd = fileno(VarTerm);
275     else if ((fd = open("/dev/null", O_RDWR)) == -1) {
276       LogPrintf(LogALERT, "Failed to open /dev/null: %s\n", strerror(errno));
277       exit(1);
278     }
279     for (i = 0; i < 3; i++)
280       dup2(fd, i);
281 
282     for (dtablesize = getdtablesize(), i = 3; i < dtablesize; i++)
283       close(i);
284 
285     TtyOldMode();
286     setuid(geteuid());
287     if (arg->argc > 0) {
288       /* substitute pseudo args */
289       argv[0] = strdup(arg->argv[0]);
290       for (argc = 1; argc < arg->argc; argc++) {
291 	if (strcasecmp(arg->argv[argc], "HISADDR") == 0)
292 	  argv[argc] = strdup(inet_ntoa(IpcpInfo.his_ipaddr));
293 	else if (strcasecmp(arg->argv[argc], "INTERFACE") == 0)
294 	  argv[argc] = strdup(IfDevName);
295 	else if (strcasecmp(arg->argv[argc], "MYADDR") == 0)
296 	  argv[argc] = strdup(inet_ntoa(IpcpInfo.want_ipaddr));
297         else
298           argv[argc] = strdup(arg->argv[argc]);
299       }
300       argv[argc] = NULL;
301       if (bg) {
302 	pid_t p;
303 
304 	p = getpid();
305 	if (daemon(1, 1) == -1) {
306 	  LogPrintf(LogERROR, "%d: daemon: %s\n", p, strerror(errno));
307 	  exit(1);
308 	}
309       } else if (VarTerm)
310         printf("ppp: Pausing until %s finishes\n", arg->argv[0]);
311       execvp(argv[0], argv);
312     } else {
313       if (VarTerm)
314         printf("ppp: Pausing until %s finishes\n", shell);
315       execl(shell, shell, NULL);
316     }
317 
318     LogPrintf(LogWARN, "exec() of %s failed\n",
319               arg->argc > 0 ? arg->argv[0] : shell);
320     exit(255);
321   }
322   if (shpid == (pid_t) - 1) {
323     LogPrintf(LogERROR, "Fork failed: %s\n", strerror(errno));
324   } else {
325     int status;
326 
327     waitpid(shpid, &status, 0);
328   }
329 
330   TtyCommandMode(0);
331 
332   return (0);
333 }
334 
335 static int
336 BgShellCommand(struct cmdargs const *arg)
337 {
338   if (arg->argc == 0)
339     return -1;
340   return ShellCommand(arg, 1);
341 }
342 
343 static int
344 FgShellCommand(struct cmdargs const *arg)
345 {
346   return ShellCommand(arg, 0);
347 }
348 
349 static struct cmdtab const Commands[] = {
350   {"accept", NULL, AcceptCommand, LOCAL_AUTH,
351   "accept option request", "accept option .."},
352   {"add", NULL, AddCommand, LOCAL_AUTH,
353   "add route", "add dest mask gateway", NULL},
354   {"add!", NULL, AddCommand, LOCAL_AUTH,
355   "add or change route", "add! dest mask gateway", (void *)1},
356   {"allow", "auth", AllowCommand, LOCAL_AUTH,
357   "Allow ppp access", "allow users|modes ...."},
358   {"bg", "!bg", BgShellCommand, LOCAL_AUTH,
359   "Run a background command", "[!]bg command"},
360   {"close", NULL, CloseCommand, LOCAL_AUTH,
361   "Close connection", "close"},
362   {"delete", NULL, DeleteCommand, LOCAL_AUTH,
363   "delete route", "delete dest", NULL},
364   {"delete!", NULL, DeleteCommand, LOCAL_AUTH,
365   "delete a route if it exists", "delete! dest", (void *)1},
366   {"deny", NULL, DenyCommand, LOCAL_AUTH,
367   "Deny option request", "deny option .."},
368   {"dial", "call", DialCommand, LOCAL_AUTH,
369   "Dial and login", "dial|call [remote]"},
370   {"disable", NULL, DisableCommand, LOCAL_AUTH,
371   "Disable option", "disable option .."},
372   {"display", NULL, DisplayCommand, LOCAL_AUTH,
373   "Display option configs", "display"},
374   {"enable", NULL, EnableCommand, LOCAL_AUTH,
375   "Enable option", "enable option .."},
376   {"passwd", NULL, LocalAuthCommand, LOCAL_NO_AUTH,
377   "Password for manipulation", "passwd LocalPassword"},
378   {"load", NULL, LoadCommand, LOCAL_AUTH,
379   "Load settings", "load [remote]"},
380   {"save", NULL, SaveCommand, LOCAL_AUTH,
381   "Save settings", "save"},
382   {"set", "setup", SetCommand, LOCAL_AUTH,
383   "Set parameters", "set[up] var value"},
384   {"shell", "!", FgShellCommand, LOCAL_AUTH,
385   "Run a subshell", "shell|! [sh command]"},
386   {"show", NULL, ShowCommand, LOCAL_AUTH,
387   "Show status and stats", "show var"},
388   {"term", NULL, TerminalCommand, LOCAL_AUTH,
389   "Enter terminal mode", "term"},
390 #ifndef NOALIAS
391   {"alias", NULL, AliasCommand, LOCAL_AUTH,
392   "alias control", "alias option [yes|no]"},
393 #endif
394   {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
395   "Quit PPP program", "quit|bye [all]"},
396   {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
397   "Display this message", "help|? [command]", Commands},
398   {NULL, "down", DownCommand, LOCAL_AUTH,
399   "Generate down event", "down"},
400   {NULL, NULL, NULL},
401 };
402 
403 static int
404 ShowLoopback(struct cmdargs const *arg)
405 {
406   if (VarTerm)
407     fprintf(VarTerm, "Local loopback is %s\n", VarLoopback ? "on" : "off");
408 
409   return 0;
410 }
411 
412 static int
413 ShowLogLevel(struct cmdargs const *arg)
414 {
415   int i;
416 
417   if (!VarTerm)
418     return 0;
419 
420   fprintf(VarTerm, "Log:  ");
421   for (i = LogMIN; i <= LogMAX; i++)
422     if (LogIsKept(i) & LOG_KEPT_SYSLOG)
423       fprintf(VarTerm, " %s", LogName(i));
424 
425   fprintf(VarTerm, "\nLocal:");
426   for (i = LogMIN; i <= LogMAX; i++)
427     if (LogIsKept(i) & LOG_KEPT_LOCAL)
428       fprintf(VarTerm, " %s", LogName(i));
429 
430   fprintf(VarTerm, "\n");
431 
432   return 0;
433 }
434 
435 static int
436 ShowEscape(struct cmdargs const *arg)
437 {
438   int code, bit;
439 
440   if (!VarTerm)
441     return 0;
442   if (EscMap[32]) {
443     for (code = 0; code < 32; code++)
444       if (EscMap[code])
445 	for (bit = 0; bit < 8; bit++)
446 	  if (EscMap[code] & (1 << bit))
447 	    fprintf(VarTerm, " 0x%02x", (code << 3) + bit);
448     fprintf(VarTerm, "\n");
449   }
450   return 0;
451 }
452 
453 static int
454 ShowTimeout(struct cmdargs const *arg)
455 {
456   if (VarTerm) {
457     int remaining;
458 
459     fprintf(VarTerm, " Idle Timer: %d secs   LQR Timer: %d secs"
460 	    "   Retry Timer: %d secs\n", VarIdleTimeout, VarLqrTimeout,
461 	    VarRetryTimeout);
462     remaining = RemainingIdleTime();
463     if (remaining != -1)
464     fprintf(VarTerm, " %d secs remaining\n", remaining);
465   }
466   return 0;
467 }
468 
469 static int
470 ShowStopped(struct cmdargs const *arg)
471 {
472   if (!VarTerm)
473     return 0;
474 
475   fprintf(VarTerm, " Stopped Timer:  LCP: ");
476   if (!LcpFsm.StoppedTimer.load)
477     fprintf(VarTerm, "Disabled");
478   else
479     fprintf(VarTerm, "%ld secs", LcpFsm.StoppedTimer.load / SECTICKS);
480 
481   fprintf(VarTerm, ", IPCP: ");
482   if (!IpcpFsm.StoppedTimer.load)
483     fprintf(VarTerm, "Disabled");
484   else
485     fprintf(VarTerm, "%ld secs", IpcpFsm.StoppedTimer.load / SECTICKS);
486 
487   fprintf(VarTerm, ", CCP: ");
488   if (!CcpFsm.StoppedTimer.load)
489     fprintf(VarTerm, "Disabled");
490   else
491     fprintf(VarTerm, "%ld secs", CcpFsm.StoppedTimer.load / SECTICKS);
492 
493   fprintf(VarTerm, "\n");
494 
495   return 0;
496 }
497 
498 static int
499 ShowAuthKey(struct cmdargs const *arg)
500 {
501   if (!VarTerm)
502     return 0;
503   fprintf(VarTerm, "AuthName = %s\n", VarAuthName);
504   fprintf(VarTerm, "AuthKey  = %s\n", HIDDEN);
505 #ifdef HAVE_DES
506   fprintf(VarTerm, "Encrypt  = %s\n", VarMSChap ? "MSChap" : "MD5" );
507 #endif
508   return 0;
509 }
510 
511 static int
512 ShowVersion(struct cmdargs const *arg)
513 {
514   if (VarTerm)
515     fprintf(VarTerm, "%s - %s \n", VarVersion, VarLocalVersion);
516   return 0;
517 }
518 
519 static int
520 ShowInitialMRU(struct cmdargs const *arg)
521 {
522   if (VarTerm)
523     fprintf(VarTerm, " Initial MRU: %d\n", VarMRU);
524   return 0;
525 }
526 
527 static int
528 ShowPreferredMTU(struct cmdargs const *arg)
529 {
530   if (VarTerm)
531     if (VarPrefMTU)
532       fprintf(VarTerm, " Preferred MTU: %d\n", VarPrefMTU);
533     else
534       fprintf(VarTerm, " Preferred MTU: unspecified\n");
535   return 0;
536 }
537 
538 static int
539 ShowReconnect(struct cmdargs const *arg)
540 {
541   if (VarTerm)
542     fprintf(VarTerm, " Reconnect Timer:  %d,  %d tries\n",
543 	    VarReconnectTimer, VarReconnectTries);
544   return 0;
545 }
546 
547 static int
548 ShowRedial(struct cmdargs const *arg)
549 {
550   if (!VarTerm)
551     return 0;
552   fprintf(VarTerm, " Redial Timer: ");
553 
554   if (VarRedialTimeout >= 0) {
555     fprintf(VarTerm, " %d seconds, ", VarRedialTimeout);
556   } else {
557     fprintf(VarTerm, " Random 0 - %d seconds, ", REDIAL_PERIOD);
558   }
559 
560   fprintf(VarTerm, " Redial Next Timer: ");
561 
562   if (VarRedialNextTimeout >= 0) {
563     fprintf(VarTerm, " %d seconds, ", VarRedialNextTimeout);
564   } else {
565     fprintf(VarTerm, " Random 0 - %d seconds, ", REDIAL_PERIOD);
566   }
567 
568   if (VarDialTries)
569     fprintf(VarTerm, "%d dial tries", VarDialTries);
570 
571   fprintf(VarTerm, "\n");
572 
573   return 0;
574 }
575 
576 #ifndef NOMSEXT
577 static int
578 ShowMSExt(struct cmdargs const *arg)
579 {
580   if (VarTerm) {
581     fprintf(VarTerm, " MS PPP extention values \n");
582     fprintf(VarTerm, "   Primary NS     : %s\n", inet_ntoa(ns_entries[0]));
583     fprintf(VarTerm, "   Secondary NS   : %s\n", inet_ntoa(ns_entries[1]));
584     fprintf(VarTerm, "   Primary NBNS   : %s\n", inet_ntoa(nbns_entries[0]));
585     fprintf(VarTerm, "   Secondary NBNS : %s\n", inet_ntoa(nbns_entries[1]));
586   }
587   return 0;
588 }
589 
590 #endif
591 
592 static struct cmdtab const ShowCommands[] = {
593   {"afilter", NULL, ShowAfilter, LOCAL_AUTH,
594   "Show keep-alive filters", "show afilter option .."},
595   {"auth", NULL, ShowAuthKey, LOCAL_AUTH,
596   "Show auth details", "show auth"},
597   {"ccp", NULL, ReportCcpStatus, LOCAL_AUTH,
598   "Show CCP status", "show cpp"},
599   {"compress", NULL, ReportCompress, LOCAL_AUTH,
600   "Show compression stats", "show compress"},
601   {"dfilter", NULL, ShowDfilter, LOCAL_AUTH,
602   "Show Demand filters", "show dfilteroption .."},
603   {"escape", NULL, ShowEscape, LOCAL_AUTH,
604   "Show escape characters", "show escape"},
605   {"hdlc", NULL, ReportHdlcStatus, LOCAL_AUTH,
606   "Show HDLC errors", "show hdlc"},
607   {"ifilter", NULL, ShowIfilter, LOCAL_AUTH,
608   "Show Input filters", "show ifilter option .."},
609   {"ipcp", NULL, ReportIpcpStatus, LOCAL_AUTH,
610   "Show IPCP status", "show ipcp"},
611   {"lcp", NULL, ReportLcpStatus, LOCAL_AUTH,
612   "Show LCP status", "show lcp"},
613   {"loopback", NULL, ShowLoopback, LOCAL_AUTH,
614   "Show loopback setting", "show loopback"},
615   {"log", NULL, ShowLogLevel, LOCAL_AUTH,
616   "Show log levels", "show log"},
617   {"mem", NULL, ShowMemMap, LOCAL_AUTH,
618   "Show memory map", "show mem"},
619   {"modem", NULL, ShowModemStatus, LOCAL_AUTH,
620   "Show modem setups", "show modem"},
621   {"mru", NULL, ShowInitialMRU, LOCAL_AUTH,
622   "Show Initial MRU", "show mru"},
623   {"mtu", NULL, ShowPreferredMTU, LOCAL_AUTH,
624   "Show Preferred MTU", "show mtu"},
625   {"ofilter", NULL, ShowOfilter, LOCAL_AUTH,
626   "Show Output filters", "show ofilter option .."},
627   {"proto", NULL, ReportProtStatus, LOCAL_AUTH,
628   "Show protocol summary", "show proto"},
629   {"reconnect", NULL, ShowReconnect, LOCAL_AUTH,
630   "Show reconnect timer", "show reconnect"},
631   {"redial", NULL, ShowRedial, LOCAL_AUTH,
632   "Show Redial timeout", "show redial"},
633   {"route", NULL, ShowRoute, LOCAL_AUTH,
634   "Show routing table", "show route"},
635   {"timeout", NULL, ShowTimeout, LOCAL_AUTH,
636   "Show Idle timeout", "show timeout"},
637   {"stopped", NULL, ShowStopped, LOCAL_AUTH,
638   "Show STOPPED timeout", "show stopped"},
639 #ifndef NOMSEXT
640   {"msext", NULL, ShowMSExt, LOCAL_AUTH,
641   "Show MS PPP extentions", "show msext"},
642 #endif
643   {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH,
644   "Show version string", "show version"},
645   {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH,
646   "Display this message", "show help|? [command]", ShowCommands},
647   {NULL, NULL, NULL},
648 };
649 
650 static struct cmdtab const *
651 FindCommand(struct cmdtab const *cmds, const char *str, int *pmatch)
652 {
653   int nmatch;
654   int len;
655   struct cmdtab const *found;
656 
657   found = NULL;
658   len = strlen(str);
659   nmatch = 0;
660   while (cmds->func) {
661     if (cmds->name && strncasecmp(str, cmds->name, len) == 0) {
662       if (cmds->name[len] == '\0') {
663 	*pmatch = 1;
664 	return cmds;
665       }
666       nmatch++;
667       found = cmds;
668     } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) {
669       if (cmds->alias[len] == '\0') {
670 	*pmatch = 1;
671 	return cmds;
672       }
673       nmatch++;
674       found = cmds;
675     }
676     cmds++;
677   }
678   *pmatch = nmatch;
679   return found;
680 }
681 
682 static int
683 FindExec(struct cmdtab const *cmds, int argc, char const *const *argv,
684          const char *prefix)
685 {
686   struct cmdtab const *cmd;
687   int val = 1;
688   int nmatch;
689   struct cmdargs arg;
690 
691   cmd = FindCommand(cmds, *argv, &nmatch);
692   if (nmatch > 1)
693     LogPrintf(LogWARN, "%s%s: Ambiguous command\n", prefix, *argv);
694   else if (cmd && (cmd->lauth & VarLocalAuth)) {
695     arg.cmd = cmds;
696     arg.argc = argc-1;
697     arg.argv = argv+1;
698     arg.data = cmd->args;
699     val = (cmd->func) (&arg);
700   } else
701     LogPrintf(LogWARN, "%s%s: Invalid command\n", prefix, *argv);
702 
703   if (val == -1)
704     LogPrintf(LogWARN, "Usage: %s\n", cmd->syntax);
705   else if (val)
706     LogPrintf(LogWARN, "%s%s: Failed %d\n", prefix, *argv, val);
707 
708   return val;
709 }
710 
711 int aft_cmd = 1;
712 
713 void
714 Prompt()
715 {
716   const char *pconnect, *pauth;
717 
718   if (!VarTerm || TermMode)
719     return;
720 
721   if (!aft_cmd)
722     fprintf(VarTerm, "\n");
723   else
724     aft_cmd = 0;
725 
726   if (VarLocalAuth == LOCAL_AUTH)
727     pauth = " ON ";
728   else
729     pauth = " on ";
730   if (IpcpFsm.state == ST_OPENED && phase == PHASE_NETWORK)
731     pconnect = "PPP";
732   else
733     pconnect = "ppp";
734   fprintf(VarTerm, "%s%s%s> ", pconnect, pauth, VarShortHost);
735   fflush(VarTerm);
736 }
737 
738 void
739 InterpretCommand(char *buff, int nb, int *argc, char ***argv)
740 {
741   static char *vector[MAXARGS];
742   char *cp;
743 
744   if (nb > 0) {
745     cp = buff + strcspn(buff, "\r\n");
746     if (cp)
747       *cp = '\0';
748     *argc = MakeArgs(buff, vector, VECSIZE(vector));
749     *argv = vector;
750   } else
751     *argc = 0;
752 }
753 
754 static int
755 arghidden(int argc, char const *const *argv, int n)
756 {
757   /* Is arg n of the given command to be hidden from the log ? */
758 
759   /* set authkey xxxxx */
760   /* set key xxxxx */
761   if (n == 2 && !strncasecmp(argv[0], "se", 2) &&
762       (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2)))
763     return 1;
764 
765   /* passwd xxxxx */
766   if (n == 1 && !strncasecmp(argv[0], "p", 1))
767     return 1;
768 
769   return 0;
770 }
771 
772 void
773 RunCommand(int argc, char const *const *argv, const char *label)
774 {
775   if (argc > 0) {
776     if (LogIsKept(LogCOMMAND)) {
777       static char buf[LINE_LEN];
778       int f, n;
779 
780       *buf = '\0';
781       if (label) {
782         strncpy(buf, label, sizeof buf - 3);
783         buf[sizeof buf - 3] = '\0';
784         strcat(buf, ": ");
785       }
786       n = strlen(buf);
787       for (f = 0; f < argc; f++) {
788         if (n < sizeof buf - 1 && f)
789           buf[n++] = ' ';
790         if (arghidden(argc, argv, f))
791           strncpy(buf+n, HIDDEN, sizeof buf - n - 1);
792         else
793           strncpy(buf+n, argv[f], sizeof buf - n - 1);
794         n += strlen(buf+n);
795       }
796       LogPrintf(LogCOMMAND, "%s\n", buf);
797     }
798     FindExec(Commands, argc, argv, "");
799   }
800 }
801 
802 void
803 DecodeCommand(char *buff, int nb, const char *label)
804 {
805   int argc;
806   char **argv;
807 
808   InterpretCommand(buff, nb, &argc, &argv);
809   RunCommand(argc, (char const *const *)argv, label);
810 }
811 
812 static int
813 ShowCommand(struct cmdargs const *arg)
814 {
815   if (arg->argc > 0)
816     FindExec(ShowCommands, arg->argc, arg->argv, "show ");
817   else if (VarTerm)
818     fprintf(VarTerm, "Use ``show ?'' to get a arg->cmd.\n");
819   else
820     LogPrintf(LogWARN, "show command must have arguments\n");
821 
822   return 0;
823 }
824 
825 static int
826 TerminalCommand(struct cmdargs const *arg)
827 {
828   if (LcpFsm.state > ST_CLOSED) {
829     if (VarTerm)
830       fprintf(VarTerm, "LCP state is [%s]\n", StateNames[LcpFsm.state]);
831     return 1;
832   }
833   if (!IsInteractive(1))
834     return (1);
835   if (OpenModem() < 0) {
836     if (VarTerm)
837       fprintf(VarTerm, "Failed to open modem.\n");
838     return (1);
839   }
840   if (VarTerm) {
841     fprintf(VarTerm, "Enter to terminal mode.\n");
842     fprintf(VarTerm, "Type `~?' for help.\n");
843   }
844   TtyTermMode();
845   return (0);
846 }
847 
848 static int
849 QuitCommand(struct cmdargs const *arg)
850 {
851   if (VarTerm) {
852     DropClient(1);
853     if (mode & MODE_INTER)
854       Cleanup(EX_NORMAL);
855     else if (arg->argc > 0 && !strcasecmp(*arg->argv, "all") && VarLocalAuth&LOCAL_AUTH)
856       Cleanup(EX_NORMAL);
857   }
858 
859   return 0;
860 }
861 
862 static int
863 CloseCommand(struct cmdargs const *arg)
864 {
865   reconnect(RECON_FALSE);
866   LcpClose();
867   return 0;
868 }
869 
870 static int
871 DownCommand(struct cmdargs const *arg)
872 {
873   LcpDown();
874   return 0;
875 }
876 
877 static int
878 SetModemSpeed(struct cmdargs const *arg)
879 {
880   int speed;
881 
882   if (arg->argc > 0) {
883     if (strcasecmp(*arg->argv, "sync") == 0) {
884       VarSpeed = 0;
885       return 0;
886     }
887     speed = atoi(*arg->argv);
888     if (IntToSpeed(speed) != B0) {
889       VarSpeed = speed;
890       return 0;
891     }
892     LogPrintf(LogWARN, "%s: Invalid speed\n", *arg->argv);
893   }
894   return -1;
895 }
896 
897 static int
898 SetReconnect(struct cmdargs const *arg)
899 {
900   if (arg->argc == 2) {
901     VarReconnectTimer = atoi(arg->argv[0]);
902     VarReconnectTries = atoi(arg->argv[1]);
903     return 0;
904   }
905   return -1;
906 }
907 
908 static int
909 SetRedialTimeout(struct cmdargs const *arg)
910 {
911   int timeout;
912   int tries;
913   char *dot;
914 
915   if (arg->argc == 1 || arg->argc == 2) {
916     if (strncasecmp(arg->argv[0], "random", 6) == 0 &&
917 	(arg->argv[0][6] == '\0' || arg->argv[0][6] == '.')) {
918       VarRedialTimeout = -1;
919       randinit();
920     } else {
921       timeout = atoi(arg->argv[0]);
922 
923       if (timeout >= 0)
924 	VarRedialTimeout = timeout;
925       else {
926 	LogPrintf(LogWARN, "Invalid redial timeout\n");
927 	return -1;
928       }
929     }
930 
931     dot = strchr(arg->argv[0], '.');
932     if (dot) {
933       if (strcasecmp(++dot, "random") == 0) {
934 	VarRedialNextTimeout = -1;
935 	randinit();
936       } else {
937 	timeout = atoi(dot);
938 	if (timeout >= 0)
939 	  VarRedialNextTimeout = timeout;
940 	else {
941 	  LogPrintf(LogWARN, "Invalid next redial timeout\n");
942 	  return -1;
943 	}
944       }
945     } else
946       VarRedialNextTimeout = NEXT_REDIAL_PERIOD;	/* Default next timeout */
947 
948     if (arg->argc == 2) {
949       tries = atoi(arg->argv[1]);
950 
951       if (tries >= 0) {
952 	VarDialTries = tries;
953       } else {
954 	LogPrintf(LogWARN, "Invalid retry value\n");
955 	return 1;
956       }
957     }
958     return 0;
959   }
960   return -1;
961 }
962 
963 static int
964 SetStoppedTimeout(struct cmdargs const *arg)
965 {
966   LcpFsm.StoppedTimer.load = 0;
967   IpcpFsm.StoppedTimer.load = 0;
968   CcpFsm.StoppedTimer.load = 0;
969   if (arg->argc <= 3) {
970     if (arg->argc > 0) {
971       LcpFsm.StoppedTimer.load = atoi(arg->argv[0]) * SECTICKS;
972       if (arg->argc > 1) {
973 	IpcpFsm.StoppedTimer.load = atoi(arg->argv[1]) * SECTICKS;
974 	if (arg->argc > 2)
975 	  CcpFsm.StoppedTimer.load = atoi(arg->argv[2]) * SECTICKS;
976       }
977     }
978     return 0;
979   }
980   return -1;
981 }
982 
983 #define ismask(x) \
984   (*x == '0' && strlen(x) == 4 && strspn(x+1, "0123456789.") == 3)
985 
986 static int
987 SetServer(struct cmdargs const *arg)
988 {
989   int res = -1;
990 
991   if (arg->argc > 0 && arg->argc < 4) {
992     const char *port, *passwd, *mask;
993 
994     /* What's what ? */
995     port = arg->argv[0];
996     if (arg->argc == 2)
997       if (ismask(arg->argv[1])) {
998         passwd = NULL;
999         mask = arg->argv[1];
1000       } else {
1001         passwd = arg->argv[1];
1002         mask = NULL;
1003       }
1004     else if (arg->argc == 3) {
1005       passwd = arg->argv[1];
1006       mask = arg->argv[2];
1007       if (!ismask(mask))
1008         return -1;
1009     } else
1010       passwd = mask = NULL;
1011 
1012     if (passwd == NULL)
1013       VarHaveLocalAuthKey = 0;
1014     else {
1015       strncpy(VarLocalAuthKey, passwd, sizeof VarLocalAuthKey - 1);
1016       VarLocalAuthKey[sizeof VarLocalAuthKey - 1] = '\0';
1017       VarHaveLocalAuthKey = 1;
1018     }
1019     LocalAuthInit();
1020 
1021     if (strcasecmp(port, "none") == 0) {
1022       int oserver;
1023 
1024       if (mask != NULL || passwd != NULL)
1025         return -1;
1026       oserver = server;
1027       ServerClose();
1028       if (oserver != -1)
1029         LogPrintf(LogPHASE, "Disabling server port.\n");
1030       res = 0;
1031     } else if (*port == '/') {
1032       mode_t imask;
1033 
1034       if (mask != NULL) {
1035 	unsigned m;
1036 
1037 	if (sscanf(mask, "%o", &m) == 1)
1038 	  imask = m;
1039         else
1040           return -1;
1041       } else
1042         imask = (mode_t)-1;
1043       res = ServerLocalOpen(port, imask);
1044     } else {
1045       int iport;
1046 
1047       if (mask != NULL)
1048         return -1;
1049 
1050       if (strspn(port, "0123456789") != strlen(port)) {
1051         struct servent *s;
1052 
1053         if ((s = getservbyname(port, "tcp")) == NULL) {
1054 	  iport = 0;
1055 	  LogPrintf(LogWARN, "%s: Invalid port or service\n", port);
1056 	} else
1057 	  iport = ntohs(s->s_port);
1058       } else
1059         iport = atoi(port);
1060       res = iport ? ServerTcpOpen(iport) : -1;
1061     }
1062   }
1063 
1064   return res;
1065 }
1066 
1067 static int
1068 SetModemParity(struct cmdargs const *arg)
1069 {
1070   return arg->argc > 0 ? ChangeParity(*arg->argv) : -1;
1071 }
1072 
1073 static int
1074 SetLogLevel(struct cmdargs const *arg)
1075 {
1076   int i;
1077   int res;
1078   int argc;
1079   char const *const *argv, *argp;
1080   void (*Discard)(int), (*Keep)(int);
1081   void (*DiscardAll)(void);
1082 
1083   argc = arg->argc;
1084   argv = arg->argv;
1085   res = 0;
1086   if (argc == 0 || strcasecmp(argv[0], "local")) {
1087     Discard = LogDiscard;
1088     Keep = LogKeep;
1089     DiscardAll = LogDiscardAll;
1090   } else {
1091     argc--;
1092     argv++;
1093     Discard = LogDiscardLocal;
1094     Keep = LogKeepLocal;
1095     DiscardAll = LogDiscardAllLocal;
1096   }
1097 
1098   if (argc == 0 || (argv[0][0] != '+' && argv[0][0] != '-'))
1099     DiscardAll();
1100   while (argc--) {
1101     argp = **argv == '+' || **argv == '-' ? *argv + 1 : *argv;
1102     for (i = LogMIN; i <= LogMAX; i++)
1103       if (strcasecmp(argp, LogName(i)) == 0) {
1104 	if (**argv == '-')
1105 	  (*Discard)(i);
1106 	else
1107 	  (*Keep)(i);
1108 	break;
1109       }
1110     if (i > LogMAX) {
1111       LogPrintf(LogWARN, "%s: Invalid log value\n", argp);
1112       res = -1;
1113     }
1114     argv++;
1115   }
1116   return res;
1117 }
1118 
1119 static int
1120 SetEscape(struct cmdargs const *arg)
1121 {
1122   int code;
1123   int argc = arg->argc;
1124   char const *const *argv = arg->argv;
1125 
1126   for (code = 0; code < 33; code++)
1127     EscMap[code] = 0;
1128 
1129   while (argc-- > 0) {
1130     sscanf(*argv++, "%x", &code);
1131     code &= 0xff;
1132     EscMap[code >> 3] |= (1 << (code & 7));
1133     EscMap[32] = 1;
1134   }
1135   return 0;
1136 }
1137 
1138 static int
1139 SetInitialMRU(struct cmdargs const *arg)
1140 {
1141   long mru;
1142   const char *err;
1143 
1144   if (arg->argc > 0) {
1145     mru = atol(*arg->argv);
1146     if (mru < MIN_MRU)
1147       err = "Given MRU value (%ld) is too small.\n";
1148     else if (mru > MAX_MRU)
1149       err = "Given MRU value (%ld) is too big.\n";
1150     else {
1151       VarMRU = mru;
1152       return 0;
1153     }
1154     LogPrintf(LogWARN, err, mru);
1155   }
1156   return -1;
1157 }
1158 
1159 static int
1160 SetPreferredMTU(struct cmdargs const *arg)
1161 {
1162   long mtu;
1163   const char *err;
1164 
1165   if (arg->argc > 0) {
1166     mtu = atol(*arg->argv);
1167     if (mtu == 0) {
1168       VarPrefMTU = 0;
1169       return 0;
1170     } else if (mtu < MIN_MTU)
1171       err = "Given MTU value (%ld) is too small.\n";
1172     else if (mtu > MAX_MTU)
1173       err = "Given MTU value (%ld) is too big.\n";
1174     else {
1175       VarPrefMTU = mtu;
1176       return 0;
1177     }
1178     LogPrintf(LogWARN, err, mtu);
1179   }
1180   return -1;
1181 }
1182 
1183 static int
1184 SetIdleTimeout(struct cmdargs const *arg)
1185 {
1186   if (arg->argc > 0) {
1187     VarIdleTimeout = atoi(arg->argv[0]);
1188     UpdateIdleTimer();		/* If we're connected, restart the idle timer */
1189     if (arg->argc > 1) {
1190       VarLqrTimeout = atoi(arg->argv[1]);
1191       if (VarLqrTimeout < 1)
1192 	VarLqrTimeout = 30;
1193       if (arg->argc > 2) {
1194 	VarRetryTimeout = atoi(arg->argv[2]);
1195 	if (VarRetryTimeout < 1 || VarRetryTimeout > 10)
1196 	  VarRetryTimeout = 3;
1197       }
1198     }
1199     return 0;
1200   }
1201   return -1;
1202 }
1203 
1204 static struct in_addr
1205 GetIpAddr(const char *cp)
1206 {
1207   struct hostent *hp;
1208   struct in_addr ipaddr;
1209 
1210   if (inet_aton(cp, &ipaddr) == 0) {
1211     hp = gethostbyname(cp);
1212     if (hp && hp->h_addrtype == AF_INET)
1213       memcpy(&ipaddr, hp->h_addr, hp->h_length);
1214     else
1215       ipaddr.s_addr = 0;
1216   }
1217   return (ipaddr);
1218 }
1219 
1220 static int
1221 SetInterfaceAddr(struct cmdargs const *arg)
1222 {
1223   const char *hisaddr;
1224 
1225   hisaddr = NULL;
1226   DefMyAddress.ipaddr.s_addr = DefHisAddress.ipaddr.s_addr = 0L;
1227 
1228   if (arg->argc > 4)
1229     return -1;
1230 
1231   HaveTriggerAddress = 0;
1232   ifnetmask.s_addr = 0;
1233   iplist_reset(&DefHisChoice);
1234 
1235   if (arg->argc > 0) {
1236     if (!ParseAddr(arg->argc, arg->argv, &DefMyAddress.ipaddr,
1237 		   &DefMyAddress.mask, &DefMyAddress.width))
1238       return 1;
1239     if (arg->argc > 1) {
1240       hisaddr = arg->argv[1];
1241       if (arg->argc > 2) {
1242 	ifnetmask = GetIpAddr(arg->argv[2]);
1243 	if (arg->argc > 3) {
1244 	  TriggerAddress = GetIpAddr(arg->argv[3]);
1245 	  HaveTriggerAddress = 1;
1246 	}
1247       }
1248     }
1249   }
1250 
1251   /*
1252    * For backwards compatibility, 0.0.0.0 means any address.
1253    */
1254   if (DefMyAddress.ipaddr.s_addr == 0) {
1255     DefMyAddress.mask.s_addr = 0;
1256     DefMyAddress.width = 0;
1257   }
1258   IpcpInfo.want_ipaddr.s_addr = DefMyAddress.ipaddr.s_addr;
1259   if (DefHisAddress.ipaddr.s_addr == 0) {
1260     DefHisAddress.mask.s_addr = 0;
1261     DefHisAddress.width = 0;
1262   }
1263 
1264   if (hisaddr && !UseHisaddr(hisaddr, mode & MODE_AUTO))
1265     return 4;
1266 
1267   return 0;
1268 }
1269 
1270 #ifndef NOMSEXT
1271 
1272 static void
1273 SetMSEXT(struct in_addr * pri_addr,
1274 	 struct in_addr * sec_addr,
1275 	 int argc,
1276 	 char const *const *argv)
1277 {
1278   int dummyint;
1279   struct in_addr dummyaddr;
1280 
1281   pri_addr->s_addr = sec_addr->s_addr = 0L;
1282 
1283   if (argc > 0) {
1284     ParseAddr(argc, argv++, pri_addr, &dummyaddr, &dummyint);
1285     if (--argc > 0)
1286       ParseAddr(argc, argv++, sec_addr, &dummyaddr, &dummyint);
1287     else
1288       sec_addr->s_addr = pri_addr->s_addr;
1289   }
1290 
1291   /*
1292    * if the primary/secondary ns entries are 0.0.0.0 we should set them to
1293    * either the localhost's ip, or the values in /etc/resolv.conf ??
1294    *
1295    * up to you if you want to implement this...
1296    */
1297 
1298 }
1299 
1300 static int
1301 SetNS(struct cmdargs const *arg)
1302 {
1303   SetMSEXT(&ns_entries[0], &ns_entries[1], arg->argc, arg->argv);
1304   return 0;
1305 }
1306 
1307 static int
1308 SetNBNS(struct cmdargs const *arg)
1309 {
1310   SetMSEXT(&nbns_entries[0], &nbns_entries[1], arg->argc, arg->argv);
1311   return 0;
1312 }
1313 
1314 #endif				/* MS_EXT */
1315 
1316 int
1317 SetVariable(struct cmdargs const *arg)
1318 {
1319   u_long map;
1320   const char *argp;
1321   int param = (int)arg->data;
1322 
1323   if (arg->argc > 0)
1324     argp = *arg->argv;
1325   else
1326     argp = "";
1327 
1328   switch (param) {
1329   case VAR_AUTHKEY:
1330     strncpy(VarAuthKey, argp, sizeof VarAuthKey - 1);
1331     VarAuthKey[sizeof VarAuthKey - 1] = '\0';
1332     break;
1333   case VAR_AUTHNAME:
1334     strncpy(VarAuthName, argp, sizeof VarAuthName - 1);
1335     VarAuthName[sizeof VarAuthName - 1] = '\0';
1336     break;
1337   case VAR_DIAL:
1338     strncpy(VarDialScript, argp, sizeof VarDialScript - 1);
1339     VarDialScript[sizeof VarDialScript - 1] = '\0';
1340     break;
1341   case VAR_LOGIN:
1342     strncpy(VarLoginScript, argp, sizeof VarLoginScript - 1);
1343     VarLoginScript[sizeof VarLoginScript - 1] = '\0';
1344     break;
1345   case VAR_DEVICE:
1346     if (mode & MODE_INTER)
1347       HangupModem(0);
1348     if (modem != -1)
1349       LogPrintf(LogWARN, "Cannot change device to \"%s\" when \"%s\" is open\n",
1350                 argp, VarDevice);
1351     else {
1352       strncpy(VarDeviceList, argp, sizeof VarDeviceList - 1);
1353       VarDeviceList[sizeof VarDeviceList - 1] = '\0';
1354     }
1355     break;
1356   case VAR_ACCMAP:
1357     sscanf(argp, "%lx", &map);
1358     VarAccmap = map;
1359     break;
1360   case VAR_PHONE:
1361     strncpy(VarPhoneList, argp, sizeof VarPhoneList - 1);
1362     VarPhoneList[sizeof VarPhoneList - 1] = '\0';
1363     strncpy(VarPhoneCopy, VarPhoneList, sizeof VarPhoneCopy - 1);
1364     VarPhoneCopy[sizeof VarPhoneCopy - 1] = '\0';
1365     VarNextPhone = VarPhoneCopy;
1366     VarAltPhone = NULL;
1367     break;
1368   case VAR_HANGUP:
1369     strncpy(VarHangupScript, argp, sizeof VarHangupScript - 1);
1370     VarHangupScript[sizeof VarHangupScript - 1] = '\0';
1371     break;
1372 #ifdef HAVE_DES
1373   case VAR_ENC:
1374     VarMSChap = !strcasecmp(argp, "mschap");
1375     break;
1376 #endif
1377   }
1378   return 0;
1379 }
1380 
1381 static int
1382 SetCtsRts(struct cmdargs const *arg)
1383 {
1384   if (arg->argc > 0) {
1385     if (strcmp(*arg->argv, "on") == 0)
1386       VarCtsRts = 1;
1387     else if (strcmp(*arg->argv, "off") == 0)
1388       VarCtsRts = 0;
1389     else
1390       return -1;
1391     return 0;
1392   }
1393   return -1;
1394 }
1395 
1396 
1397 static int
1398 SetOpenMode(struct cmdargs const *arg)
1399 {
1400   if (arg->argc > 0) {
1401     if (strcmp(*arg->argv, "active") == 0)
1402       VarOpenMode = OPEN_ACTIVE;
1403     else if (strcmp(*arg->argv, "passive") == 0)
1404       VarOpenMode = OPEN_PASSIVE;
1405     else
1406       return -1;
1407     return 0;
1408   }
1409   return -1;
1410 }
1411 
1412 static struct cmdtab const SetCommands[] = {
1413   {"accmap", NULL, SetVariable, LOCAL_AUTH,
1414   "Set accmap value", "set accmap hex-value", (const void *) VAR_ACCMAP},
1415   {"afilter", NULL, SetAfilter, LOCAL_AUTH,
1416   "Set keep Alive filter", "set afilter ..."},
1417   {"authkey", "key", SetVariable, LOCAL_AUTH,
1418   "Set authentication key", "set authkey|key key", (const void *) VAR_AUTHKEY},
1419   {"authname", NULL, SetVariable, LOCAL_AUTH,
1420   "Set authentication name", "set authname name", (const void *) VAR_AUTHNAME},
1421   {"ctsrts", NULL, SetCtsRts, LOCAL_AUTH,
1422   "Use CTS/RTS modem signalling", "set ctsrts [on|off]"},
1423   {"device", "line", SetVariable, LOCAL_AUTH, "Set modem device name",
1424   "set device|line device-name[,device-name]", (const void *) VAR_DEVICE},
1425   {"dfilter", NULL, SetDfilter, LOCAL_AUTH,
1426   "Set demand filter", "set dfilter ..."},
1427   {"dial", NULL, SetVariable, LOCAL_AUTH,
1428   "Set dialing script", "set dial chat-script", (const void *) VAR_DIAL},
1429 #ifdef HAVE_DES
1430   {"encrypt", NULL, SetVariable, LOCAL_AUTH, "Set CHAP encryption algorithm",
1431   "set encrypt MSChap|MD5", (const void *) VAR_ENC},
1432 #endif
1433   {"escape", NULL, SetEscape, LOCAL_AUTH,
1434   "Set escape characters", "set escape hex-digit ..."},
1435   {"hangup", NULL, SetVariable, LOCAL_AUTH,
1436   "Set hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
1437   {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "Set destination address",
1438   "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"},
1439   {"ifilter", NULL, SetIfilter, LOCAL_AUTH,
1440   "Set input filter", "set ifilter ..."},
1441   {"loopback", NULL, SetLoopback, LOCAL_AUTH,
1442   "Set loopback facility", "set loopback on|off"},
1443   {"log", NULL, SetLogLevel, LOCAL_AUTH,
1444   "Set log level", "set log [local] [+|-]value..."},
1445   {"login", NULL, SetVariable, LOCAL_AUTH,
1446   "Set login script", "set login chat-script", (const void *) VAR_LOGIN},
1447   {"mru", NULL, SetInitialMRU, LOCAL_AUTH,
1448   "Set Initial MRU value", "set mru value"},
1449   {"mtu", NULL, SetPreferredMTU, LOCAL_AUTH,
1450   "Set Preferred MTU value", "set mtu value"},
1451   {"ofilter", NULL, SetOfilter, LOCAL_AUTH,
1452   "Set output filter", "set ofilter ..."},
1453   {"openmode", NULL, SetOpenMode, LOCAL_AUTH,
1454   "Set open mode", "set openmode [active|passive]"},
1455   {"parity", NULL, SetModemParity, LOCAL_AUTH,
1456   "Set modem parity", "set parity [odd|even|none]"},
1457   {"phone", NULL, SetVariable, LOCAL_AUTH, "Set telephone number(s)",
1458   "set phone phone1[:phone2[...]]", (const void *) VAR_PHONE},
1459   {"reconnect", NULL, SetReconnect, LOCAL_AUTH,
1460   "Set Reconnect timeout", "set reconnect value ntries"},
1461   {"redial", NULL, SetRedialTimeout, LOCAL_AUTH, "Set Redial timeout",
1462   "set redial value|random[.value|random] [dial_attempts]"},
1463   {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH, "Set STOPPED timeouts",
1464   "set stopped [LCPseconds [IPCPseconds [CCPseconds]]]"},
1465   {"server", "socket", SetServer, LOCAL_AUTH,
1466   "Set server port", "set server|socket TcpPort|LocalName|none [mask]"},
1467   {"speed", NULL, SetModemSpeed, LOCAL_AUTH,
1468   "Set modem speed", "set speed value"},
1469   {"timeout", NULL, SetIdleTimeout, LOCAL_AUTH,
1470   "Set Idle timeout", "set timeout value"},
1471 #ifndef NOMSEXT
1472   {"ns", NULL, SetNS, LOCAL_AUTH,
1473   "Set NameServer", "set ns pri-addr [sec-addr]"},
1474   {"nbns", NULL, SetNBNS, LOCAL_AUTH,
1475   "Set NetBIOS NameServer", "set nbns pri-addr [sec-addr]"},
1476 #endif
1477   {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
1478   "Display this message", "set help|? [command]", SetCommands},
1479   {NULL, NULL, NULL},
1480 };
1481 
1482 static int
1483 SetCommand(struct cmdargs const *arg)
1484 {
1485   if (arg->argc > 0)
1486     FindExec(SetCommands, arg->argc, arg->argv, "set ");
1487   else if (VarTerm)
1488     fprintf(VarTerm, "Use `set ?' to get a arg->cmd or `set ? <var>' for"
1489 	    " syntax help.\n");
1490   else
1491     LogPrintf(LogWARN, "set command must have arguments\n");
1492 
1493   return 0;
1494 }
1495 
1496 
1497 static int
1498 AddCommand(struct cmdargs const *arg)
1499 {
1500   struct in_addr dest, gateway, netmask;
1501   int gw;
1502 
1503   if (arg->argc != 3 && arg->argc != 2)
1504     return -1;
1505 
1506   if (arg->argc == 2)
1507     if (strcasecmp(arg->argv[0], "default"))
1508       return -1;
1509     else {
1510       dest.s_addr = netmask.s_addr = INADDR_ANY;
1511       gw = 1;
1512     }
1513   else {
1514     if (strcasecmp(arg->argv[0], "MYADDR") == 0)
1515       dest = IpcpInfo.want_ipaddr;
1516     else if (strcasecmp(arg->argv[0], "HISADDR") == 0)
1517       dest = IpcpInfo.his_ipaddr;
1518     else
1519       dest = GetIpAddr(arg->argv[0]);
1520     netmask = GetIpAddr(arg->argv[1]);
1521     gw = 2;
1522   }
1523   if (strcasecmp(arg->argv[gw], "HISADDR") == 0)
1524     gateway = IpcpInfo.his_ipaddr;
1525   else if (strcasecmp(arg->argv[gw], "INTERFACE") == 0)
1526     gateway.s_addr = INADDR_ANY;
1527   else
1528     gateway = GetIpAddr(arg->argv[gw]);
1529   OsSetRoute(RTM_ADD, dest, gateway, netmask, arg->data ? 1 : 0);
1530   return 0;
1531 }
1532 
1533 static int
1534 DeleteCommand(struct cmdargs const *arg)
1535 {
1536   struct in_addr dest, none;
1537 
1538   if (arg->argc == 1)
1539     if(strcasecmp(arg->argv[0], "all") == 0)
1540       DeleteIfRoutes(0);
1541     else {
1542       if (strcasecmp(arg->argv[0], "MYADDR") == 0)
1543         dest = IpcpInfo.want_ipaddr;
1544       else if (strcasecmp(arg->argv[0], "default") == 0)
1545         dest.s_addr = INADDR_ANY;
1546       else
1547         dest = GetIpAddr(arg->argv[0]);
1548       none.s_addr = INADDR_ANY;
1549       OsSetRoute(RTM_DELETE, dest, none, none, arg->data ? 1 : 0);
1550     }
1551   else
1552     return -1;
1553 
1554   return 0;
1555 }
1556 
1557 #ifndef NOALIAS
1558 static struct cmdtab const AliasCommands[] =
1559 {
1560   {"enable", NULL, AliasEnable, LOCAL_AUTH,
1561   "enable IP aliasing", "alias enable [yes|no]"},
1562   {"port", NULL, AliasRedirectPort, LOCAL_AUTH,
1563   "port redirection", "alias port [proto addr_local:port_local  port_alias]"},
1564   {"addr", NULL, AliasRedirectAddr, LOCAL_AUTH,
1565   "static address translation", "alias addr [addr_local addr_alias]"},
1566   {"deny_incoming", NULL, AliasOption, LOCAL_AUTH,
1567     "stop incoming connections", "alias deny_incoming [yes|no]",
1568   (const void *) PKT_ALIAS_DENY_INCOMING},
1569   {"log", NULL, AliasOption, LOCAL_AUTH,
1570     "log aliasing link creation", "alias log [yes|no]",
1571   (const void *) PKT_ALIAS_LOG},
1572   {"same_ports", NULL, AliasOption, LOCAL_AUTH,
1573     "try to leave port numbers unchanged", "alias same_ports [yes|no]",
1574   (const void *) PKT_ALIAS_SAME_PORTS},
1575   {"use_sockets", NULL, AliasOption, LOCAL_AUTH,
1576     "allocate host sockets", "alias use_sockets [yes|no]",
1577   (const void *) PKT_ALIAS_USE_SOCKETS},
1578   {"unregistered_only", NULL, AliasOption, LOCAL_AUTH,
1579     "alias unregistered (private) IP address space only",
1580     "alias unregistered_only [yes|no]",
1581   (const void *) PKT_ALIAS_UNREGISTERED_ONLY},
1582   {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
1583     "Display this message", "alias help|? [command]", AliasCommands},
1584   {NULL, NULL, NULL},
1585 };
1586 
1587 
1588 static int
1589 AliasCommand(struct cmdargs const *arg)
1590 {
1591   if (arg->argc > 0)
1592     FindExec(AliasCommands, arg->argc, arg->argv, "alias ");
1593   else if (VarTerm)
1594     fprintf(VarTerm, "Use `alias help' to get a arg->cmd or `alias help <option>'"
1595 	    " for syntax help.\n");
1596   else
1597     LogPrintf(LogWARN, "alias command must have arguments\n");
1598 
1599   return 0;
1600 }
1601 
1602 static int
1603 AliasEnable(struct cmdargs const *arg)
1604 {
1605   if (arg->argc == 1)
1606     if (strcasecmp(arg->argv[0], "yes") == 0) {
1607       if (!(mode & MODE_ALIAS)) {
1608 	if (loadAliasHandlers(&VarAliasHandlers) == 0) {
1609 	  mode |= MODE_ALIAS;
1610 	  return 0;
1611 	}
1612 	LogPrintf(LogWARN, "Cannot load alias library\n");
1613 	return 1;
1614       }
1615       return 0;
1616     } else if (strcasecmp(arg->argv[0], "no") == 0) {
1617       if (mode & MODE_ALIAS) {
1618 	unloadAliasHandlers();
1619 	mode &= ~MODE_ALIAS;
1620       }
1621       return 0;
1622     }
1623   return -1;
1624 }
1625 
1626 
1627 static int
1628 AliasOption(struct cmdargs const *arg)
1629 {
1630   unsigned param = (unsigned)arg->data;
1631   if (arg->argc == 1)
1632     if (strcasecmp(arg->argv[0], "yes") == 0) {
1633       if (mode & MODE_ALIAS) {
1634 	VarPacketAliasSetMode(param, param);
1635 	return 0;
1636       }
1637       LogPrintf(LogWARN, "alias not enabled\n");
1638     } else if (strcmp(arg->argv[0], "no") == 0) {
1639       if (mode & MODE_ALIAS) {
1640 	VarPacketAliasSetMode(0, param);
1641 	return 0;
1642       }
1643       LogPrintf(LogWARN, "alias not enabled\n");
1644     }
1645   return -1;
1646 }
1647 #endif /* #ifndef NOALIAS */
1648 
1649 static struct cmdtab const AllowCommands[] = {
1650   {"users", "user", AllowUsers, LOCAL_AUTH,
1651   "Allow users access to ppp", "allow users logname..."},
1652   {"modes", "mode", AllowModes, LOCAL_AUTH,
1653   "Only allow certain ppp modes", "allow modes mode..."},
1654   {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
1655   "Display this message", "allow help|? [command]", AllowCommands},
1656   {NULL, NULL, NULL},
1657 };
1658 
1659 static int
1660 AllowCommand(struct cmdargs const *arg)
1661 {
1662   if (arg->argc > 0)
1663     FindExec(AllowCommands, arg->argc, arg->argv, "allow ");
1664   else if (VarTerm)
1665     fprintf(VarTerm, "Use `allow ?' to get a arg->cmd or `allow ? <cmd>' for"
1666 	    " syntax help.\n");
1667   else
1668     LogPrintf(LogWARN, "allow command must have arguments\n");
1669 
1670   return 0;
1671 }
1672