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