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