xref: /freebsd/usr.sbin/ppp/command.c (revision 11afcc8f9f96d657b8e6f7547c02c1957331fc96)
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.157 1998/07/29 18:21:13 brian Exp $
21  *
22  */
23 #include <sys/types.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 #include <sys/un.h>
32 
33 #ifndef NOALIAS
34 #include <alias.h>
35 #endif
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/wait.h>
43 #include <termios.h>
44 #include <unistd.h>
45 
46 #include "defs.h"
47 #include "command.h"
48 #include "mbuf.h"
49 #include "log.h"
50 #include "timer.h"
51 #include "fsm.h"
52 #include "lcp.h"
53 #include "iplist.h"
54 #include "throughput.h"
55 #include "slcompress.h"
56 #include "ipcp.h"
57 #include "modem.h"
58 #ifndef NOALIAS
59 #include "alias_cmd.h"
60 #endif
61 #include "lqr.h"
62 #include "hdlc.h"
63 #include "systems.h"
64 #include "filter.h"
65 #include "descriptor.h"
66 #include "main.h"
67 #include "route.h"
68 #include "ccp.h"
69 #include "auth.h"
70 #include "async.h"
71 #include "link.h"
72 #include "physical.h"
73 #include "mp.h"
74 #include "bundle.h"
75 #include "server.h"
76 #include "prompt.h"
77 #include "chat.h"
78 #include "chap.h"
79 #include "datalink.h"
80 
81 /* ``set'' values */
82 #define	VAR_AUTHKEY	0
83 #define	VAR_DIAL	1
84 #define	VAR_LOGIN	2
85 #define	VAR_AUTHNAME	3
86 #define	VAR_AUTOLOAD	4
87 #define	VAR_WINSIZE	5
88 #define	VAR_DEVICE	6
89 #define	VAR_ACCMAP	7
90 #define	VAR_MRRU	8
91 #define	VAR_MRU		9
92 #define	VAR_MTU		10
93 #define	VAR_OPENMODE	11
94 #define	VAR_PHONE	12
95 #define	VAR_HANGUP	13
96 #define	VAR_IDLETIMEOUT	14
97 #define	VAR_LQRPERIOD	15
98 #define	VAR_LCPRETRY	16
99 #define	VAR_CHAPRETRY	17
100 #define	VAR_PAPRETRY	18
101 #define	VAR_CCPRETRY	19
102 #define	VAR_IPCPRETRY	20
103 #define	VAR_DNS		21
104 #define	VAR_NBNS	22
105 #define	VAR_MODE	23
106 
107 /* ``accept|deny|disable|enable'' masks */
108 #define NEG_HISMASK (1)
109 #define NEG_MYMASK (2)
110 
111 /* ``accept|deny|disable|enable'' values */
112 #define NEG_ACFCOMP	40
113 #define NEG_CHAP	41
114 #define NEG_DEFLATE	42
115 #define NEG_LQR		43
116 #define NEG_PAP		44
117 #define NEG_PPPDDEFLATE	45
118 #define NEG_PRED1	46
119 #define NEG_PROTOCOMP	47
120 #define NEG_SHORTSEQ	48
121 #define NEG_VJCOMP	49
122 #define NEG_DNS		50
123 
124 const char Version[] = "2.0";
125 const char VersionDate[] = "$Date: 1998/07/29 18:21:13 $";
126 
127 static int ShowCommand(struct cmdargs const *);
128 static int TerminalCommand(struct cmdargs const *);
129 static int QuitCommand(struct cmdargs const *);
130 static int OpenCommand(struct cmdargs const *);
131 static int CloseCommand(struct cmdargs const *);
132 static int DownCommand(struct cmdargs const *);
133 static int AllowCommand(struct cmdargs const *);
134 static int SetCommand(struct cmdargs const *);
135 static int LinkCommand(struct cmdargs const *);
136 static int AddCommand(struct cmdargs const *);
137 static int DeleteCommand(struct cmdargs const *);
138 static int NegotiateCommand(struct cmdargs const *);
139 static int ClearCommand(struct cmdargs const *);
140 #ifndef NOALIAS
141 static int AliasCommand(struct cmdargs const *);
142 static int AliasEnable(struct cmdargs const *);
143 static int AliasOption(struct cmdargs const *);
144 #endif
145 
146 static const char *
147 showcx(struct cmdtab const *cmd)
148 {
149   if (cmd->lauth & LOCAL_CX)
150     return "(c)";
151   else if (cmd->lauth & LOCAL_CX_OPT)
152     return "(o)";
153 
154   return "";
155 }
156 
157 static int
158 HelpCommand(struct cmdargs const *arg)
159 {
160   struct cmdtab const *cmd;
161   int n, cmax, dmax, cols, cxlen;
162   const char *cx;
163 
164   if (!arg->prompt) {
165     log_Printf(LogWARN, "help: Cannot help without a prompt\n");
166     return 0;
167   }
168 
169   if (arg->argc > arg->argn) {
170     for (cmd = arg->cmdtab; cmd->name || cmd->alias; cmd++)
171       if ((cmd->lauth & arg->prompt->auth) &&
172           ((cmd->name && !strcasecmp(cmd->name, arg->argv[arg->argn])) ||
173            (cmd->alias && !strcasecmp(cmd->alias, arg->argv[arg->argn])))) {
174 	prompt_Printf(arg->prompt, "%s %s\n", cmd->syntax, showcx(cmd));
175 	return 0;
176       }
177     return -1;
178   }
179 
180   cmax = dmax = 0;
181   for (cmd = arg->cmdtab; cmd->func; cmd++)
182     if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
183       if ((n = strlen(cmd->name) + strlen(showcx(cmd))) > cmax)
184         cmax = n;
185       if ((n = strlen(cmd->helpmes)) > dmax)
186         dmax = n;
187     }
188 
189   cols = 80 / (dmax + cmax + 3);
190   n = 0;
191   prompt_Printf(arg->prompt, "(o) = Optional context,"
192                 " (c) = Context required\n");
193   for (cmd = arg->cmdtab; cmd->func; cmd++)
194     if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
195       cx = showcx(cmd);
196       cxlen = cmax - strlen(cmd->name);
197       prompt_Printf(arg->prompt, " %s%-*.*s: %-*.*s",
198               cmd->name, cxlen, cxlen, cx, dmax, dmax, cmd->helpmes);
199       if (++n % cols == 0)
200         prompt_Printf(arg->prompt, "\n");
201     }
202   if (n % cols != 0)
203     prompt_Printf(arg->prompt, "\n");
204 
205   return 0;
206 }
207 
208 static int
209 CloneCommand(struct cmdargs const *arg)
210 {
211   char namelist[LINE_LEN];
212   char *name;
213   int f;
214 
215   if (arg->argc == arg->argn)
216     return -1;
217 
218   namelist[sizeof namelist - 1] = '\0';
219   for (f = arg->argn; f < arg->argc; f++) {
220     strncpy(namelist, arg->argv[f], sizeof namelist - 1);
221     for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
222       bundle_DatalinkClone(arg->bundle, arg->cx, name);
223   }
224 
225   return 0;
226 }
227 
228 static int
229 RemoveCommand(struct cmdargs const *arg)
230 {
231   if (arg->argc != arg->argn)
232     return -1;
233 
234   if (arg->cx->state != DATALINK_CLOSED) {
235     log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n");
236     return 2;
237   }
238 
239   bundle_DatalinkRemove(arg->bundle, arg->cx);
240   return 0;
241 }
242 
243 static int
244 RenameCommand(struct cmdargs const *arg)
245 {
246   if (arg->argc != arg->argn + 1)
247     return -1;
248 
249   if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn]))
250     return 0;
251 
252   log_Printf(LogWARN, "%s -> %s: target name already exists\n",
253              arg->cx->name, arg->argv[arg->argn]);
254   return 1;
255 }
256 
257 int
258 LoadCommand(struct cmdargs const *arg)
259 {
260   const char *name;
261 
262   if (arg->argc > arg->argn)
263     name = arg->argv[arg->argn];
264   else
265     name = "default";
266 
267   if (!system_IsValid(name, arg->prompt, arg->bundle->phys_type.all)) {
268     log_Printf(LogWARN, "%s: Label not allowed\n", name);
269     return 1;
270   } else {
271     /*
272      * Set the label before & after so that `set enddisc' works and
273      * we handle nested `load' commands.
274      */
275     bundle_SetLabel(arg->bundle, arg->argc > arg->argn ? name : NULL);
276     if (system_Select(arg->bundle, name, CONFFILE, arg->prompt, arg->cx) < 0) {
277       bundle_SetLabel(arg->bundle, NULL);
278       log_Printf(LogWARN, "%s: label not found.\n", name);
279       return -1;
280     }
281     bundle_SetLabel(arg->bundle, arg->argc > arg->argn ? name : NULL);
282   }
283   return 0;
284 }
285 
286 int
287 SaveCommand(struct cmdargs const *arg)
288 {
289   log_Printf(LogWARN, "save command is not implemented (yet).\n");
290   return 1;
291 }
292 
293 static int
294 DialCommand(struct cmdargs const *arg)
295 {
296   int res;
297 
298   if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO)))
299       || (!arg->cx &&
300           (arg->bundle->phys_type.all & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) {
301     log_Printf(LogWARN, "Manual dial is only available for auto and"
302               " interactive links\n");
303     return 1;
304   }
305 
306   if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0)
307     return res;
308 
309   bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
310 
311   return 0;
312 }
313 
314 static int
315 ShellCommand(struct cmdargs const *arg, int bg)
316 {
317   const char *shell;
318   pid_t shpid;
319   int argc;
320   char *argv[MAXARGS];
321 
322 #ifdef SHELL_ONLY_INTERACTIVELY
323   /* we're only allowed to shell when we run ppp interactively */
324   if (arg->prompt && arg->prompt->owner) {
325     log_Printf(LogWARN, "Can't start a shell from a network connection\n");
326     return 1;
327   }
328 #endif
329 
330   if (arg->argc == arg->argn) {
331     if (!arg->prompt) {
332       log_Printf(LogWARN, "Can't start an interactive shell from"
333                 " a config file\n");
334       return 1;
335     } else if (arg->prompt->owner) {
336       log_Printf(LogWARN, "Can't start an interactive shell from"
337                 " a socket connection\n");
338       return 1;
339     } else if (bg) {
340       log_Printf(LogWARN, "Can only start an interactive shell in"
341 		" the foreground mode\n");
342       return 1;
343     }
344   }
345 
346   if ((shpid = fork()) == 0) {
347     int i, fd;
348 
349     if ((shell = getenv("SHELL")) == 0)
350       shell = _PATH_BSHELL;
351 
352     timer_TermService();
353 
354     if (arg->prompt)
355       fd = arg->prompt->fd_out;
356     else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
357       log_Printf(LogALERT, "Failed to open %s: %s\n",
358                 _PATH_DEVNULL, strerror(errno));
359       exit(1);
360     }
361     for (i = 0; i < 3; i++)
362       dup2(fd, i);
363 
364     fcntl(3, F_SETFD, 1);	/* Set close-on-exec flag */
365 
366     setuid(geteuid());
367     if (arg->argc > arg->argn) {
368       /* substitute pseudo args */
369       argv[0] = strdup(arg->argv[arg->argn]);
370       for (argc = 1; argc < arg->argc - arg->argn; argc++) {
371 	if (strcasecmp(arg->argv[argc + arg->argn], "HISADDR") == 0)
372 	  argv[argc] = strdup(inet_ntoa(arg->bundle->ncp.ipcp.peer_ip));
373 	else if (strcasecmp(arg->argv[argc + arg->argn], "INTERFACE") == 0)
374 	  argv[argc] = strdup(arg->bundle->ifp.Name);
375 	else if (strcasecmp(arg->argv[argc + arg->argn], "MYADDR") == 0)
376 	  argv[argc] = strdup(inet_ntoa(arg->bundle->ncp.ipcp.my_ip));
377         else
378           argv[argc] = strdup(arg->argv[argc + arg->argn]);
379       }
380       argv[argc] = NULL;
381       if (bg) {
382 	pid_t p;
383 
384 	p = getpid();
385 	if (daemon(1, 1) == -1) {
386 	  log_Printf(LogERROR, "%d: daemon: %s\n", (int)p, strerror(errno));
387 	  exit(1);
388 	}
389       } else if (arg->prompt)
390         printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]);
391       execvp(argv[0], argv);
392     } else {
393       if (arg->prompt)
394         printf("ppp: Pausing until %s finishes\n", shell);
395       prompt_TtyOldMode(arg->prompt);
396       execl(shell, shell, NULL);
397     }
398 
399     log_Printf(LogWARN, "exec() of %s failed\n",
400               arg->argc > arg->argn ? arg->argv[arg->argn] : shell);
401     exit(255);
402   }
403 
404   if (shpid == (pid_t) - 1)
405     log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno));
406   else {
407     int status;
408     waitpid(shpid, &status, 0);
409   }
410 
411   if (arg->prompt && !arg->prompt->owner)
412     prompt_TtyCommandMode(arg->prompt);
413 
414   return 0;
415 }
416 
417 static int
418 BgShellCommand(struct cmdargs const *arg)
419 {
420   if (arg->argc == arg->argn)
421     return -1;
422   return ShellCommand(arg, 1);
423 }
424 
425 static int
426 FgShellCommand(struct cmdargs const *arg)
427 {
428   return ShellCommand(arg, 0);
429 }
430 
431 static struct cmdtab const Commands[] = {
432   {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
433   "accept option request", "accept option .."},
434   {"add", NULL, AddCommand, LOCAL_AUTH,
435   "add route", "add dest mask gateway", NULL},
436   {NULL, "add!", AddCommand, LOCAL_AUTH,
437   "add or change route", "add! dest mask gateway", (void *)1},
438 #ifndef NOALIAS
439   {"alias", NULL, AliasCommand, LOCAL_AUTH,
440   "alias control", "alias option [yes|no]"},
441 #endif
442   {"allow", "auth", AllowCommand, LOCAL_AUTH,
443   "Allow ppp access", "allow users|modes ...."},
444   {"bg", "!bg", BgShellCommand, LOCAL_AUTH,
445   "Run a background command", "[!]bg command"},
446   {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT,
447   "Clear throughput statistics", "clear ipcp|modem [current|overall|peak]..."},
448   {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX,
449   "Clone a link", "clone newname..."},
450   {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT,
451   "Close an FSM", "close [lcp|ccp]"},
452   {"delete", NULL, DeleteCommand, LOCAL_AUTH,
453   "delete route", "delete dest", NULL},
454   {NULL, "delete!", DeleteCommand, LOCAL_AUTH,
455   "delete a route if it exists", "delete! dest", (void *)1},
456   {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
457   "Deny option request", "deny option .."},
458   {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT,
459   "Dial and login", "dial|call [remote]", NULL},
460   {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
461   "Disable option", "disable option .."},
462   {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT,
463   "Generate a down event", "down"},
464   {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
465   "Enable option", "enable option .."},
466   {"link", "datalink", LinkCommand, LOCAL_AUTH,
467   "Link specific commands", "link name command ..."},
468   {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT,
469   "Load settings", "load [remote]"},
470   {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT,
471   "Open an FSM", "open! [lcp|ccp|ipcp]", (void *)1},
472   {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH,
473   "Password for manipulation", "passwd LocalPassword"},
474   {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
475   "Quit PPP program", "quit|bye [all]"},
476   {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX,
477   "Remove a link", "remove"},
478   {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX,
479   "Rename a link", "rename name"},
480   {"save", NULL, SaveCommand, LOCAL_AUTH,
481   "Save settings", "save"},
482   {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT,
483   "Set parameters", "set[up] var value"},
484   {"shell", "!", FgShellCommand, LOCAL_AUTH,
485   "Run a subshell", "shell|! [sh command]"},
486   {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT,
487   "Show status and stats", "show var"},
488   {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX,
489   "Enter terminal mode", "term"},
490   {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
491   "Display this message", "help|? [command]", Commands},
492   {NULL, NULL, NULL},
493 };
494 
495 static int
496 ShowEscape(struct cmdargs const *arg)
497 {
498   if (arg->cx->physical->async.cfg.EscMap[32]) {
499     int code, bit;
500     const char *sep = "";
501 
502     for (code = 0; code < 32; code++)
503       if (arg->cx->physical->async.cfg.EscMap[code])
504 	for (bit = 0; bit < 8; bit++)
505 	  if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) {
506 	    prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit);
507             sep = ", ";
508           }
509     prompt_Printf(arg->prompt, "\n");
510   }
511   return 0;
512 }
513 
514 static int
515 ShowTimerList(struct cmdargs const *arg)
516 {
517   timer_Show(0, arg->prompt);
518   return 0;
519 }
520 
521 static int
522 ShowStopped(struct cmdargs const *arg)
523 {
524   prompt_Printf(arg->prompt, " Stopped Timer:  LCP: ");
525   if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load)
526     prompt_Printf(arg->prompt, "Disabled");
527   else
528     prompt_Printf(arg->prompt, "%ld secs",
529                   arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS);
530 
531   prompt_Printf(arg->prompt, ", CCP: ");
532   if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load)
533     prompt_Printf(arg->prompt, "Disabled");
534   else
535     prompt_Printf(arg->prompt, "%ld secs",
536                   arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS);
537 
538   prompt_Printf(arg->prompt, "\n");
539 
540   return 0;
541 }
542 
543 static int
544 ShowVersion(struct cmdargs const *arg)
545 {
546   prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, VersionDate);
547   return 0;
548 }
549 
550 static int
551 ShowProtocolStats(struct cmdargs const *arg)
552 {
553   struct link *l = command_ChooseLink(arg);
554 
555   prompt_Printf(arg->prompt, "%s:\n", l->name);
556   link_ReportProtocolStatus(l, arg->prompt);
557   return 0;
558 }
559 
560 static struct cmdtab const ShowCommands[] = {
561   {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH,
562   "bundle details", "show bundle"},
563   {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT,
564   "CCP status", "show cpp"},
565   {"compress", NULL, sl_Show, LOCAL_AUTH,
566   "VJ compression stats", "show compress"},
567   {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX,
568   "escape characters", "show escape"},
569   {"filter", NULL, filter_Show, LOCAL_AUTH,
570   "packet filters", "show filter [in|out|dial|alive]"},
571   {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX,
572   "HDLC errors", "show hdlc"},
573   {"ipcp", NULL, ipcp_Show, LOCAL_AUTH,
574   "IPCP status", "show ipcp"},
575   {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX,
576   "LCP status", "show lcp"},
577   {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX,
578   "(high-level) link info", "show link"},
579   {"links", NULL, bundle_ShowLinks, LOCAL_AUTH,
580   "available link names", "show links"},
581   {"log", NULL, log_ShowLevel, LOCAL_AUTH,
582   "log levels", "show log"},
583   {"mem", NULL, mbuf_Show, LOCAL_AUTH,
584   "mbuf allocations", "show mem"},
585   {"modem", NULL, modem_ShowStatus, LOCAL_AUTH | LOCAL_CX,
586   "(low-level) link info", "show modem"},
587   {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH,
588   "multilink setup", "show mp"},
589   {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT,
590   "protocol summary", "show proto"},
591   {"route", NULL, route_Show, LOCAL_AUTH,
592   "routing table", "show route"},
593   {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX,
594   "STOPPED timeout", "show stopped"},
595   {"timers", NULL, ShowTimerList, LOCAL_AUTH,
596   "alarm timers", "show timers"},
597   {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH,
598   "version string", "show version"},
599   {"who", NULL, log_ShowWho, LOCAL_AUTH,
600   "client list", "show who"},
601   {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH,
602   "Display this message", "show help|? [command]", ShowCommands},
603   {NULL, NULL, NULL},
604 };
605 
606 static struct cmdtab const *
607 FindCommand(struct cmdtab const *cmds, const char *str, int *pmatch)
608 {
609   int nmatch;
610   int len;
611   struct cmdtab const *found;
612 
613   found = NULL;
614   len = strlen(str);
615   nmatch = 0;
616   while (cmds->func) {
617     if (cmds->name && strncasecmp(str, cmds->name, len) == 0) {
618       if (cmds->name[len] == '\0') {
619 	*pmatch = 1;
620 	return cmds;
621       }
622       nmatch++;
623       found = cmds;
624     } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) {
625       if (cmds->alias[len] == '\0') {
626 	*pmatch = 1;
627 	return cmds;
628       }
629       nmatch++;
630       found = cmds;
631     }
632     cmds++;
633   }
634   *pmatch = nmatch;
635   return found;
636 }
637 
638 static const char *
639 mkPrefix(int argc, char const *const *argv, char *tgt, int sz)
640 {
641   int f, tlen, len;
642 
643   tlen = 0;
644   for (f = 0; f < argc && tlen < sz - 2; f++) {
645     if (f)
646       tgt[tlen++] = ' ';
647     len = strlen(argv[f]);
648     if (len > sz - tlen - 1)
649       len = sz - tlen - 1;
650     strncpy(tgt+tlen, argv[f], len);
651     tlen += len;
652   }
653   tgt[tlen] = '\0';
654   return tgt;
655 }
656 
657 static int
658 FindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn,
659          char const *const *argv, struct prompt *prompt, struct datalink *cx)
660 {
661   struct cmdtab const *cmd;
662   int val = 1;
663   int nmatch;
664   struct cmdargs arg;
665   char prefix[100];
666 
667   cmd = FindCommand(cmds, argv[argn], &nmatch);
668   if (nmatch > 1)
669     log_Printf(LogWARN, "%s: Ambiguous command\n",
670               mkPrefix(argn+1, argv, prefix, sizeof prefix));
671   else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) {
672     if ((cmd->lauth & LOCAL_CX) && !cx)
673       /* We've got no context, but we require it */
674       cx = bundle2datalink(bundle, NULL);
675 
676     if ((cmd->lauth & LOCAL_CX) && !cx)
677       log_Printf(LogWARN, "%s: No context (use the `link' command)\n",
678                 mkPrefix(argn+1, argv, prefix, sizeof prefix));
679     else {
680       if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
681         log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n",
682                   mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name);
683         cx = NULL;
684       }
685       arg.cmdtab = cmds;
686       arg.cmd = cmd;
687       arg.argc = argc;
688       arg.argn = argn+1;
689       arg.argv = argv;
690       arg.bundle = bundle;
691       arg.cx = cx;
692       arg.prompt = prompt;
693       val = (*cmd->func) (&arg);
694     }
695   } else
696     log_Printf(LogWARN, "%s: Invalid command\n",
697               mkPrefix(argn+1, argv, prefix, sizeof prefix));
698 
699   if (val == -1)
700     log_Printf(LogWARN, "Usage: %s\n", cmd->syntax);
701   else if (val)
702     log_Printf(LogWARN, "%s: Failed %d\n",
703               mkPrefix(argn+1, argv, prefix, sizeof prefix), val);
704 
705   return val;
706 }
707 
708 int
709 command_Interpret(char *buff, int nb, char *argv[MAXARGS])
710 {
711   char *cp;
712 
713   if (nb > 0) {
714     cp = buff + strcspn(buff, "\r\n");
715     if (cp)
716       *cp = '\0';
717     return MakeArgs(buff, argv, MAXARGS);
718   }
719   return 0;
720 }
721 
722 static int
723 arghidden(int argc, char const *const *argv, int n)
724 {
725   /* Is arg n of the given command to be hidden from the log ? */
726 
727   /* set authkey xxxxx */
728   /* set key xxxxx */
729   if (n == 2 && !strncasecmp(argv[0], "se", 2) &&
730       (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2)))
731     return 1;
732 
733   /* passwd xxxxx */
734   if (n == 1 && !strncasecmp(argv[0], "p", 1))
735     return 1;
736 
737   /* set server port xxxxx .... */
738   if (n == 3 && !strncasecmp(argv[0], "se", 2) &&
739       !strncasecmp(argv[1], "se", 2))
740     return 1;
741 
742   return 0;
743 }
744 
745 void
746 command_Run(struct bundle *bundle, int argc, char const *const *argv,
747            struct prompt *prompt, const char *label, struct datalink *cx)
748 {
749   if (argc > 0) {
750     if (log_IsKept(LogCOMMAND)) {
751       static char buf[LINE_LEN];
752       int f, n;
753 
754       *buf = '\0';
755       if (label) {
756         strncpy(buf, label, sizeof buf - 3);
757         buf[sizeof buf - 3] = '\0';
758         strcat(buf, ": ");
759       }
760       n = strlen(buf);
761       for (f = 0; f < argc; f++) {
762         if (n < sizeof buf - 1 && f)
763           buf[n++] = ' ';
764         if (arghidden(argc, argv, f))
765           strncpy(buf+n, "********", sizeof buf - n - 1);
766         else
767           strncpy(buf+n, argv[f], sizeof buf - n - 1);
768         n += strlen(buf+n);
769       }
770       log_Printf(LogCOMMAND, "%s\n", buf);
771     }
772     FindExec(bundle, Commands, argc, 0, argv, prompt, cx);
773   }
774 }
775 
776 void
777 command_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt,
778               const char *label)
779 {
780   int argc;
781   char *argv[MAXARGS];
782 
783   argc = command_Interpret(buff, nb, argv);
784   command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL);
785 }
786 
787 static int
788 ShowCommand(struct cmdargs const *arg)
789 {
790   if (!arg->prompt)
791     log_Printf(LogWARN, "show: Cannot show without a prompt\n");
792   else if (arg->argc > arg->argn)
793     FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv,
794              arg->prompt, arg->cx);
795   else
796     prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n");
797 
798   return 0;
799 }
800 
801 static int
802 TerminalCommand(struct cmdargs const *arg)
803 {
804   if (!arg->prompt) {
805     log_Printf(LogWARN, "term: Need a prompt\n");
806     return 1;
807   }
808 
809   if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) {
810     prompt_Printf(arg->prompt, "LCP state is [%s]\n",
811                   State2Nam(arg->cx->physical->link.lcp.fsm.state));
812     return 1;
813   }
814 
815   datalink_Up(arg->cx, 0, 0);
816   prompt_TtyTermMode(arg->prompt, arg->cx);
817   return 0;
818 }
819 
820 static int
821 QuitCommand(struct cmdargs const *arg)
822 {
823   if (!arg->prompt || prompt_IsController(arg->prompt) ||
824       (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") &&
825        (arg->prompt->auth & LOCAL_AUTH)))
826     Cleanup(EX_NORMAL);
827   if (arg->prompt)
828     prompt_Destroy(arg->prompt, 1);
829 
830   return 0;
831 }
832 
833 static int
834 OpenCommand(struct cmdargs const *arg)
835 {
836   if (arg->argc == arg->argn)
837     bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
838   else if (arg->argc == arg->argn + 1) {
839     if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
840       struct datalink *cx = arg->cx ?
841         arg->cx : bundle2datalink(arg->bundle, NULL);
842       if (cx) {
843         if (cx->physical->link.lcp.fsm.state == ST_OPENED)
844           fsm_Reopen(&cx->physical->link.lcp.fsm);
845         else
846           bundle_Open(arg->bundle, cx->name, PHYS_ALL, 1);
847       } else
848         log_Printf(LogWARN, "open lcp: You must specify a link\n");
849     } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
850       struct fsm *fp;
851 
852       fp = &command_ChooseLink(arg)->ccp.fsm;
853       if (fp->link->lcp.fsm.state != ST_OPENED)
854         log_Printf(LogWARN, "open: LCP must be open before opening CCP\n");
855       else if (fp->state == ST_OPENED)
856         fsm_Reopen(fp);
857       else {
858         fp->open_mode = 0;	/* Not passive any more */
859         if (fp->state == ST_STOPPED) {
860           fsm_Down(fp);
861           fsm_Up(fp);
862         } else {
863           fsm_Up(fp);
864           fsm_Open(fp);
865         }
866       }
867     } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) {
868       if (arg->cx)
869         log_Printf(LogWARN, "open ipcp: You need not specify a link\n");
870       if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
871         fsm_Reopen(&arg->bundle->ncp.ipcp.fsm);
872       else
873         bundle_Open(arg->bundle, NULL, PHYS_ALL, 1);
874     } else
875       return -1;
876   } else
877     return -1;
878 
879   return 0;
880 }
881 
882 static int
883 CloseCommand(struct cmdargs const *arg)
884 {
885   if (arg->argc == arg->argn)
886     bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN);
887   else if (arg->argc == arg->argn + 1) {
888     if (!strcasecmp(arg->argv[arg->argn], "lcp"))
889       bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP);
890     else if (!strcasecmp(arg->argv[arg->argn], "ccp") ||
891              !strcasecmp(arg->argv[arg->argn], "ccp!")) {
892       struct fsm *fp;
893 
894       fp = &command_ChooseLink(arg)->ccp.fsm;
895       if (fp->state == ST_OPENED) {
896         fsm_Close(fp);
897         if (arg->argv[arg->argn][3] == '!')
898           fp->open_mode = 0;		/* Stay ST_CLOSED */
899         else
900           fp->open_mode = OPEN_PASSIVE;	/* Wait for the peer to start */
901       }
902     } else
903       return -1;
904   } else
905     return -1;
906 
907   return 0;
908 }
909 
910 static int
911 DownCommand(struct cmdargs const *arg)
912 {
913   if (arg->argc == arg->argn) {
914       if (arg->cx)
915         datalink_Down(arg->cx, CLOSE_STAYDOWN);
916       else
917         bundle_Down(arg->bundle, CLOSE_STAYDOWN);
918   } else if (arg->argc == arg->argn + 1) {
919     if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
920       if (arg->cx)
921         datalink_Down(arg->cx, CLOSE_LCP);
922       else
923         bundle_Down(arg->bundle, CLOSE_LCP);
924     } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
925       struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm :
926                                  &arg->bundle->ncp.mp.link.ccp.fsm;
927       fsm2initial(fp);
928     } else
929       return -1;
930   } else
931     return -1;
932 
933   return 0;
934 }
935 
936 static int
937 SetModemSpeed(struct cmdargs const *arg)
938 {
939   long speed;
940   char *end;
941 
942   if (arg->argc > arg->argn && *arg->argv[arg->argn]) {
943     if (arg->argc > arg->argn+1) {
944       log_Printf(LogWARN, "SetModemSpeed: Too many arguments");
945       return -1;
946     }
947     if (strcasecmp(arg->argv[arg->argn], "sync") == 0) {
948       physical_SetSync(arg->cx->physical);
949       return 0;
950     }
951     end = NULL;
952     speed = strtol(arg->argv[arg->argn], &end, 10);
953     if (*end) {
954       log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"",
955                 arg->argv[arg->argn]);
956       return -1;
957     }
958     if (physical_SetSpeed(arg->cx->physical, speed))
959       return 0;
960     log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]);
961   } else
962     log_Printf(LogWARN, "SetModemSpeed: No speed specified\n");
963 
964   return -1;
965 }
966 
967 static int
968 SetStoppedTimeout(struct cmdargs const *arg)
969 {
970   struct link *l = &arg->cx->physical->link;
971 
972   l->lcp.fsm.StoppedTimer.load = 0;
973   l->ccp.fsm.StoppedTimer.load = 0;
974   if (arg->argc <= arg->argn+2) {
975     if (arg->argc > arg->argn) {
976       l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS;
977       if (arg->argc > arg->argn+1)
978         l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS;
979     }
980     return 0;
981   }
982   return -1;
983 }
984 
985 #define ismask(x) \
986   (*x == '0' && strlen(x) == 4 && strspn(x+1, "0123456789.") == 3)
987 
988 static int
989 SetServer(struct cmdargs const *arg)
990 {
991   int res = -1;
992 
993   if (arg->argc > arg->argn && arg->argc < arg->argn+4) {
994     const char *port, *passwd, *mask;
995 
996     /* What's what ? */
997     port = arg->argv[arg->argn];
998     if (arg->argc == arg->argn + 2) {
999       passwd = arg->argv[arg->argn+1];
1000       mask = NULL;
1001     } else if (arg->argc == arg->argn + 3) {
1002       passwd = arg->argv[arg->argn+1];
1003       mask = arg->argv[arg->argn+2];
1004       if (!ismask(mask))
1005         return -1;
1006     } else if (strcasecmp(port, "none") == 0) {
1007       if (server_Close(arg->bundle))
1008         log_Printf(LogPHASE, "Disabled server port.\n");
1009       return 0;
1010     } else
1011       return -1;
1012 
1013     strncpy(server.passwd, passwd, sizeof server.passwd - 1);
1014     server.passwd[sizeof server.passwd - 1] = '\0';
1015 
1016     if (*port == '/') {
1017       mode_t imask;
1018       char *ptr, name[LINE_LEN + 12];
1019 
1020       if (mask != NULL) {
1021 	unsigned m;
1022 
1023 	if (sscanf(mask, "%o", &m) == 1)
1024 	  imask = m;
1025         else
1026           return -1;
1027       } else
1028         imask = (mode_t)-1;
1029 
1030       ptr = strstr(port, "%d");
1031       if (ptr) {
1032         snprintf(name, sizeof name, "%.*s%d%s",
1033                  (int)(ptr - port), port, arg->bundle->unit, ptr + 2);
1034         port = name;
1035       }
1036       res = server_LocalOpen(arg->bundle, port, imask);
1037     } else {
1038       int iport, add = 0;
1039 
1040       if (mask != NULL)
1041         return -1;
1042 
1043       if (*port == '+') {
1044         port++;
1045         add = 1;
1046       }
1047       if (strspn(port, "0123456789") != strlen(port)) {
1048         struct servent *s;
1049 
1050         if ((s = getservbyname(port, "tcp")) == NULL) {
1051 	  iport = 0;
1052 	  log_Printf(LogWARN, "%s: Invalid port or service\n", port);
1053 	} else
1054 	  iport = ntohs(s->s_port);
1055       } else
1056         iport = atoi(port);
1057 
1058       if (iport) {
1059         if (add)
1060           iport += arg->bundle->unit;
1061         res = server_TcpOpen(arg->bundle, iport);
1062       } else
1063         res = -1;
1064     }
1065   }
1066 
1067   return res;
1068 }
1069 
1070 static int
1071 SetModemParity(struct cmdargs const *arg)
1072 {
1073   return arg->argc > arg->argn ? modem_SetParity(arg->cx->physical,
1074                                                  arg->argv[arg->argn]) : -1;
1075 }
1076 
1077 static int
1078 SetEscape(struct cmdargs const *arg)
1079 {
1080   int code;
1081   int argc = arg->argc - arg->argn;
1082   char const *const *argv = arg->argv + arg->argn;
1083 
1084   for (code = 0; code < 33; code++)
1085     arg->cx->physical->async.cfg.EscMap[code] = 0;
1086 
1087   while (argc-- > 0) {
1088     sscanf(*argv++, "%x", &code);
1089     code &= 0xff;
1090     arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7));
1091     arg->cx->physical->async.cfg.EscMap[32] = 1;
1092   }
1093   return 0;
1094 }
1095 
1096 static struct in_addr
1097 GetIpAddr(const char *cp)
1098 {
1099   struct hostent *hp;
1100   struct in_addr ipaddr;
1101 
1102   if (inet_aton(cp, &ipaddr) == 0) {
1103     hp = gethostbyname(cp);
1104     if (hp && hp->h_addrtype == AF_INET)
1105       memcpy(&ipaddr, hp->h_addr, hp->h_length);
1106     else
1107       ipaddr.s_addr = 0;
1108   }
1109   return (ipaddr);
1110 }
1111 
1112 static int
1113 SetInterfaceAddr(struct cmdargs const *arg)
1114 {
1115   struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
1116   const char *hisaddr;
1117 
1118   hisaddr = NULL;
1119   ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY;
1120   ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY;
1121 
1122   if (arg->argc > arg->argn + 4)
1123     return -1;
1124 
1125   ipcp->cfg.HaveTriggerAddress = 0;
1126   ipcp->cfg.netmask.s_addr = INADDR_ANY;
1127   iplist_reset(&ipcp->cfg.peer_list);
1128 
1129   if (arg->argc > arg->argn) {
1130     if (!ParseAddr(ipcp, arg->argc - arg->argn, arg->argv + arg->argn,
1131                    &ipcp->cfg.my_range.ipaddr, &ipcp->cfg.my_range.mask,
1132                    &ipcp->cfg.my_range.width))
1133       return 1;
1134     if (arg->argc > arg->argn+1) {
1135       hisaddr = arg->argv[arg->argn+1];
1136       if (arg->argc > arg->argn+2) {
1137         ipcp->cfg.netmask = GetIpAddr(arg->argv[arg->argn+2]);
1138 	if (arg->argc > arg->argn+3) {
1139 	  ipcp->cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]);
1140 	  ipcp->cfg.HaveTriggerAddress = 1;
1141 	}
1142       }
1143     }
1144   }
1145 
1146   /*
1147    * For backwards compatibility, 0.0.0.0 means any address.
1148    */
1149   if (ipcp->cfg.my_range.ipaddr.s_addr == INADDR_ANY) {
1150     ipcp->cfg.my_range.mask.s_addr = INADDR_ANY;
1151     ipcp->cfg.my_range.width = 0;
1152   }
1153   ipcp->my_ip.s_addr = ipcp->cfg.my_range.ipaddr.s_addr;
1154 
1155   if (ipcp->cfg.peer_range.ipaddr.s_addr == INADDR_ANY) {
1156     ipcp->cfg.peer_range.mask.s_addr = INADDR_ANY;
1157     ipcp->cfg.peer_range.width = 0;
1158   }
1159 
1160   if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr,
1161                                   arg->bundle->phys_type.all & PHYS_AUTO))
1162     return 4;
1163 
1164   return 0;
1165 }
1166 
1167 static int
1168 SetVariable(struct cmdargs const *arg)
1169 {
1170   long long_val, param = (long)arg->cmd->args;
1171   int mode, dummyint;
1172   const char *argp;
1173   struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
1174   const char *err = NULL;
1175   struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
1176   struct in_addr dummyaddr, *addr;
1177 
1178   if (arg->argc > arg->argn)
1179     argp = arg->argv[arg->argn];
1180   else
1181     argp = "";
1182 
1183   if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
1184     log_Printf(LogWARN, "set %s: No context (use the `link' command)\n",
1185               arg->cmd->name);
1186     return 1;
1187   } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
1188     log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n",
1189               arg->cmd->name, cx->name);
1190     cx = NULL;
1191   }
1192 
1193   switch (param) {
1194   case VAR_AUTHKEY:
1195     if (bundle_Phase(arg->bundle) == PHASE_DEAD) {
1196       strncpy(arg->bundle->cfg.auth.key, argp,
1197               sizeof arg->bundle->cfg.auth.key - 1);
1198       arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0';
1199     } else {
1200       err = "set authkey: Only available at phase DEAD\n";
1201       log_Printf(LogWARN, err);
1202     }
1203     break;
1204 
1205   case VAR_AUTHNAME:
1206     if (bundle_Phase(arg->bundle) == PHASE_DEAD) {
1207       strncpy(arg->bundle->cfg.auth.name, argp,
1208               sizeof arg->bundle->cfg.auth.name - 1);
1209       arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name - 1] = '\0';
1210     } else {
1211       err = "set authname: Only available at phase DEAD\n";
1212       log_Printf(LogWARN, err);
1213     }
1214     break;
1215 
1216   case VAR_AUTOLOAD:
1217     if (arg->argc == arg->argn + 2 || arg->argc == arg->argn + 4) {
1218       arg->bundle->autoload.running = 1;
1219       arg->bundle->cfg.autoload.max.timeout = atoi(arg->argv[arg->argn]);
1220       arg->bundle->cfg.autoload.max.packets = atoi(arg->argv[arg->argn + 1]);
1221       if (arg->argc == arg->argn + 4) {
1222         arg->bundle->cfg.autoload.min.timeout = atoi(arg->argv[arg->argn + 2]);
1223         arg->bundle->cfg.autoload.min.packets = atoi(arg->argv[arg->argn + 3]);
1224       } else {
1225         arg->bundle->cfg.autoload.min.timeout = 0;
1226         arg->bundle->cfg.autoload.min.packets = 0;
1227       }
1228     } else {
1229       err = "Set autoload requires two or four arguments\n";
1230       log_Printf(LogWARN, err);
1231     }
1232     break;
1233 
1234   case VAR_DIAL:
1235     strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1);
1236     cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0';
1237     break;
1238 
1239   case VAR_LOGIN:
1240     strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1);
1241     cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0';
1242     break;
1243 
1244   case VAR_WINSIZE:
1245     if (arg->argc > arg->argn) {
1246       l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]);
1247       if (l->ccp.cfg.deflate.out.winsize < 8 ||
1248           l->ccp.cfg.deflate.out.winsize > 15) {
1249           log_Printf(LogWARN, "%d: Invalid outgoing window size\n",
1250                     l->ccp.cfg.deflate.out.winsize);
1251           l->ccp.cfg.deflate.out.winsize = 15;
1252       }
1253       if (arg->argc > arg->argn+1) {
1254         l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]);
1255         if (l->ccp.cfg.deflate.in.winsize < 8 ||
1256             l->ccp.cfg.deflate.in.winsize > 15) {
1257             log_Printf(LogWARN, "%d: Invalid incoming window size\n",
1258                       l->ccp.cfg.deflate.in.winsize);
1259             l->ccp.cfg.deflate.in.winsize = 15;
1260         }
1261       } else
1262         l->ccp.cfg.deflate.in.winsize = 0;
1263     } else {
1264       err = "No window size specified\n";
1265       log_Printf(LogWARN, err);
1266     }
1267     break;
1268 
1269   case VAR_DEVICE:
1270     physical_SetDeviceList(cx->physical, arg->argc - arg->argn,
1271                            arg->argv + arg->argn);
1272     break;
1273 
1274   case VAR_ACCMAP:
1275     if (arg->argc > arg->argn) {
1276       u_long ulong_val;
1277       sscanf(argp, "%lx", &ulong_val);
1278       cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val;
1279     } else {
1280       err = "No accmap specified\n";
1281       log_Printf(LogWARN, err);
1282     }
1283     break;
1284 
1285   case VAR_MODE:
1286     mode = Nam2mode(argp);
1287     if (mode == PHYS_NONE || mode == PHYS_ALL) {
1288       log_Printf(LogWARN, "%s: Invalid mode\n", argp);
1289       return -1;
1290     }
1291     bundle_SetMode(arg->bundle, cx, mode);
1292     break;
1293 
1294   case VAR_MRRU:
1295     if (bundle_Phase(arg->bundle) != PHASE_DEAD) {
1296       log_Printf(LogWARN, "mrru: Only changable at phase DEAD\n");
1297       return 1;
1298     }
1299     long_val = atol(argp);
1300     if (long_val && long_val < MIN_MRU) {
1301       log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU);
1302       return 1;
1303     } else if (long_val > MAX_MRU) {
1304       log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU);
1305       return 1;
1306     } else
1307       arg->bundle->ncp.mp.cfg.mrru = long_val;
1308     break;
1309 
1310   case VAR_MRU:
1311     long_val = atol(argp);
1312     if (long_val == 0)
1313       l->lcp.cfg.mru = DEF_MRU;
1314     else if (long_val < MIN_MRU) {
1315       log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU);
1316       return 1;
1317     } else if (long_val > MAX_MRU) {
1318       log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU);
1319       return 1;
1320     } else
1321       l->lcp.cfg.mru = long_val;
1322     break;
1323 
1324   case VAR_MTU:
1325     long_val = atol(argp);
1326     if (long_val && long_val < MIN_MTU) {
1327       log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU);
1328       return 1;
1329     } else if (long_val > MAX_MTU) {
1330       log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU);
1331       return 1;
1332     } else
1333       arg->bundle->cfg.mtu = long_val;
1334     break;
1335 
1336   case VAR_OPENMODE:
1337     if (strcasecmp(argp, "active") == 0)
1338       cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ?
1339         atoi(arg->argv[arg->argn+1]) : 1;
1340     else if (strcasecmp(argp, "passive") == 0)
1341       cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE;
1342     else {
1343       err = "%s: Invalid openmode\n";
1344       log_Printf(LogWARN, err, argp);
1345     }
1346     break;
1347 
1348   case VAR_PHONE:
1349     strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1);
1350     cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0';
1351     break;
1352 
1353   case VAR_HANGUP:
1354     strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1);
1355     cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0';
1356     break;
1357 
1358   case VAR_IDLETIMEOUT:
1359     if (arg->argc > arg->argn+1)
1360       err = "Too many idle timeout values\n";
1361     else if (arg->argc == arg->argn+1)
1362       bundle_SetIdleTimer(arg->bundle, atoi(argp));
1363     if (err)
1364       log_Printf(LogWARN, err);
1365     break;
1366 
1367   case VAR_LQRPERIOD:
1368     long_val = atol(argp);
1369     if (long_val < MIN_LQRPERIOD) {
1370       log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n",
1371                  long_val, MIN_LQRPERIOD);
1372       return 1;
1373     } else
1374       l->lcp.cfg.lqrperiod = long_val;
1375     break;
1376 
1377   case VAR_LCPRETRY:
1378     long_val = atol(argp);
1379     if (long_val < MIN_FSMRETRY) {
1380       log_Printf(LogWARN, "%ld: Invalid LCP FSM retry period - min %d\n",
1381                  long_val, MIN_FSMRETRY);
1382       return 1;
1383     } else
1384       cx->physical->link.lcp.cfg.fsmretry = long_val;
1385     break;
1386 
1387   case VAR_CHAPRETRY:
1388     long_val = atol(argp);
1389     if (long_val < MIN_FSMRETRY) {
1390       log_Printf(LogWARN, "%ld: Invalid CHAP FSM retry period - min %d\n",
1391                  long_val, MIN_FSMRETRY);
1392       return 1;
1393     } else
1394       cx->chap.auth.cfg.fsmretry = long_val;
1395     break;
1396 
1397   case VAR_PAPRETRY:
1398     long_val = atol(argp);
1399     if (long_val < MIN_FSMRETRY) {
1400       log_Printf(LogWARN, "%ld: Invalid PAP FSM retry period - min %d\n",
1401                  long_val, MIN_FSMRETRY);
1402       return 1;
1403     } else
1404       cx->pap.cfg.fsmretry = long_val;
1405     break;
1406 
1407   case VAR_CCPRETRY:
1408     long_val = atol(argp);
1409     if (long_val < MIN_FSMRETRY) {
1410       log_Printf(LogWARN, "%ld: Invalid CCP FSM retry period - min %d\n",
1411                  long_val, MIN_FSMRETRY);
1412       return 1;
1413     } else
1414       l->ccp.cfg.fsmretry = long_val;
1415     break;
1416 
1417   case VAR_IPCPRETRY:
1418     long_val = atol(argp);
1419     if (long_val < MIN_FSMRETRY) {
1420       log_Printf(LogWARN, "%ld: Invalid IPCP FSM retry period - min %d\n",
1421                  long_val, MIN_FSMRETRY);
1422       return 1;
1423     } else
1424       arg->bundle->ncp.ipcp.cfg.fsmretry = long_val;
1425     break;
1426 
1427   case VAR_NBNS:
1428   case VAR_DNS:
1429     if (param == VAR_DNS)
1430       addr = arg->bundle->ncp.ipcp.cfg.ns.dns;
1431     else
1432       addr = arg->bundle->ncp.ipcp.cfg.ns.nbns;
1433 
1434     addr[0].s_addr = addr[1].s_addr = INADDR_ANY;
1435 
1436     if (arg->argc > arg->argn) {
1437       ParseAddr(&arg->bundle->ncp.ipcp, 1, arg->argv + arg->argn,
1438                 addr, &dummyaddr, &dummyint);
1439       if (arg->argc > arg->argn+1)
1440         ParseAddr(&arg->bundle->ncp.ipcp, 1, arg->argv + arg->argn + 1,
1441                   addr + 1, &dummyaddr, &dummyint);
1442 
1443       if (addr[1].s_addr == INADDR_ANY)
1444         addr[1].s_addr = addr[0].s_addr;
1445       if (addr[0].s_addr == INADDR_ANY)
1446         addr[0].s_addr = addr[1].s_addr;
1447     }
1448     break;
1449   }
1450 
1451   return err ? 1 : 0;
1452 }
1453 
1454 static int
1455 SetCtsRts(struct cmdargs const *arg)
1456 {
1457   if (arg->argc == arg->argn+1) {
1458     if (strcmp(arg->argv[arg->argn], "on") == 0)
1459       physical_SetRtsCts(arg->cx->physical, 1);
1460     else if (strcmp(arg->argv[arg->argn], "off") == 0)
1461       physical_SetRtsCts(arg->cx->physical, 0);
1462     else
1463       return -1;
1464     return 0;
1465   }
1466   return -1;
1467 }
1468 
1469 static struct cmdtab const SetCommands[] = {
1470   {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
1471   "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP},
1472   {"authkey", "key", SetVariable, LOCAL_AUTH,
1473   "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY},
1474   {"authname", NULL, SetVariable, LOCAL_AUTH,
1475   "authentication name", "set authname name", (const void *)VAR_AUTHNAME},
1476   {"autoload", NULL, SetVariable, LOCAL_AUTH,
1477   "auto link [de]activation", "set autoload maxtime maxload mintime minload",
1478   (const void *)VAR_AUTOLOAD},
1479   {"ccpretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
1480   "FSM retry period", "set ccpretry value", (const void *)VAR_CCPRETRY},
1481   {"chapretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
1482   "CHAP retry period", "set chapretry value", (const void *)VAR_CHAPRETRY},
1483   {"ctsrts", "crtscts", SetCtsRts, LOCAL_AUTH | LOCAL_CX,
1484   "Use hardware flow control", "set ctsrts [on|off]"},
1485   {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
1486   "deflate window sizes", "set deflate out-winsize in-winsize",
1487   (const void *) VAR_WINSIZE},
1488   {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX,
1489   "modem device name", "set device|line device-name[,device-name]",
1490   (const void *) VAR_DEVICE},
1491   {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
1492   "dialing script", "set dial chat-script", (const void *) VAR_DIAL},
1493   {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server",
1494   "set dns pri-addr [sec-addr]", (const void *)VAR_DNS},
1495   {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH,
1496   "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]"},
1497   {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX,
1498   "escape characters", "set escape hex-digit ..."},
1499   {"filter", NULL, filter_Set, LOCAL_AUTH,
1500   "packet filters", "set filter alive|dial|in|out rule-no permit|deny "
1501   "[src_addr[/width]] [dst_addr[/width]] [tcp|udp|icmp [src [lt|eq|gt port]] "
1502   "[dst [lt|eq|gt port]] [estab] [syn] [finrst]]"},
1503   {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
1504   "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
1505   {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address",
1506   "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"},
1507   {"ipcpretry", NULL, SetVariable, LOCAL_AUTH,
1508   "FSM retry period", "set ipcpretry value", (const void *)VAR_IPCPRETRY},
1509   {"lcpretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
1510   "FSM retry period", "set lcpretry value", (const void *)VAR_LCPRETRY},
1511   {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level",
1512   "set log [local] [+|-]async|ccp|chat|command|connect|debug|hdlc|id0|ipcp|"
1513   "lcp|lqm|phase|tcp/ip|timer|tun..."},
1514   {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
1515   "login script", "set login chat-script", (const void *) VAR_LOGIN},
1516   {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
1517   "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD},
1518   {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value",
1519   "set mode interactive|auto|ddial|background", (const void *)VAR_MODE},
1520   {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value",
1521   "set mrru value", (const void *)VAR_MRRU},
1522   {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
1523   "MRU value", "set mru value", (const void *)VAR_MRU},
1524   {"mtu", NULL, SetVariable, LOCAL_AUTH,
1525   "interface MTU value", "set mtu value", (const void *)VAR_MTU},
1526   {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server",
1527   "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS},
1528   {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode",
1529   "set openmode active|passive [secs]", (const void *)VAR_OPENMODE},
1530   {"papretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
1531   "PAP retry period", "set papretry value", (const void *)VAR_PAPRETRY},
1532   {"parity", NULL, SetModemParity, LOCAL_AUTH | LOCAL_CX,
1533   "modem parity", "set parity [odd|even|none]"},
1534   {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)",
1535   "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE},
1536   {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX,
1537   "Reconnect timeout", "set reconnect value ntries"},
1538   {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX,
1539   "Redial timeout", "set redial value|random[.value|random] [attempts]"},
1540   {"server", "socket", SetServer, LOCAL_AUTH,
1541   "server port", "set server|socket TcpPort|LocalName|none password [mask]"},
1542   {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX,
1543   "modem speed", "set speed value"},
1544   {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX,
1545   "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"},
1546   {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout",
1547   "set timeout idletime", (const void *)VAR_IDLETIMEOUT},
1548   {"vj", NULL, ipcp_vjset, LOCAL_AUTH,
1549   "vj values", "set vj slots|slotcomp [value]"},
1550   {"weight", NULL, mp_SetDatalinkWeight, LOCAL_AUTH | LOCAL_CX,
1551   "datalink weighting", "set weight n"},
1552   {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
1553   "Display this message", "set help|? [command]", SetCommands},
1554   {NULL, NULL, NULL},
1555 };
1556 
1557 static int
1558 SetCommand(struct cmdargs const *arg)
1559 {
1560   if (arg->argc > arg->argn)
1561     FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv,
1562              arg->prompt, arg->cx);
1563   else if (arg->prompt)
1564     prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for"
1565 	    " syntax help.\n");
1566   else
1567     log_Printf(LogWARN, "set command must have arguments\n");
1568 
1569   return 0;
1570 }
1571 
1572 
1573 static int
1574 AddCommand(struct cmdargs const *arg)
1575 {
1576   struct in_addr dest, gateway, netmask;
1577   int gw, addrs;
1578 
1579   if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2)
1580     return -1;
1581 
1582   addrs = 0;
1583   if (arg->argc == arg->argn+2) {
1584     if (!strcasecmp(arg->argv[arg->argn], "default"))
1585       dest.s_addr = netmask.s_addr = INADDR_ANY;
1586     else {
1587       int width;
1588 
1589       if (!ParseAddr(&arg->bundle->ncp.ipcp, 1, arg->argv + arg->argn,
1590 	             &dest, &netmask, &width))
1591         return -1;
1592       if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6))
1593         addrs = ROUTE_DSTMYADDR;
1594       else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7))
1595         addrs = ROUTE_DSTHISADDR;
1596     }
1597     gw = 1;
1598   } else {
1599     if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
1600       addrs = ROUTE_DSTMYADDR;
1601       dest = arg->bundle->ncp.ipcp.my_ip;
1602     } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
1603       addrs = ROUTE_DSTHISADDR;
1604       dest = arg->bundle->ncp.ipcp.peer_ip;
1605     } else
1606       dest = GetIpAddr(arg->argv[arg->argn]);
1607     netmask = GetIpAddr(arg->argv[arg->argn+1]);
1608     gw = 2;
1609   }
1610 
1611   if (strcasecmp(arg->argv[arg->argn+gw], "HISADDR") == 0) {
1612     gateway = arg->bundle->ncp.ipcp.peer_ip;
1613     addrs |= ROUTE_GWHISADDR;
1614   } else if (strcasecmp(arg->argv[arg->argn+gw], "INTERFACE") == 0)
1615     gateway.s_addr = INADDR_ANY;
1616   else
1617     gateway = GetIpAddr(arg->argv[arg->argn+gw]);
1618 
1619   if (bundle_SetRoute(arg->bundle, RTM_ADD, dest, gateway, netmask,
1620                   arg->cmd->args ? 1 : 0, (addrs & ROUTE_GWHISADDR) ? 1 : 0))
1621     route_Add(&arg->bundle->ncp.ipcp.route, addrs, dest, netmask, gateway);
1622 
1623   return 0;
1624 }
1625 
1626 static int
1627 DeleteCommand(struct cmdargs const *arg)
1628 {
1629   struct in_addr dest, none;
1630   int addrs;
1631 
1632   if (arg->argc == arg->argn+1) {
1633     if(strcasecmp(arg->argv[arg->argn], "all") == 0) {
1634       route_IfDelete(arg->bundle, 0);
1635       route_DeleteAll(&arg->bundle->ncp.ipcp.route);
1636     } else {
1637       addrs = 0;
1638       if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
1639         dest = arg->bundle->ncp.ipcp.my_ip;
1640         addrs = ROUTE_DSTMYADDR;
1641       } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
1642         dest = arg->bundle->ncp.ipcp.peer_ip;
1643         addrs = ROUTE_DSTHISADDR;
1644       } else {
1645         if (strcasecmp(arg->argv[arg->argn], "default") == 0)
1646           dest.s_addr = INADDR_ANY;
1647         else
1648           dest = GetIpAddr(arg->argv[arg->argn]);
1649         addrs = ROUTE_STATIC;
1650       }
1651       none.s_addr = INADDR_ANY;
1652       bundle_SetRoute(arg->bundle, RTM_DELETE, dest, none, none,
1653                       arg->cmd->args ? 1 : 0, 0);
1654       route_Delete(&arg->bundle->ncp.ipcp.route, addrs, dest);
1655     }
1656   } else
1657     return -1;
1658 
1659   return 0;
1660 }
1661 
1662 #ifndef NOALIAS
1663 static struct cmdtab const AliasCommands[] =
1664 {
1665   {"addr", NULL, alias_RedirectAddr, LOCAL_AUTH,
1666    "static address translation", "alias addr [addr_local addr_alias]"},
1667   {"deny_incoming", NULL, AliasOption, LOCAL_AUTH,
1668    "stop incoming connections", "alias deny_incoming [yes|no]",
1669    (const void *) PKT_ALIAS_DENY_INCOMING},
1670   {"enable", NULL, AliasEnable, LOCAL_AUTH,
1671    "enable IP aliasing", "alias enable [yes|no]"},
1672   {"log", NULL, AliasOption, LOCAL_AUTH,
1673    "log aliasing link creation", "alias log [yes|no]",
1674    (const void *) PKT_ALIAS_LOG},
1675   {"port", NULL, alias_RedirectPort, LOCAL_AUTH,
1676    "port redirection", "alias port [proto addr_local:port_local  port_alias]"},
1677   {"same_ports", NULL, AliasOption, LOCAL_AUTH,
1678    "try to leave port numbers unchanged", "alias same_ports [yes|no]",
1679    (const void *) PKT_ALIAS_SAME_PORTS},
1680   {"unregistered_only", NULL, AliasOption, LOCAL_AUTH,
1681    "alias unregistered (private) IP address space only",
1682    "alias unregistered_only [yes|no]",
1683    (const void *) PKT_ALIAS_UNREGISTERED_ONLY},
1684   {"use_sockets", NULL, AliasOption, LOCAL_AUTH,
1685    "allocate host sockets", "alias use_sockets [yes|no]",
1686    (const void *) PKT_ALIAS_USE_SOCKETS},
1687   {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
1688    "Display this message", "alias help|? [command]", AliasCommands},
1689   {NULL, NULL, NULL},
1690 };
1691 
1692 
1693 static int
1694 AliasCommand(struct cmdargs const *arg)
1695 {
1696   if (arg->argc > arg->argn)
1697     FindExec(arg->bundle, AliasCommands, arg->argc, arg->argn, arg->argv,
1698              arg->prompt, arg->cx);
1699   else if (arg->prompt)
1700     prompt_Printf(arg->prompt, "Use `alias help' to get a list or `alias help"
1701             " <option>' for syntax help.\n");
1702   else
1703     log_Printf(LogWARN, "alias command must have arguments\n");
1704 
1705   return 0;
1706 }
1707 
1708 static int
1709 AliasEnable(struct cmdargs const *arg)
1710 {
1711   if (arg->argc == arg->argn+1) {
1712     if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
1713       arg->bundle->AliasEnabled = 1;
1714       return 0;
1715     } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) {
1716       arg->bundle->AliasEnabled = 0;
1717       return 0;
1718     }
1719   }
1720 
1721   return -1;
1722 }
1723 
1724 
1725 static int
1726 AliasOption(struct cmdargs const *arg)
1727 {
1728   unsigned param = (unsigned)arg->cmd->args;
1729   if (arg->argc == arg->argn+1) {
1730     if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
1731       if (arg->bundle->AliasEnabled) {
1732 	PacketAliasSetMode(param, param);
1733 	return 0;
1734       }
1735       log_Printf(LogWARN, "alias not enabled\n");
1736     } else if (strcmp(arg->argv[arg->argn], "no") == 0) {
1737       if (arg->bundle->AliasEnabled) {
1738 	PacketAliasSetMode(0, param);
1739 	return 0;
1740       }
1741       log_Printf(LogWARN, "alias not enabled\n");
1742     }
1743   }
1744   return -1;
1745 }
1746 #endif /* #ifndef NOALIAS */
1747 
1748 static struct cmdtab const AllowCommands[] = {
1749   {"modes", "mode", AllowModes, LOCAL_AUTH,
1750   "Only allow certain ppp modes", "allow modes mode..."},
1751   {"users", "user", AllowUsers, LOCAL_AUTH,
1752   "Allow users access to ppp", "allow users logname..."},
1753   {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
1754   "Display this message", "allow help|? [command]", AllowCommands},
1755   {NULL, NULL, NULL},
1756 };
1757 
1758 static int
1759 AllowCommand(struct cmdargs const *arg)
1760 {
1761   /* arg->bundle may be NULL (see system_IsValid()) ! */
1762   if (arg->argc > arg->argn)
1763     FindExec(arg->bundle, AllowCommands, arg->argc, arg->argn, arg->argv,
1764              arg->prompt, arg->cx);
1765   else if (arg->prompt)
1766     prompt_Printf(arg->prompt, "Use `allow ?' to get a list or `allow ? <cmd>'"
1767                   " for syntax help.\n");
1768   else
1769     log_Printf(LogWARN, "allow command must have arguments\n");
1770 
1771   return 0;
1772 }
1773 
1774 static int
1775 LinkCommand(struct cmdargs const *arg)
1776 {
1777   if (arg->argc > arg->argn+1) {
1778     char namelist[LINE_LEN];
1779     struct datalink *cx;
1780     char *name;
1781     int result = 0;
1782 
1783     if (!strcmp(arg->argv[arg->argn], "*")) {
1784       struct datalink *dl;
1785 
1786       cx = arg->bundle->links;
1787       while (cx) {
1788         /* Watch it, the command could be a ``remove'' */
1789         dl = cx->next;
1790         FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
1791                  arg->prompt, cx);
1792         for (cx = arg->bundle->links; cx; cx = cx->next)
1793           if (cx == dl)
1794             break;		/* Pointer's still valid ! */
1795       }
1796     } else {
1797       strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
1798       namelist[sizeof namelist - 1] = '\0';
1799       for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
1800         if (!bundle2datalink(arg->bundle, name)) {
1801           log_Printf(LogWARN, "link: %s: Invalid link name\n", name);
1802           return 1;
1803         }
1804 
1805       strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
1806       namelist[sizeof namelist - 1] = '\0';
1807       for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) {
1808         cx = bundle2datalink(arg->bundle, name);
1809         if (cx)
1810           FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
1811                    arg->prompt, cx);
1812         else {
1813           log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name);
1814           result++;
1815         }
1816       }
1817     }
1818     return result;
1819   }
1820 
1821   log_Printf(LogWARN, "Usage: %s\n", arg->cmd->syntax);
1822   return 2;
1823 }
1824 
1825 struct link *
1826 command_ChooseLink(struct cmdargs const *arg)
1827 {
1828   if (arg->cx)
1829     return &arg->cx->physical->link;
1830   else if (!arg->bundle->ncp.mp.cfg.mrru) {
1831     struct datalink *dl = bundle2datalink(arg->bundle, NULL);
1832     if (dl)
1833       return &dl->physical->link;
1834   }
1835   return &arg->bundle->ncp.mp.link;
1836 }
1837 
1838 static const char *
1839 ident_cmd(const char *cmd, unsigned *keep, unsigned *add)
1840 {
1841   const char *result;
1842 
1843   switch (*cmd) {
1844     case 'A':
1845     case 'a':
1846       result = "accept";
1847       *keep = NEG_MYMASK;
1848       *add = NEG_ACCEPTED;
1849       break;
1850     case 'D':
1851     case 'd':
1852       switch (cmd[1]) {
1853         case 'E':
1854         case 'e':
1855           result = "deny";
1856           *keep = NEG_MYMASK;
1857           *add = 0;
1858           break;
1859         case 'I':
1860         case 'i':
1861           result = "disable";
1862           *keep = NEG_HISMASK;
1863           *add = 0;
1864           break;
1865         default:
1866           return NULL;
1867       }
1868       break;
1869     case 'E':
1870     case 'e':
1871       result = "enable";
1872       *keep = NEG_HISMASK;
1873       *add = NEG_ENABLED;
1874       break;
1875     default:
1876       return NULL;
1877   }
1878 
1879   return result;
1880 }
1881 
1882 static int
1883 OptSet(struct cmdargs const *arg)
1884 {
1885   int bit = (int)(long)arg->cmd->args;
1886   const char *cmd;
1887   unsigned keep;			/* Keep these bits */
1888   unsigned add;				/* Add these bits */
1889 
1890   if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
1891     return 1;
1892 
1893   if (add)
1894     arg->bundle->cfg.opt |= bit;
1895   else
1896     arg->bundle->cfg.opt &= ~bit;
1897   return 0;
1898 }
1899 
1900 static int
1901 NegotiateSet(struct cmdargs const *arg)
1902 {
1903   long param = (long)arg->cmd->args;
1904   struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
1905   struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
1906   const char *cmd;
1907   unsigned keep;			/* Keep these bits */
1908   unsigned add;				/* Add these bits */
1909 
1910   if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
1911     return 1;
1912 
1913   if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
1914     log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n",
1915               cmd, arg->cmd->name);
1916     return 2;
1917   } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
1918     log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n",
1919               cmd, arg->cmd->name, cx->name);
1920     cx = NULL;
1921   }
1922 
1923   switch (param) {
1924     case NEG_ACFCOMP:
1925       cx->physical->link.lcp.cfg.acfcomp &= keep;
1926       cx->physical->link.lcp.cfg.acfcomp |= add;
1927       break;
1928     case NEG_CHAP:
1929       cx->physical->link.lcp.cfg.chap &= keep;
1930       cx->physical->link.lcp.cfg.chap |= add;
1931       break;
1932     case NEG_DEFLATE:
1933       l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep;
1934       l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add;
1935       break;
1936     case NEG_DNS:
1937       arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep;
1938       arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add;
1939       break;
1940     case NEG_LQR:
1941       cx->physical->link.lcp.cfg.lqr &= keep;
1942       cx->physical->link.lcp.cfg.lqr |= add;
1943       break;
1944     case NEG_PAP:
1945       cx->physical->link.lcp.cfg.pap &= keep;
1946       cx->physical->link.lcp.cfg.pap |= add;
1947       break;
1948     case NEG_PPPDDEFLATE:
1949       l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep;
1950       l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add;
1951       break;
1952     case NEG_PRED1:
1953       l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep;
1954       l->ccp.cfg.neg[CCP_NEG_PRED1] |= add;
1955       break;
1956     case NEG_PROTOCOMP:
1957       cx->physical->link.lcp.cfg.protocomp &= keep;
1958       cx->physical->link.lcp.cfg.protocomp |= add;
1959       break;
1960     case NEG_SHORTSEQ:
1961       if (bundle_Phase(arg->bundle) != PHASE_DEAD)
1962         log_Printf(LogWARN, "shortseq: Only changable at phase DEAD\n");
1963       else {
1964         arg->bundle->ncp.mp.cfg.shortseq &= keep;
1965         arg->bundle->ncp.mp.cfg.shortseq |= add;
1966       }
1967       break;
1968     case NEG_VJCOMP:
1969       arg->bundle->ncp.ipcp.cfg.vj.neg &= keep;
1970       arg->bundle->ncp.ipcp.cfg.vj.neg |= add;
1971       break;
1972   }
1973 
1974   return 0;
1975 }
1976 
1977 static struct cmdtab const NegotiateCommands[] = {
1978   {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids",
1979   "disable|enable", (const void *)OPT_IDCHECK},
1980   {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface",
1981   "disable|enable", (const void *)OPT_LOOPBACK},
1982   {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file",
1983   "disable|enable", (const void *)OPT_PASSWDAUTH},
1984   {"proxy", NULL, OptSet, LOCAL_AUTH, "Create proxy ARP entry",
1985   "disable|enable", (const void *)OPT_PROXY},
1986   {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes",
1987   "disable|enable", (const void *)OPT_SROUTES},
1988   {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput",
1989   "disable|enable", (const void *)OPT_THROUGHPUT},
1990   {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp",
1991   "disable|enable", (const void *)OPT_UTMP},
1992 
1993 #define OPT_MAX 7	/* accept/deny allowed below and not above */
1994 
1995   {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
1996   "Address & Control field compression", "accept|deny|disable|enable",
1997   (const void *)NEG_ACFCOMP},
1998   {"chap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
1999   "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable",
2000   (const void *)NEG_CHAP},
2001   {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
2002   "Deflate compression", "accept|deny|disable|enable",
2003   (const void *)NEG_DEFLATE},
2004   {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
2005   "Deflate (type 24) compression", "accept|deny|disable|enable",
2006   (const void *)NEG_PPPDDEFLATE},
2007   {"dns", NULL, NegotiateSet, LOCAL_AUTH,
2008   "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS},
2009   {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
2010   "Link Quality Reports", "accept|deny|disable|enable",
2011   (const void *)NEG_LQR},
2012   {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
2013   "Password Authentication protocol", "accept|deny|disable|enable",
2014   (const void *)NEG_PAP},
2015   {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
2016   "Predictor 1 compression", "accept|deny|disable|enable",
2017   (const void *)NEG_PRED1},
2018   {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
2019   "Protocol field compression", "accept|deny|disable|enable",
2020   (const void *)NEG_PROTOCOMP},
2021   {"shortseq", NULL, NegotiateSet, LOCAL_AUTH,
2022   "MP Short Sequence Numbers", "accept|deny|disable|enable",
2023   (const void *)NEG_SHORTSEQ},
2024   {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH,
2025   "Van Jacobson header compression", "accept|deny|disable|enable",
2026   (const void *)NEG_VJCOMP},
2027   {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
2028   "Display this message", "accept|deny|disable|enable help|? [value]",
2029   NegotiateCommands},
2030   {NULL, NULL, NULL},
2031 };
2032 
2033 static int
2034 NegotiateCommand(struct cmdargs const *arg)
2035 {
2036   if (arg->argc > arg->argn) {
2037     char const *argv[3];
2038     unsigned keep, add;
2039     int n;
2040 
2041     if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL)
2042       return -1;
2043     argv[2] = NULL;
2044 
2045     for (n = arg->argn; n < arg->argc; n++) {
2046       argv[1] = arg->argv[n];
2047       FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ?
2048                0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx);
2049     }
2050   } else if (arg->prompt)
2051     prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n",
2052 	    arg->argv[arg->argn-1]);
2053   else
2054     log_Printf(LogWARN, "%s command must have arguments\n",
2055               arg->argv[arg->argn] );
2056 
2057   return 0;
2058 }
2059 
2060 const char *
2061 command_ShowNegval(unsigned val)
2062 {
2063   switch (val&3) {
2064     case 1: return "disabled & accepted";
2065     case 2: return "enabled & denied";
2066     case 3: return "enabled & accepted";
2067   }
2068   return "disabled & denied";
2069 }
2070 
2071 static int
2072 ClearCommand(struct cmdargs const *arg)
2073 {
2074   struct pppThroughput *t;
2075   struct datalink *cx;
2076   int i, clear_type;
2077 
2078   if (arg->argc < arg->argn + 1)
2079     return -1;
2080 
2081   if (strcasecmp(arg->argv[arg->argn], "modem") == 0) {
2082     cx = arg->cx;
2083     if (!cx)
2084       cx = bundle2datalink(arg->bundle, NULL);
2085     if (!cx) {
2086       log_Printf(LogWARN, "A link must be specified for ``clear modem''\n");
2087       return 1;
2088     }
2089     t = &cx->physical->link.throughput;
2090   } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0)
2091     t = &arg->bundle->ncp.ipcp.throughput;
2092   else
2093     return -1;
2094 
2095   if (arg->argc > arg->argn + 1) {
2096     clear_type = 0;
2097     for (i = arg->argn + 1; i < arg->argc; i++)
2098       if (strcasecmp(arg->argv[i], "overall") == 0)
2099         clear_type |= THROUGHPUT_OVERALL;
2100       else if (strcasecmp(arg->argv[i], "current") == 0)
2101         clear_type |= THROUGHPUT_CURRENT;
2102       else if (strcasecmp(arg->argv[i], "peak") == 0)
2103         clear_type |= THROUGHPUT_PEAK;
2104       else
2105         return -1;
2106   } else
2107     clear_type = THROUGHPUT_ALL;
2108 
2109   throughput_clear(t, clear_type, arg->prompt);
2110   return 0;
2111 }
2112