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