command.c revision 37385
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.153 1998/07/04 10:24:49 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 124const char Version[] = "2.0"; 125const char VersionDate[] = "$Date: 1998/07/04 10:24:49 $"; 126 127static int ShowCommand(struct cmdargs const *); 128static int TerminalCommand(struct cmdargs const *); 129static int QuitCommand(struct cmdargs const *); 130static int OpenCommand(struct cmdargs const *); 131static int CloseCommand(struct cmdargs const *); 132static int DownCommand(struct cmdargs const *); 133static int AllowCommand(struct cmdargs const *); 134static int SetCommand(struct cmdargs const *); 135static int LinkCommand(struct cmdargs const *); 136static int AddCommand(struct cmdargs const *); 137static int DeleteCommand(struct cmdargs const *); 138static int NegotiateCommand(struct cmdargs const *); 139static int ClearCommand(struct cmdargs const *); 140#ifndef NOALIAS 141static int AliasCommand(struct cmdargs const *); 142static int AliasEnable(struct cmdargs const *); 143static int AliasOption(struct cmdargs const *); 144#endif 145 146static const char * 147showcx(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 157static int 158HelpCommand(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 208static int 209CloneCommand(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 228static int 229RemoveCommand(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 243static int 244RenameCommand(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 257int 258LoadCommand(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 286int 287SaveCommand(struct cmdargs const *arg) 288{ 289 log_Printf(LogWARN, "save command is not implemented (yet).\n"); 290 return 1; 291} 292 293static int 294DialCommand(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); 310 311 return 0; 312} 313 314static int 315ShellCommand(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 417static int 418BgShellCommand(struct cmdargs const *arg) 419{ 420 if (arg->argc == arg->argn) 421 return -1; 422 return ShellCommand(arg, 1); 423} 424 425static int 426FgShellCommand(struct cmdargs const *arg) 427{ 428 return ShellCommand(arg, 0); 429} 430 431static 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]"}, 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]"}, 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 495static int 496ShowEscape(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 514static int 515ShowTimerList(struct cmdargs const *arg) 516{ 517 timer_Show(0, arg->prompt); 518 return 0; 519} 520 521static int 522ShowStopped(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 543static int 544ShowVersion(struct cmdargs const *arg) 545{ 546 prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, VersionDate); 547 return 0; 548} 549 550static int 551ShowProtocolStats(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 560static 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 606static struct cmdtab const * 607FindCommand(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 638static const char * 639mkPrefix(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 657static int 658FindExec(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 708int 709command_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 722static int 723arghidden(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 745void 746command_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 776void 777command_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 787static int 788ShowCommand(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 801static int 802TerminalCommand(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 820static int 821QuitCommand(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 833static int 834OpenCommand(struct cmdargs const *arg) 835{ 836 if (arg->argc == arg->argn) 837 bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL); 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); 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); 874 } else 875 return -1; 876 } else 877 return -1; 878 879 return 0; 880} 881 882static int 883CloseCommand(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 910static int 911DownCommand(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 936static int 937SetModemSpeed(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 967static int 968SetStoppedTimeout(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 988static int 989SetServer(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 1070static int 1071SetModemParity(struct cmdargs const *arg) 1072{ 1073 return arg->argc > arg->argn ? modem_SetParity(arg->cx->physical, 1074 arg->argv[arg->argn]) : -1; 1075} 1076 1077static int 1078SetEscape(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 1096static struct in_addr 1097GetIpAddr(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 1112static int 1113SetInterfaceAddr(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 1167static int 1168SetVariable(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 1454static int 1455SetCtsRts(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 1469static 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 1557static int 1558SetCommand(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 1573static int 1574AddCommand(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)) 1621 route_Add(&arg->bundle->ncp.ipcp.route, addrs, dest, netmask, gateway); 1622 1623 return 0; 1624} 1625 1626static int 1627DeleteCommand(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); 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 1663static 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 1693static int 1694AliasCommand(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 1708static int 1709AliasEnable(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 1725static int 1726AliasOption(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 1748static 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 1758static int 1759AllowCommand(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 1774static int 1775LinkCommand(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 1825struct link * 1826command_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 1838static const char * 1839ident_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 1882static int 1883OptSet(struct cmdargs const *arg) 1884{ 1885 int bit = (long)arg->cmd->args ? 1 : 0; 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 1900static int 1901NegotiateSet(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 1977static 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 2033static int 2034NegotiateCommand(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 2060const char * 2061command_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 2071static int 2072ClearCommand(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