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