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