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