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