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