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