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