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