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