command.c revision 31858
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.114 1997/12/18 01:10:13 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      DefMyAddress.ipaddr.s_addr = DefHisAddress.ipaddr.s_addr = 0L;
1265      return 4;
1266    }
1267  }
1268
1269  return 0;
1270}
1271
1272#ifndef NOMSEXT
1273
1274static void
1275SetMSEXT(struct in_addr * pri_addr,
1276	 struct in_addr * sec_addr,
1277	 int argc,
1278	 char const *const *argv)
1279{
1280  int dummyint;
1281  struct in_addr dummyaddr;
1282
1283  pri_addr->s_addr = sec_addr->s_addr = 0L;
1284
1285  if (argc > 0) {
1286    ParseAddr(argc, argv++, pri_addr, &dummyaddr, &dummyint);
1287    if (--argc > 0)
1288      ParseAddr(argc, argv++, sec_addr, &dummyaddr, &dummyint);
1289    else
1290      sec_addr->s_addr = pri_addr->s_addr;
1291  }
1292
1293  /*
1294   * if the primary/secondary ns entries are 0.0.0.0 we should set them to
1295   * either the localhost's ip, or the values in /etc/resolv.conf ??
1296   *
1297   * up to you if you want to implement this...
1298   */
1299
1300}
1301
1302static int
1303SetNS(struct cmdargs const *arg)
1304{
1305  SetMSEXT(&ns_entries[0], &ns_entries[1], arg->argc, arg->argv);
1306  return 0;
1307}
1308
1309static int
1310SetNBNS(struct cmdargs const *arg)
1311{
1312  SetMSEXT(&nbns_entries[0], &nbns_entries[1], arg->argc, arg->argv);
1313  return 0;
1314}
1315
1316#endif				/* MS_EXT */
1317
1318int
1319SetVariable(struct cmdargs const *arg)
1320{
1321  u_long map;
1322  const char *argp;
1323  int param = (int)arg->data;
1324
1325  if (arg->argc > 0)
1326    argp = *arg->argv;
1327  else
1328    argp = "";
1329
1330  switch (param) {
1331  case VAR_AUTHKEY:
1332    strncpy(VarAuthKey, argp, sizeof(VarAuthKey) - 1);
1333    VarAuthKey[sizeof(VarAuthKey) - 1] = '\0';
1334    break;
1335  case VAR_AUTHNAME:
1336    strncpy(VarAuthName, argp, sizeof(VarAuthName) - 1);
1337    VarAuthName[sizeof(VarAuthName) - 1] = '\0';
1338    break;
1339  case VAR_DIAL:
1340    strncpy(VarDialScript, argp, sizeof(VarDialScript) - 1);
1341    VarDialScript[sizeof(VarDialScript) - 1] = '\0';
1342    break;
1343  case VAR_LOGIN:
1344    strncpy(VarLoginScript, argp, sizeof(VarLoginScript) - 1);
1345    VarLoginScript[sizeof(VarLoginScript) - 1] = '\0';
1346    break;
1347  case VAR_DEVICE:
1348    if (modem != -1)
1349      LogPrintf(LogWARN, "Cannot change device to \"%s\" when \"%s\" is open\n",
1350                argp, VarDevice);
1351    else {
1352      strncpy(VarDevice, argp, sizeof(VarDevice) - 1);
1353      VarDevice[sizeof(VarDevice) - 1] = '\0';
1354      VarBaseDevice = strrchr(VarDevice, '/');
1355      VarBaseDevice = VarBaseDevice ? VarBaseDevice + 1 : "";
1356    }
1357    break;
1358  case VAR_ACCMAP:
1359    sscanf(argp, "%lx", &map);
1360    VarAccmap = map;
1361    break;
1362  case VAR_PHONE:
1363    strncpy(VarPhoneList, argp, sizeof(VarPhoneList) - 1);
1364    VarPhoneList[sizeof(VarPhoneList) - 1] = '\0';
1365    strncpy(VarPhoneCopy, VarPhoneList, sizeof(VarPhoneCopy));
1366    VarPhoneCopy[sizeof(VarPhoneCopy) - 1] = '\0';
1367    VarNextPhone = VarPhoneCopy;
1368    VarAltPhone = NULL;
1369    break;
1370  case VAR_HANGUP:
1371    strncpy(VarHangupScript, argp, sizeof(VarHangupScript) - 1);
1372    VarHangupScript[sizeof(VarHangupScript) - 1] = '\0';
1373    break;
1374#ifdef HAVE_DES
1375  case VAR_ENC:
1376    VarMSChap = !strcasecmp(argp, "mschap");
1377    break;
1378#endif
1379  }
1380  return 0;
1381}
1382
1383static int
1384SetCtsRts(struct cmdargs const *arg)
1385{
1386  if (arg->argc > 0) {
1387    if (strcmp(*arg->argv, "on") == 0)
1388      VarCtsRts = 1;
1389    else if (strcmp(*arg->argv, "off") == 0)
1390      VarCtsRts = 0;
1391    else
1392      return -1;
1393    return 0;
1394  }
1395  return -1;
1396}
1397
1398
1399static int
1400SetOpenMode(struct cmdargs const *arg)
1401{
1402  if (arg->argc > 0) {
1403    if (strcmp(*arg->argv, "active") == 0)
1404      VarOpenMode = OPEN_ACTIVE;
1405    else if (strcmp(*arg->argv, "passive") == 0)
1406      VarOpenMode = OPEN_PASSIVE;
1407    else
1408      return -1;
1409    return 0;
1410  }
1411  return -1;
1412}
1413
1414static struct cmdtab const SetCommands[] = {
1415  {"accmap", NULL, SetVariable, LOCAL_AUTH,
1416  "Set accmap value", "set accmap hex-value", (const void *) VAR_ACCMAP},
1417  {"afilter", NULL, SetAfilter, LOCAL_AUTH,
1418  "Set keep Alive filter", "set afilter ..."},
1419  {"authkey", "key", SetVariable, LOCAL_AUTH,
1420  "Set authentication key", "set authkey|key key", (const void *) VAR_AUTHKEY},
1421  {"authname", NULL, SetVariable, LOCAL_AUTH,
1422  "Set authentication name", "set authname name", (const void *) VAR_AUTHNAME},
1423  {"ctsrts", NULL, SetCtsRts, LOCAL_AUTH,
1424  "Use CTS/RTS modem signalling", "set ctsrts [on|off]"},
1425  {"device", "line", SetVariable, LOCAL_AUTH, "Set modem device name",
1426  "set device|line device-name", (const void *) VAR_DEVICE},
1427  {"dfilter", NULL, SetDfilter, LOCAL_AUTH,
1428  "Set demand filter", "set dfilter ..."},
1429  {"dial", NULL, SetVariable, LOCAL_AUTH,
1430  "Set dialing script", "set dial chat-script", (const void *) VAR_DIAL},
1431#ifdef HAVE_DES
1432  {"encrypt", NULL, SetVariable, LOCAL_AUTH, "Set CHAP encryption algorithm",
1433  "set encrypt MSChap|MD5", (const void *) VAR_ENC},
1434#endif
1435  {"escape", NULL, SetEscape, LOCAL_AUTH,
1436  "Set escape characters", "set escape hex-digit ..."},
1437  {"hangup", NULL, SetVariable, LOCAL_AUTH,
1438  "Set hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
1439  {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "Set destination address",
1440  "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"},
1441  {"ifilter", NULL, SetIfilter, LOCAL_AUTH,
1442  "Set input filter", "set ifilter ..."},
1443  {"loopback", NULL, SetLoopback, LOCAL_AUTH,
1444  "Set loopback facility", "set loopback on|off"},
1445  {"log", NULL, SetLogLevel, LOCAL_AUTH,
1446  "Set log level", "set log [local] [+|-]value..."},
1447  {"login", NULL, SetVariable, LOCAL_AUTH,
1448  "Set login script", "set login chat-script", (const void *) VAR_LOGIN},
1449  {"mru", NULL, SetInitialMRU, LOCAL_AUTH,
1450  "Set Initial MRU value", "set mru value"},
1451  {"mtu", NULL, SetPreferredMTU, LOCAL_AUTH,
1452  "Set Preferred MTU value", "set mtu value"},
1453  {"ofilter", NULL, SetOfilter, LOCAL_AUTH,
1454  "Set output filter", "set ofilter ..."},
1455  {"openmode", NULL, SetOpenMode, LOCAL_AUTH,
1456  "Set open mode", "set openmode [active|passive]"},
1457  {"parity", NULL, SetModemParity, LOCAL_AUTH,
1458  "Set modem parity", "set parity [odd|even|none]"},
1459  {"phone", NULL, SetVariable, LOCAL_AUTH, "Set telephone number(s)",
1460  "set phone phone1[:phone2[...]]", (const void *) VAR_PHONE},
1461  {"reconnect", NULL, SetReconnect, LOCAL_AUTH,
1462  "Set Reconnect timeout", "set reconnect value ntries"},
1463  {"redial", NULL, SetRedialTimeout, LOCAL_AUTH, "Set Redial timeout",
1464  "set redial value|random[.value|random] [dial_attempts]"},
1465  {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH, "Set STOPPED timeouts",
1466  "set stopped [LCPseconds [IPCPseconds [CCPseconds]]]"},
1467  {"server", "socket", SetServer, LOCAL_AUTH,
1468  "Set server port", "set server|socket TcpPort|LocalName|none [mask]"},
1469  {"speed", NULL, SetModemSpeed, LOCAL_AUTH,
1470  "Set modem speed", "set speed value"},
1471  {"timeout", NULL, SetIdleTimeout, LOCAL_AUTH,
1472  "Set Idle timeout", "set timeout value"},
1473#ifndef NOMSEXT
1474  {"ns", NULL, SetNS, LOCAL_AUTH,
1475  "Set NameServer", "set ns pri-addr [sec-addr]"},
1476  {"nbns", NULL, SetNBNS, LOCAL_AUTH,
1477  "Set NetBIOS NameServer", "set nbns pri-addr [sec-addr]"},
1478#endif
1479  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
1480  "Display this message", "set help|? [command]", SetCommands},
1481  {NULL, NULL, NULL},
1482};
1483
1484static int
1485SetCommand(struct cmdargs const *arg)
1486{
1487  if (arg->argc > 0)
1488    FindExec(SetCommands, arg->argc, arg->argv, "set ");
1489  else if (VarTerm)
1490    fprintf(VarTerm, "Use `set ?' to get a arg->cmd or `set ? <var>' for"
1491	    " syntax help.\n");
1492  else
1493    LogPrintf(LogWARN, "set command must have arguments\n");
1494
1495  return 0;
1496}
1497
1498
1499static int
1500AddCommand(struct cmdargs const *arg)
1501{
1502  struct in_addr dest, gateway, netmask;
1503  int gw;
1504
1505  if (arg->argc != 3 && arg->argc != 2)
1506    return -1;
1507
1508  if (arg->argc == 2)
1509    if (strcasecmp(arg->argv[0], "default"))
1510      return -1;
1511    else {
1512      dest.s_addr = netmask.s_addr = INADDR_ANY;
1513      gw = 1;
1514    }
1515  else {
1516    if (strcasecmp(arg->argv[0], "MYADDR") == 0)
1517      dest = IpcpInfo.want_ipaddr;
1518    else
1519      dest = GetIpAddr(arg->argv[0]);
1520    netmask = GetIpAddr(arg->argv[1]);
1521    gw = 2;
1522  }
1523  if (strcasecmp(arg->argv[gw], "HISADDR") == 0)
1524    gateway = IpcpInfo.his_ipaddr;
1525  else if (strcasecmp(arg->argv[gw], "INTERFACE") == 0)
1526    gateway.s_addr = INADDR_ANY;
1527  else
1528    gateway = GetIpAddr(arg->argv[gw]);
1529  OsSetRoute(RTM_ADD, dest, gateway, netmask);
1530  return 0;
1531}
1532
1533static int
1534DeleteCommand(struct cmdargs const *arg)
1535{
1536  struct in_addr dest, none;
1537
1538  if (arg->argc == 1)
1539    if(strcasecmp(arg->argv[0], "all") == 0)
1540      DeleteIfRoutes(0);
1541    else {
1542      if (strcasecmp(arg->argv[0], "MYADDR") == 0)
1543        dest = IpcpInfo.want_ipaddr;
1544      else if (strcasecmp(arg->argv[0], "default") == 0)
1545        dest.s_addr = INADDR_ANY;
1546      else
1547        dest = GetIpAddr(arg->argv[0]);
1548      none.s_addr = INADDR_ANY;
1549      OsSetRoute(RTM_DELETE, dest, none, none);
1550    }
1551  else
1552    return -1;
1553
1554  return 0;
1555}
1556
1557#ifndef NOALIAS
1558static struct cmdtab const AliasCommands[] =
1559{
1560  {"enable", NULL, AliasEnable, LOCAL_AUTH,
1561  "enable IP aliasing", "alias enable [yes|no]"},
1562  {"port", NULL, AliasRedirectPort, LOCAL_AUTH,
1563  "port redirection", "alias port [proto addr_local:port_local  port_alias]"},
1564  {"addr", NULL, AliasRedirectAddr, LOCAL_AUTH,
1565  "static address translation", "alias addr [addr_local addr_alias]"},
1566  {"deny_incoming", NULL, AliasOption, LOCAL_AUTH,
1567    "stop incoming connections", "alias deny_incoming [yes|no]",
1568  (const void *) PKT_ALIAS_DENY_INCOMING},
1569  {"log", NULL, AliasOption, LOCAL_AUTH,
1570    "log aliasing link creation", "alias log [yes|no]",
1571  (const void *) PKT_ALIAS_LOG},
1572  {"same_ports", NULL, AliasOption, LOCAL_AUTH,
1573    "try to leave port numbers unchanged", "alias same_ports [yes|no]",
1574  (const void *) PKT_ALIAS_SAME_PORTS},
1575  {"use_sockets", NULL, AliasOption, LOCAL_AUTH,
1576    "allocate host sockets", "alias use_sockets [yes|no]",
1577  (const void *) PKT_ALIAS_USE_SOCKETS},
1578  {"unregistered_only", NULL, AliasOption, LOCAL_AUTH,
1579    "alias unregistered (private) IP address space only",
1580    "alias unregistered_only [yes|no]",
1581  (const void *) PKT_ALIAS_UNREGISTERED_ONLY},
1582  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
1583    "Display this message", "alias help|? [command]", AliasCommands},
1584  {NULL, NULL, NULL},
1585};
1586
1587
1588static int
1589AliasCommand(struct cmdargs const *arg)
1590{
1591  if (arg->argc > 0)
1592    FindExec(AliasCommands, arg->argc, arg->argv, "alias ");
1593  else if (VarTerm)
1594    fprintf(VarTerm, "Use `alias help' to get a arg->cmd or `alias help <option>'"
1595	    " for syntax help.\n");
1596  else
1597    LogPrintf(LogWARN, "alias command must have arguments\n");
1598
1599  return 0;
1600}
1601
1602static int
1603AliasEnable(struct cmdargs const *arg)
1604{
1605  if (arg->argc == 1)
1606    if (strcasecmp(arg->argv[0], "yes") == 0) {
1607      if (!(mode & MODE_ALIAS)) {
1608	if (loadAliasHandlers(&VarAliasHandlers) == 0) {
1609	  mode |= MODE_ALIAS;
1610	  return 0;
1611	}
1612	LogPrintf(LogWARN, "Cannot load alias library\n");
1613	return 1;
1614      }
1615      return 0;
1616    } else if (strcasecmp(arg->argv[0], "no") == 0) {
1617      if (mode & MODE_ALIAS) {
1618	unloadAliasHandlers();
1619	mode &= ~MODE_ALIAS;
1620      }
1621      return 0;
1622    }
1623  return -1;
1624}
1625
1626
1627static int
1628AliasOption(struct cmdargs const *arg)
1629{
1630  unsigned param = (unsigned)arg->data;
1631  if (arg->argc == 1)
1632    if (strcasecmp(arg->argv[0], "yes") == 0) {
1633      if (mode & MODE_ALIAS) {
1634	VarPacketAliasSetMode(param, param);
1635	return 0;
1636      }
1637      LogPrintf(LogWARN, "alias not enabled\n");
1638    } else if (strcmp(arg->argv[0], "no") == 0) {
1639      if (mode & MODE_ALIAS) {
1640	VarPacketAliasSetMode(0, param);
1641	return 0;
1642      }
1643      LogPrintf(LogWARN, "alias not enabled\n");
1644    }
1645  return -1;
1646}
1647#endif /* #ifndef NOALIAS */
1648
1649static struct cmdtab const AllowCommands[] = {
1650  {"users", "user", AllowUsers, LOCAL_AUTH,
1651  "Allow users access to ppp", "allow users logname..."},
1652  {"modes", "mode", AllowModes, LOCAL_AUTH,
1653  "Only allow certain ppp modes", "allow modes mode..."},
1654  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
1655  "Display this message", "allow help|? [command]", AllowCommands},
1656  {NULL, NULL, NULL},
1657};
1658
1659static int
1660AllowCommand(struct cmdargs const *arg)
1661{
1662  if (arg->argc > 0)
1663    FindExec(AllowCommands, arg->argc, arg->argv, "allow ");
1664  else if (VarTerm)
1665    fprintf(VarTerm, "Use `allow ?' to get a arg->cmd or `allow ? <cmd>' for"
1666	    " syntax help.\n");
1667  else
1668    LogPrintf(LogWARN, "allow command must have arguments\n");
1669
1670  return 0;
1671}
1672