1 /*- 2 * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 3 * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 4 * Internet Initiative Japan, Inc (IIJ) 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #include <sys/param.h> 32 #include <netinet/in_systm.h> 33 #include <netinet/in.h> 34 #include <netinet/ip.h> 35 #include <arpa/inet.h> 36 #include <sys/socket.h> 37 #include <net/route.h> 38 #include <netdb.h> 39 #include <sys/un.h> 40 41 #include <ctype.h> 42 #include <errno.h> 43 #include <fcntl.h> 44 #include <paths.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <sys/wait.h> 49 #include <termios.h> 50 #include <unistd.h> 51 52 #ifndef NONAT 53 #ifdef LOCALNAT 54 #include "alias.h" 55 #else 56 #include <alias.h> 57 #endif 58 #endif 59 60 #include "layer.h" 61 #include "defs.h" 62 #include "command.h" 63 #include "mbuf.h" 64 #include "log.h" 65 #include "timer.h" 66 #include "fsm.h" 67 #include "iplist.h" 68 #include "throughput.h" 69 #include "slcompress.h" 70 #include "lqr.h" 71 #include "hdlc.h" 72 #include "lcp.h" 73 #include "ipcp.h" 74 #ifndef NONAT 75 #include "nat_cmd.h" 76 #endif 77 #include "systems.h" 78 #include "filter.h" 79 #include "descriptor.h" 80 #include "main.h" 81 #include "route.h" 82 #include "ccp.h" 83 #include "auth.h" 84 #include "async.h" 85 #include "link.h" 86 #include "physical.h" 87 #include "mp.h" 88 #ifndef NORADIUS 89 #include "radius.h" 90 #endif 91 #include "bundle.h" 92 #include "server.h" 93 #include "prompt.h" 94 #include "chat.h" 95 #include "chap.h" 96 #include "cbcp.h" 97 #include "datalink.h" 98 #include "iface.h" 99 #include "id.h" 100 101 /* ``set'' values */ 102 #define VAR_AUTHKEY 0 103 #define VAR_DIAL 1 104 #define VAR_LOGIN 2 105 #define VAR_AUTHNAME 3 106 #define VAR_AUTOLOAD 4 107 #define VAR_WINSIZE 5 108 #define VAR_DEVICE 6 109 #define VAR_ACCMAP 7 110 #define VAR_MRRU 8 111 #define VAR_MRU 9 112 #define VAR_MTU 10 113 #define VAR_OPENMODE 11 114 #define VAR_PHONE 12 115 #define VAR_HANGUP 13 116 #define VAR_IDLETIMEOUT 14 117 #define VAR_LQRPERIOD 15 118 #define VAR_LCPRETRY 16 119 #define VAR_CHAPRETRY 17 120 #define VAR_PAPRETRY 18 121 #define VAR_CCPRETRY 19 122 #define VAR_IPCPRETRY 20 123 #define VAR_DNS 21 124 #define VAR_NBNS 22 125 #define VAR_MODE 23 126 #define VAR_CALLBACK 24 127 #define VAR_CBCP 25 128 #define VAR_CHOKED 26 129 #define VAR_SENDPIPE 27 130 #define VAR_RECVPIPE 28 131 #define VAR_RADIUS 29 132 #define VAR_CD 30 133 #define VAR_PARITY 31 134 #define VAR_CRTSCTS 32 135 #define VAR_URGENTPORTS 33 136 #define VAR_LOGOUT 34 137 #define VAR_IFQUEUE 35 138 #define VAR_MPPE 36 139 140 /* ``accept|deny|disable|enable'' masks */ 141 #define NEG_HISMASK (1) 142 #define NEG_MYMASK (2) 143 144 /* ``accept|deny|disable|enable'' values */ 145 #define NEG_ACFCOMP 40 146 #define NEG_CHAP05 41 147 #define NEG_CHAP80 42 148 #define NEG_CHAP80LM 43 149 #define NEG_DEFLATE 44 150 #define NEG_DNS 45 151 #define NEG_ENDDISC 46 152 #define NEG_LQR 47 153 #define NEG_PAP 48 154 #define NEG_PPPDDEFLATE 49 155 #define NEG_PRED1 50 156 #define NEG_PROTOCOMP 51 157 #define NEG_SHORTSEQ 52 158 #define NEG_VJCOMP 53 159 #define NEG_MPPE 54 160 #define NEG_CHAP81 55 161 162 const char Version[] = "2.3.2"; 163 164 static int ShowCommand(struct cmdargs const *); 165 static int TerminalCommand(struct cmdargs const *); 166 static int QuitCommand(struct cmdargs const *); 167 static int OpenCommand(struct cmdargs const *); 168 static int CloseCommand(struct cmdargs const *); 169 static int DownCommand(struct cmdargs const *); 170 static int SetCommand(struct cmdargs const *); 171 static int LinkCommand(struct cmdargs const *); 172 static int AddCommand(struct cmdargs const *); 173 static int DeleteCommand(struct cmdargs const *); 174 static int NegotiateCommand(struct cmdargs const *); 175 static int ClearCommand(struct cmdargs const *); 176 static int RunListCommand(struct cmdargs const *); 177 static int IfaceAddCommand(struct cmdargs const *); 178 static int IfaceDeleteCommand(struct cmdargs const *); 179 static int IfaceClearCommand(struct cmdargs const *); 180 static int SetProcTitle(struct cmdargs const *); 181 #ifndef NONAT 182 static int NatEnable(struct cmdargs const *); 183 static int NatOption(struct cmdargs const *); 184 #endif 185 186 static const char * 187 showcx(struct cmdtab const *cmd) 188 { 189 if (cmd->lauth & LOCAL_CX) 190 return "(c)"; 191 else if (cmd->lauth & LOCAL_CX_OPT) 192 return "(o)"; 193 194 return ""; 195 } 196 197 static int 198 HelpCommand(struct cmdargs const *arg) 199 { 200 struct cmdtab const *cmd; 201 int n, cmax, dmax, cols, cxlen; 202 const char *cx; 203 204 if (!arg->prompt) { 205 log_Printf(LogWARN, "help: Cannot help without a prompt\n"); 206 return 0; 207 } 208 209 if (arg->argc > arg->argn) { 210 for (cmd = arg->cmdtab; cmd->name || cmd->alias; cmd++) 211 if ((cmd->lauth & arg->prompt->auth) && 212 ((cmd->name && !strcasecmp(cmd->name, arg->argv[arg->argn])) || 213 (cmd->alias && !strcasecmp(cmd->alias, arg->argv[arg->argn])))) { 214 prompt_Printf(arg->prompt, "%s %s\n", cmd->syntax, showcx(cmd)); 215 return 0; 216 } 217 return -1; 218 } 219 220 cmax = dmax = 0; 221 for (cmd = arg->cmdtab; cmd->func; cmd++) 222 if (cmd->name && (cmd->lauth & arg->prompt->auth)) { 223 if ((n = strlen(cmd->name) + strlen(showcx(cmd))) > cmax) 224 cmax = n; 225 if ((n = strlen(cmd->helpmes)) > dmax) 226 dmax = n; 227 } 228 229 cols = 80 / (dmax + cmax + 3); 230 n = 0; 231 prompt_Printf(arg->prompt, "(o) = Optional context," 232 " (c) = Context required\n"); 233 for (cmd = arg->cmdtab; cmd->func; cmd++) 234 if (cmd->name && (cmd->lauth & arg->prompt->auth)) { 235 cx = showcx(cmd); 236 cxlen = cmax - strlen(cmd->name); 237 if (n % cols != 0) 238 prompt_Printf(arg->prompt, " "); 239 prompt_Printf(arg->prompt, "%s%-*.*s: %-*.*s", 240 cmd->name, cxlen, cxlen, cx, dmax, dmax, cmd->helpmes); 241 if (++n % cols == 0) 242 prompt_Printf(arg->prompt, "\n"); 243 } 244 if (n % cols != 0) 245 prompt_Printf(arg->prompt, "\n"); 246 247 return 0; 248 } 249 250 static int 251 IdentCommand(struct cmdargs const *arg) 252 { 253 int f, pos; 254 255 *arg->cx->physical->link.lcp.cfg.ident = '\0'; 256 257 for (pos = 0, f = arg->argn; f < arg->argc; f++) 258 pos += snprintf(arg->cx->physical->link.lcp.cfg.ident + pos, 259 sizeof arg->cx->physical->link.lcp.cfg.ident - pos, "%s%s", 260 f == arg->argn ? "" : " ", arg->argv[f]); 261 262 return 0; 263 } 264 265 static int 266 SendIdentification(struct cmdargs const *arg) 267 { 268 if (arg->cx->state < DATALINK_LCP) { 269 log_Printf(LogWARN, "sendident: link has not reached LCP\n"); 270 return 2; 271 } 272 return lcp_SendIdentification(&arg->cx->physical->link.lcp) ? 0 : 1; 273 } 274 275 static int 276 CloneCommand(struct cmdargs const *arg) 277 { 278 char namelist[LINE_LEN]; 279 char *name; 280 int f; 281 282 if (arg->argc == arg->argn) 283 return -1; 284 285 namelist[sizeof namelist - 1] = '\0'; 286 for (f = arg->argn; f < arg->argc; f++) { 287 strncpy(namelist, arg->argv[f], sizeof namelist - 1); 288 for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) 289 bundle_DatalinkClone(arg->bundle, arg->cx, name); 290 } 291 292 return 0; 293 } 294 295 static int 296 RemoveCommand(struct cmdargs const *arg) 297 { 298 if (arg->argc != arg->argn) 299 return -1; 300 301 if (arg->cx->state != DATALINK_CLOSED) { 302 log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n"); 303 return 2; 304 } 305 306 bundle_DatalinkRemove(arg->bundle, arg->cx); 307 return 0; 308 } 309 310 static int 311 RenameCommand(struct cmdargs const *arg) 312 { 313 if (arg->argc != arg->argn + 1) 314 return -1; 315 316 if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn])) 317 return 0; 318 319 log_Printf(LogWARN, "%s -> %s: target name already exists\n", 320 arg->cx->name, arg->argv[arg->argn]); 321 return 1; 322 } 323 324 int 325 LoadCommand(struct cmdargs const *arg) 326 { 327 const char *err; 328 int n, mode; 329 330 mode = arg->bundle->phys_type.all; 331 332 if (arg->argn < arg->argc) { 333 for (n = arg->argn; n < arg->argc; n++) 334 if ((err = system_IsValid(arg->argv[n], arg->prompt, mode)) != NULL) { 335 log_Printf(LogWARN, "%s: %s\n", arg->argv[n], err); 336 return 1; 337 } 338 339 for (n = arg->argn; n < arg->argc; n++) { 340 bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]); 341 system_Select(arg->bundle, arg->argv[n], CONFFILE, arg->prompt, arg->cx); 342 } 343 bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]); 344 } else if ((err = system_IsValid("default", arg->prompt, mode)) != NULL) { 345 log_Printf(LogWARN, "default: %s\n", err); 346 return 1; 347 } else { 348 bundle_SetLabel(arg->bundle, "default"); 349 system_Select(arg->bundle, "default", CONFFILE, arg->prompt, arg->cx); 350 bundle_SetLabel(arg->bundle, "default"); 351 } 352 353 return 0; 354 } 355 356 int 357 SaveCommand(struct cmdargs const *arg) 358 { 359 log_Printf(LogWARN, "save command is not implemented (yet).\n"); 360 return 1; 361 } 362 363 static int 364 DialCommand(struct cmdargs const *arg) 365 { 366 int res; 367 368 if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO))) 369 || (!arg->cx && 370 (arg->bundle->phys_type.all & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) { 371 log_Printf(LogWARN, "Manual dial is only available for auto and" 372 " interactive links\n"); 373 return 1; 374 } 375 376 if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0) 377 return res; 378 379 bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1); 380 381 return 0; 382 } 383 384 #define isinword(ch) (isalnum(ch) || (ch) == '_') 385 386 static char * 387 strstrword(char *big, const char *little) 388 { 389 /* Get the first occurance of the word ``little'' in ``big'' */ 390 char *pos; 391 int len; 392 393 pos = big; 394 len = strlen(little); 395 396 while ((pos = strstr(pos, little)) != NULL) 397 if ((pos != big && isinword(pos[-1])) || isinword(pos[len])) 398 pos++; 399 else if (pos != big && pos[-1] == '\\') 400 memmove(pos - 1, pos, strlen(pos) + 1); 401 else 402 break; 403 404 return pos; 405 } 406 407 static char * 408 subst(char *tgt, const char *oldstr, const char *newstr) 409 { 410 /* tgt is a malloc()d area... realloc() as necessary */ 411 char *word, *ntgt; 412 int ltgt, loldstr, lnewstr, pos; 413 414 if ((word = strstrword(tgt, oldstr)) == NULL) 415 return tgt; 416 417 ltgt = strlen(tgt) + 1; 418 loldstr = strlen(oldstr); 419 lnewstr = strlen(newstr); 420 do { 421 pos = word - tgt; 422 if (loldstr > lnewstr) 423 bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr); 424 if (loldstr != lnewstr) { 425 ntgt = realloc(tgt, ltgt += lnewstr - loldstr); 426 if (ntgt == NULL) 427 break; /* Oh wonderful ! */ 428 word = ntgt + pos; 429 tgt = ntgt; 430 } 431 if (lnewstr > loldstr) 432 bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr); 433 bcopy(newstr, word, lnewstr); 434 } while ((word = strstrword(word, oldstr))); 435 436 return tgt; 437 } 438 439 void 440 command_Expand(char **nargv, int argc, char const *const *oargv, 441 struct bundle *bundle, int inc0, pid_t pid) 442 { 443 int arg; 444 char pidstr[12]; 445 446 if (inc0) 447 arg = 0; /* Start at arg 0 */ 448 else { 449 nargv[0] = strdup(oargv[0]); 450 arg = 1; 451 } 452 snprintf(pidstr, sizeof pidstr, "%d", (int)pid); 453 for (; arg < argc; arg++) { 454 nargv[arg] = strdup(oargv[arg]); 455 nargv[arg] = subst(nargv[arg], "HISADDR", 456 inet_ntoa(bundle->ncp.ipcp.peer_ip)); 457 nargv[arg] = subst(nargv[arg], "AUTHNAME", bundle->cfg.auth.name); 458 nargv[arg] = subst(nargv[arg], "INTERFACE", bundle->iface->name); 459 nargv[arg] = subst(nargv[arg], "MYADDR", inet_ntoa(bundle->ncp.ipcp.my_ip)); 460 nargv[arg] = subst(nargv[arg], "USER", bundle->ncp.mp.peer.authname); 461 nargv[arg] = subst(nargv[arg], "PEER_ENDDISC", 462 mp_Enddisc(bundle->ncp.mp.peer.enddisc.class, 463 bundle->ncp.mp.peer.enddisc.address, 464 bundle->ncp.mp.peer.enddisc.len)); 465 nargv[arg] = subst(nargv[arg], "ENDDISC", 466 mp_Enddisc(bundle->ncp.mp.cfg.enddisc.class, 467 bundle->ncp.mp.cfg.enddisc.address, 468 bundle->ncp.mp.cfg.enddisc.len)); 469 nargv[arg] = subst(nargv[arg], "PROCESSID", pidstr); 470 nargv[arg] = subst(nargv[arg], "LABEL", bundle_GetLabel(bundle)); 471 nargv[arg] = subst(nargv[arg], "DNS0", 472 inet_ntoa(bundle->ncp.ipcp.ns.dns[0])); 473 nargv[arg] = subst(nargv[arg], "DNS1", 474 inet_ntoa(bundle->ncp.ipcp.ns.dns[1])); 475 nargv[arg] = subst(nargv[arg], "VERSION", Version); 476 nargv[arg] = subst(nargv[arg], "COMPILATIONDATE", __DATE__); 477 } 478 nargv[arg] = NULL; 479 } 480 481 static int 482 ShellCommand(struct cmdargs const *arg, int bg) 483 { 484 const char *shell; 485 pid_t shpid, pid; 486 487 #ifdef SHELL_ONLY_INTERACTIVELY 488 /* we're only allowed to shell when we run ppp interactively */ 489 if (arg->prompt && arg->prompt->owner) { 490 log_Printf(LogWARN, "Can't start a shell from a network connection\n"); 491 return 1; 492 } 493 #endif 494 495 if (arg->argc == arg->argn) { 496 if (!arg->prompt) { 497 log_Printf(LogWARN, "Can't start an interactive shell from" 498 " a config file\n"); 499 return 1; 500 } else if (arg->prompt->owner) { 501 log_Printf(LogWARN, "Can't start an interactive shell from" 502 " a socket connection\n"); 503 return 1; 504 } else if (bg) { 505 log_Printf(LogWARN, "Can only start an interactive shell in" 506 " the foreground mode\n"); 507 return 1; 508 } 509 } 510 511 pid = getpid(); 512 if ((shpid = fork()) == 0) { 513 int i, fd; 514 515 if ((shell = getenv("SHELL")) == 0) 516 shell = _PATH_BSHELL; 517 518 timer_TermService(); 519 520 if (arg->prompt) 521 fd = arg->prompt->fd_out; 522 else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) { 523 log_Printf(LogALERT, "Failed to open %s: %s\n", 524 _PATH_DEVNULL, strerror(errno)); 525 exit(1); 526 } 527 dup2(fd, STDIN_FILENO); 528 dup2(fd, STDOUT_FILENO); 529 dup2(fd, STDERR_FILENO); 530 for (i = getdtablesize(); i > STDERR_FILENO; i--) 531 fcntl(i, F_SETFD, 1); 532 533 #ifndef NOSUID 534 setuid(ID0realuid()); 535 #endif 536 if (arg->argc > arg->argn) { 537 /* substitute pseudo args */ 538 char *argv[MAXARGS]; 539 int argc = arg->argc - arg->argn; 540 541 if (argc >= sizeof argv / sizeof argv[0]) { 542 argc = sizeof argv / sizeof argv[0] - 1; 543 log_Printf(LogWARN, "Truncating shell command to %d args\n", argc); 544 } 545 command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 0, pid); 546 if (bg) { 547 pid_t p; 548 549 p = getpid(); 550 if (daemon(1, 1) == -1) { 551 log_Printf(LogERROR, "%d: daemon: %s\n", (int)p, strerror(errno)); 552 exit(1); 553 } 554 } else if (arg->prompt) 555 printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]); 556 execvp(argv[0], argv); 557 } else { 558 if (arg->prompt) 559 printf("ppp: Pausing until %s finishes\n", shell); 560 prompt_TtyOldMode(arg->prompt); 561 execl(shell, shell, NULL); 562 } 563 564 log_Printf(LogWARN, "exec() of %s failed: %s\n", 565 arg->argc > arg->argn ? arg->argv[arg->argn] : shell, 566 strerror(errno)); 567 _exit(255); 568 } 569 570 if (shpid == (pid_t) - 1) 571 log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno)); 572 else { 573 int status; 574 waitpid(shpid, &status, 0); 575 } 576 577 if (arg->prompt && !arg->prompt->owner) 578 prompt_TtyCommandMode(arg->prompt); 579 580 return 0; 581 } 582 583 static int 584 BgShellCommand(struct cmdargs const *arg) 585 { 586 if (arg->argc == arg->argn) 587 return -1; 588 return ShellCommand(arg, 1); 589 } 590 591 static int 592 FgShellCommand(struct cmdargs const *arg) 593 { 594 return ShellCommand(arg, 0); 595 } 596 597 static int 598 ResolvCommand(struct cmdargs const *arg) 599 { 600 if (arg->argc == arg->argn + 1) { 601 if (!strcasecmp(arg->argv[arg->argn], "reload")) 602 ipcp_LoadDNS(&arg->bundle->ncp.ipcp); 603 else if (!strcasecmp(arg->argv[arg->argn], "restore")) 604 ipcp_RestoreDNS(&arg->bundle->ncp.ipcp); 605 else if (!strcasecmp(arg->argv[arg->argn], "rewrite")) 606 ipcp_WriteDNS(&arg->bundle->ncp.ipcp); 607 else if (!strcasecmp(arg->argv[arg->argn], "readonly")) 608 arg->bundle->ncp.ipcp.ns.writable = 0; 609 else if (!strcasecmp(arg->argv[arg->argn], "writable")) 610 arg->bundle->ncp.ipcp.ns.writable = 1; 611 else 612 return -1; 613 614 return 0; 615 } 616 617 return -1; 618 } 619 620 #ifndef NONAT 621 static struct cmdtab const NatCommands[] = 622 { 623 {"addr", NULL, nat_RedirectAddr, LOCAL_AUTH, 624 "static address translation", "nat addr [addr_local addr_alias]"}, 625 {"deny_incoming", NULL, NatOption, LOCAL_AUTH, 626 "stop incoming connections", "nat deny_incoming yes|no", 627 (const void *) PKT_ALIAS_DENY_INCOMING}, 628 {"enable", NULL, NatEnable, LOCAL_AUTH, 629 "enable NAT", "nat enable yes|no"}, 630 {"log", NULL, NatOption, LOCAL_AUTH, 631 "log NAT link creation", "nat log yes|no", 632 (const void *) PKT_ALIAS_LOG}, 633 {"port", NULL, nat_RedirectPort, LOCAL_AUTH, "port redirection", 634 "nat port proto localaddr:port[-port] aliasport[-aliasport]"}, 635 {"proxy", NULL, nat_ProxyRule, LOCAL_AUTH, 636 "proxy control", "nat proxy server host[:port] ..."}, 637 {"same_ports", NULL, NatOption, LOCAL_AUTH, 638 "try to leave port numbers unchanged", "nat same_ports yes|no", 639 (const void *) PKT_ALIAS_SAME_PORTS}, 640 {"target", NULL, nat_SetTarget, LOCAL_AUTH, 641 "Default address for incoming connections", "nat target addr" }, 642 {"unregistered_only", NULL, NatOption, LOCAL_AUTH, 643 "translate unregistered (private) IP address space only", 644 "nat unregistered_only yes|no", 645 (const void *) PKT_ALIAS_UNREGISTERED_ONLY}, 646 {"use_sockets", NULL, NatOption, LOCAL_AUTH, 647 "allocate host sockets", "nat use_sockets yes|no", 648 (const void *) PKT_ALIAS_USE_SOCKETS}, 649 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 650 "Display this message", "nat help|? [command]", NatCommands}, 651 {NULL, NULL, NULL}, 652 }; 653 #endif 654 655 static struct cmdtab const AllowCommands[] = { 656 {"modes", "mode", AllowModes, LOCAL_AUTH, 657 "Only allow certain ppp modes", "allow modes mode..."}, 658 {"users", "user", AllowUsers, LOCAL_AUTH, 659 "Only allow ppp access to certain users", "allow users logname..."}, 660 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 661 "Display this message", "allow help|? [command]", AllowCommands}, 662 {NULL, NULL, NULL}, 663 }; 664 665 static struct cmdtab const IfaceCommands[] = 666 { 667 {"add", NULL, IfaceAddCommand, LOCAL_AUTH, 668 "Add iface address", "iface add addr[/bits| mask] peer", NULL}, 669 {NULL, "add!", IfaceAddCommand, LOCAL_AUTH, 670 "Add or change an iface address", "iface add! addr[/bits| mask] peer", 671 (void *)1}, 672 {"clear", NULL, IfaceClearCommand, LOCAL_AUTH, 673 "Clear iface address(es)", "iface clear"}, 674 {"delete", "rm", IfaceDeleteCommand, LOCAL_AUTH, 675 "Delete iface address", "iface delete addr", NULL}, 676 {NULL, "rm!", IfaceDeleteCommand, LOCAL_AUTH, 677 "Delete iface address", "iface delete addr", (void *)1}, 678 {NULL, "delete!", IfaceDeleteCommand, LOCAL_AUTH, 679 "Delete iface address", "iface delete addr", (void *)1}, 680 {"show", NULL, iface_Show, LOCAL_AUTH, 681 "Show iface address(es)", "iface show"}, 682 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 683 "Display this message", "nat help|? [command]", IfaceCommands}, 684 {NULL, NULL, NULL}, 685 }; 686 687 static struct cmdtab const Commands[] = { 688 {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT, 689 "accept option request", "accept option .."}, 690 {"add", NULL, AddCommand, LOCAL_AUTH, 691 "add route", "add dest mask gateway", NULL}, 692 {NULL, "add!", AddCommand, LOCAL_AUTH, 693 "add or change route", "add! dest mask gateway", (void *)1}, 694 {"allow", "auth", RunListCommand, LOCAL_AUTH, 695 "Allow ppp access", "allow users|modes ....", AllowCommands}, 696 {"bg", "!bg", BgShellCommand, LOCAL_AUTH, 697 "Run a background command", "[!]bg command"}, 698 {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT, 699 "Clear throughput statistics", 700 "clear ipcp|physical [current|overall|peak]..."}, 701 {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX, 702 "Clone a link", "clone newname..."}, 703 {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT, 704 "Close an FSM", "close [lcp|ccp]"}, 705 {"delete", NULL, DeleteCommand, LOCAL_AUTH, 706 "delete route", "delete dest", NULL}, 707 {NULL, "delete!", DeleteCommand, LOCAL_AUTH, 708 "delete a route if it exists", "delete! dest", (void *)1}, 709 {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT, 710 "Deny option request", "deny option .."}, 711 {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT, 712 "Dial and login", "dial|call [system ...]", NULL}, 713 {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT, 714 "Disable option", "disable option .."}, 715 {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT, 716 "Generate a down event", "down [ccp|lcp]"}, 717 {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT, 718 "Enable option", "enable option .."}, 719 {"ident", NULL, IdentCommand, LOCAL_AUTH | LOCAL_CX, 720 "Set the link identity", "ident text..."}, 721 {"iface", "interface", RunListCommand, LOCAL_AUTH, 722 "interface control", "iface option ...", IfaceCommands}, 723 {"link", "datalink", LinkCommand, LOCAL_AUTH, 724 "Link specific commands", "link name command ..."}, 725 {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT, 726 "Load settings", "load [system ...]"}, 727 #ifndef NONAT 728 {"nat", "alias", RunListCommand, LOCAL_AUTH, 729 "NAT control", "nat option yes|no", NatCommands}, 730 #endif 731 {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT, 732 "Open an FSM", "open! [lcp|ccp|ipcp]", (void *)1}, 733 {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH, 734 "Password for manipulation", "passwd LocalPassword"}, 735 {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 736 "Quit PPP program", "quit|bye [all]"}, 737 {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX, 738 "Remove a link", "remove"}, 739 {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX, 740 "Rename a link", "rename name"}, 741 {"resolv", NULL, ResolvCommand, LOCAL_AUTH, 742 "Manipulate resolv.conf", "resolv readonly|reload|restore|rewrite|writable"}, 743 {"save", NULL, SaveCommand, LOCAL_AUTH, 744 "Save settings", "save"}, 745 {"sendident", NULL, SendIdentification, LOCAL_AUTH | LOCAL_CX, 746 "Transmit the link identity", "sendident"}, 747 {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT, 748 "Set parameters", "set[up] var value"}, 749 {"shell", "!", FgShellCommand, LOCAL_AUTH, 750 "Run a subshell", "shell|! [sh command]"}, 751 {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT, 752 "Show status and stats", "show var"}, 753 {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX, 754 "Enter terminal mode", "term"}, 755 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 756 "Display this message", "help|? [command]", Commands}, 757 {NULL, NULL, NULL}, 758 }; 759 760 static int 761 ShowEscape(struct cmdargs const *arg) 762 { 763 if (arg->cx->physical->async.cfg.EscMap[32]) { 764 int code, bit; 765 const char *sep = ""; 766 767 for (code = 0; code < 32; code++) 768 if (arg->cx->physical->async.cfg.EscMap[code]) 769 for (bit = 0; bit < 8; bit++) 770 if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) { 771 prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit); 772 sep = ", "; 773 } 774 prompt_Printf(arg->prompt, "\n"); 775 } 776 return 0; 777 } 778 779 static int 780 ShowTimerList(struct cmdargs const *arg) 781 { 782 timer_Show(0, arg->prompt); 783 return 0; 784 } 785 786 static int 787 ShowStopped(struct cmdargs const *arg) 788 { 789 prompt_Printf(arg->prompt, " Stopped Timer: LCP: "); 790 if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load) 791 prompt_Printf(arg->prompt, "Disabled"); 792 else 793 prompt_Printf(arg->prompt, "%ld secs", 794 arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS); 795 796 prompt_Printf(arg->prompt, ", CCP: "); 797 if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load) 798 prompt_Printf(arg->prompt, "Disabled"); 799 else 800 prompt_Printf(arg->prompt, "%ld secs", 801 arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS); 802 803 prompt_Printf(arg->prompt, "\n"); 804 805 return 0; 806 } 807 808 static int 809 ShowVersion(struct cmdargs const *arg) 810 { 811 prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, __DATE__); 812 return 0; 813 } 814 815 static int 816 ShowProtocolStats(struct cmdargs const *arg) 817 { 818 struct link *l = command_ChooseLink(arg); 819 820 prompt_Printf(arg->prompt, "%s:\n", l->name); 821 link_ReportProtocolStatus(l, arg->prompt); 822 return 0; 823 } 824 825 static struct cmdtab const ShowCommands[] = { 826 {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH, 827 "bundle details", "show bundle"}, 828 {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT, 829 "CCP status", "show cpp"}, 830 {"compress", NULL, sl_Show, LOCAL_AUTH, 831 "VJ compression stats", "show compress"}, 832 {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX, 833 "escape characters", "show escape"}, 834 {"filter", NULL, filter_Show, LOCAL_AUTH, 835 "packet filters", "show filter [in|out|dial|alive]"}, 836 {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX, 837 "HDLC errors", "show hdlc"}, 838 {"iface", "interface", iface_Show, LOCAL_AUTH, 839 "Interface status", "show iface"}, 840 {"ipcp", NULL, ipcp_Show, LOCAL_AUTH, 841 "IPCP status", "show ipcp"}, 842 {"layers", NULL, link_ShowLayers, LOCAL_AUTH | LOCAL_CX_OPT, 843 "Protocol layers", "show layers"}, 844 {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX, 845 "LCP status", "show lcp"}, 846 {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX, 847 "(high-level) link info", "show link"}, 848 {"links", NULL, bundle_ShowLinks, LOCAL_AUTH, 849 "available link names", "show links"}, 850 {"log", NULL, log_ShowLevel, LOCAL_AUTH, 851 "log levels", "show log"}, 852 {"mem", NULL, mbuf_Show, LOCAL_AUTH, 853 "mbuf allocations", "show mem"}, 854 {"physical", NULL, physical_ShowStatus, LOCAL_AUTH | LOCAL_CX, 855 "(low-level) link info", "show physical"}, 856 {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH, 857 "multilink setup", "show mp"}, 858 {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT, 859 "protocol summary", "show proto"}, 860 {"route", NULL, route_Show, LOCAL_AUTH, 861 "routing table", "show route"}, 862 {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX, 863 "STOPPED timeout", "show stopped"}, 864 {"timers", NULL, ShowTimerList, LOCAL_AUTH, 865 "alarm timers", "show timers"}, 866 {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH, 867 "version string", "show version"}, 868 {"who", NULL, log_ShowWho, LOCAL_AUTH, 869 "client list", "show who"}, 870 {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH, 871 "Display this message", "show help|? [command]", ShowCommands}, 872 {NULL, NULL, NULL}, 873 }; 874 875 static struct cmdtab const * 876 FindCommand(struct cmdtab const *cmds, const char *str, int *pmatch) 877 { 878 int nmatch; 879 int len; 880 struct cmdtab const *found; 881 882 found = NULL; 883 len = strlen(str); 884 nmatch = 0; 885 while (cmds->func) { 886 if (cmds->name && strncasecmp(str, cmds->name, len) == 0) { 887 if (cmds->name[len] == '\0') { 888 *pmatch = 1; 889 return cmds; 890 } 891 nmatch++; 892 found = cmds; 893 } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) { 894 if (cmds->alias[len] == '\0') { 895 *pmatch = 1; 896 return cmds; 897 } 898 nmatch++; 899 found = cmds; 900 } 901 cmds++; 902 } 903 *pmatch = nmatch; 904 return found; 905 } 906 907 static const char * 908 mkPrefix(int argc, char const *const *argv, char *tgt, int sz) 909 { 910 int f, tlen, len; 911 912 tlen = 0; 913 for (f = 0; f < argc && tlen < sz - 2; f++) { 914 if (f) 915 tgt[tlen++] = ' '; 916 len = strlen(argv[f]); 917 if (len > sz - tlen - 1) 918 len = sz - tlen - 1; 919 strncpy(tgt+tlen, argv[f], len); 920 tlen += len; 921 } 922 tgt[tlen] = '\0'; 923 return tgt; 924 } 925 926 static int 927 FindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn, 928 char const *const *argv, struct prompt *prompt, struct datalink *cx) 929 { 930 struct cmdtab const *cmd; 931 int val = 1; 932 int nmatch; 933 struct cmdargs arg; 934 char prefix[100]; 935 936 cmd = FindCommand(cmds, argv[argn], &nmatch); 937 if (nmatch > 1) 938 log_Printf(LogWARN, "%s: Ambiguous command\n", 939 mkPrefix(argn+1, argv, prefix, sizeof prefix)); 940 else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) { 941 if ((cmd->lauth & LOCAL_CX) && !cx) 942 /* We've got no context, but we require it */ 943 cx = bundle2datalink(bundle, NULL); 944 945 if ((cmd->lauth & LOCAL_CX) && !cx) 946 log_Printf(LogWARN, "%s: No context (use the `link' command)\n", 947 mkPrefix(argn+1, argv, prefix, sizeof prefix)); 948 else { 949 if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) { 950 log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n", 951 mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name); 952 cx = NULL; 953 } 954 arg.cmdtab = cmds; 955 arg.cmd = cmd; 956 arg.argc = argc; 957 arg.argn = argn+1; 958 arg.argv = argv; 959 arg.bundle = bundle; 960 arg.cx = cx; 961 arg.prompt = prompt; 962 val = (*cmd->func) (&arg); 963 } 964 } else 965 log_Printf(LogWARN, "%s: Invalid command\n", 966 mkPrefix(argn+1, argv, prefix, sizeof prefix)); 967 968 if (val == -1) 969 log_Printf(LogWARN, "Usage: %s\n", cmd->syntax); 970 else if (val) 971 log_Printf(LogWARN, "%s: Failed %d\n", 972 mkPrefix(argn+1, argv, prefix, sizeof prefix), val); 973 974 return val; 975 } 976 977 int 978 command_Expand_Interpret(char *buff, int nb, char *argv[MAXARGS], int offset) 979 { 980 char buff2[LINE_LEN-offset]; 981 982 InterpretArg(buff, buff2); 983 strncpy(buff, buff2, LINE_LEN - offset - 1); 984 buff[LINE_LEN - offset - 1] = '\0'; 985 986 return command_Interpret(buff, nb, argv); 987 } 988 989 int 990 command_Interpret(char *buff, int nb, char *argv[MAXARGS]) 991 { 992 char *cp; 993 994 if (nb > 0) { 995 cp = buff + strcspn(buff, "\r\n"); 996 if (cp) 997 *cp = '\0'; 998 return MakeArgs(buff, argv, MAXARGS, PARSE_REDUCE); 999 } 1000 return 0; 1001 } 1002 1003 static int 1004 arghidden(int argc, char const *const *argv, int n) 1005 { 1006 /* Is arg n of the given command to be hidden from the log ? */ 1007 1008 /* set authkey xxxxx */ 1009 /* set key xxxxx */ 1010 if (n == 2 && !strncasecmp(argv[0], "se", 2) && 1011 (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2))) 1012 return 1; 1013 1014 /* passwd xxxxx */ 1015 if (n == 1 && !strncasecmp(argv[0], "p", 1)) 1016 return 1; 1017 1018 /* set server port xxxxx .... */ 1019 if (n == 3 && !strncasecmp(argv[0], "se", 2) && 1020 !strncasecmp(argv[1], "se", 2)) 1021 return 1; 1022 1023 return 0; 1024 } 1025 1026 void 1027 command_Run(struct bundle *bundle, int argc, char const *const *argv, 1028 struct prompt *prompt, const char *label, struct datalink *cx) 1029 { 1030 if (argc > 0) { 1031 if (log_IsKept(LogCOMMAND)) { 1032 char buf[LINE_LEN]; 1033 int f, n; 1034 1035 if (label) { 1036 strncpy(buf, label, sizeof buf - 3); 1037 buf[sizeof buf - 3] = '\0'; 1038 strcat(buf, ": "); 1039 n = strlen(buf); 1040 } else { 1041 *buf = '\0'; 1042 n = 0; 1043 } 1044 buf[sizeof buf - 1] = '\0'; /* In case we run out of room in buf */ 1045 1046 for (f = 0; f < argc; f++) { 1047 if (n < sizeof buf - 1 && f) 1048 buf[n++] = ' '; 1049 if (arghidden(argc, argv, f)) 1050 strncpy(buf+n, "********", sizeof buf - n - 1); 1051 else 1052 strncpy(buf+n, argv[f], sizeof buf - n - 1); 1053 n += strlen(buf+n); 1054 } 1055 log_Printf(LogCOMMAND, "%s\n", buf); 1056 } 1057 FindExec(bundle, Commands, argc, 0, argv, prompt, cx); 1058 } 1059 } 1060 1061 int 1062 command_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt, 1063 const char *label) 1064 { 1065 int argc; 1066 char *argv[MAXARGS]; 1067 1068 if ((argc = command_Expand_Interpret(buff, nb, argv, 0)) < 0) 1069 return 0; 1070 1071 command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL); 1072 return 1; 1073 } 1074 1075 static int 1076 ShowCommand(struct cmdargs const *arg) 1077 { 1078 if (!arg->prompt) 1079 log_Printf(LogWARN, "show: Cannot show without a prompt\n"); 1080 else if (arg->argc > arg->argn) 1081 FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv, 1082 arg->prompt, arg->cx); 1083 else 1084 prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n"); 1085 1086 return 0; 1087 } 1088 1089 static int 1090 TerminalCommand(struct cmdargs const *arg) 1091 { 1092 if (!arg->prompt) { 1093 log_Printf(LogWARN, "term: Need a prompt\n"); 1094 return 1; 1095 } 1096 1097 if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) { 1098 prompt_Printf(arg->prompt, "LCP state is [%s]\n", 1099 State2Nam(arg->cx->physical->link.lcp.fsm.state)); 1100 return 1; 1101 } 1102 1103 datalink_Up(arg->cx, 0, 0); 1104 prompt_TtyTermMode(arg->prompt, arg->cx); 1105 return 0; 1106 } 1107 1108 static int 1109 QuitCommand(struct cmdargs const *arg) 1110 { 1111 if (!arg->prompt || prompt_IsController(arg->prompt) || 1112 (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") && 1113 (arg->prompt->auth & LOCAL_AUTH))) 1114 Cleanup(EX_NORMAL); 1115 if (arg->prompt) 1116 prompt_Destroy(arg->prompt, 1); 1117 1118 return 0; 1119 } 1120 1121 static int 1122 OpenCommand(struct cmdargs const *arg) 1123 { 1124 if (arg->argc == arg->argn) 1125 bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1); 1126 else if (arg->argc == arg->argn + 1) { 1127 if (!strcasecmp(arg->argv[arg->argn], "lcp")) { 1128 struct datalink *cx = arg->cx ? 1129 arg->cx : bundle2datalink(arg->bundle, NULL); 1130 if (cx) { 1131 if (cx->physical->link.lcp.fsm.state == ST_OPENED) 1132 fsm_Reopen(&cx->physical->link.lcp.fsm); 1133 else 1134 bundle_Open(arg->bundle, cx->name, PHYS_ALL, 1); 1135 } else 1136 log_Printf(LogWARN, "open lcp: You must specify a link\n"); 1137 } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) { 1138 struct fsm *fp; 1139 1140 fp = &command_ChooseLink(arg)->ccp.fsm; 1141 if (fp->link->lcp.fsm.state != ST_OPENED) 1142 log_Printf(LogWARN, "open: LCP must be open before opening CCP\n"); 1143 else if (fp->state == ST_OPENED) 1144 fsm_Reopen(fp); 1145 else { 1146 fp->open_mode = 0; /* Not passive any more */ 1147 if (fp->state == ST_STOPPED) { 1148 fsm_Down(fp); 1149 fsm_Up(fp); 1150 } else { 1151 fsm_Up(fp); 1152 fsm_Open(fp); 1153 } 1154 } 1155 } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) { 1156 if (arg->cx) 1157 log_Printf(LogWARN, "open ipcp: You need not specify a link\n"); 1158 if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED) 1159 fsm_Reopen(&arg->bundle->ncp.ipcp.fsm); 1160 else 1161 bundle_Open(arg->bundle, NULL, PHYS_ALL, 1); 1162 } else 1163 return -1; 1164 } else 1165 return -1; 1166 1167 return 0; 1168 } 1169 1170 static int 1171 CloseCommand(struct cmdargs const *arg) 1172 { 1173 if (arg->argc == arg->argn) 1174 bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN); 1175 else if (arg->argc == arg->argn + 1) { 1176 if (!strcasecmp(arg->argv[arg->argn], "lcp")) 1177 bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP); 1178 else if (!strcasecmp(arg->argv[arg->argn], "ccp") || 1179 !strcasecmp(arg->argv[arg->argn], "ccp!")) { 1180 struct fsm *fp; 1181 1182 fp = &command_ChooseLink(arg)->ccp.fsm; 1183 if (fp->state == ST_OPENED) { 1184 fsm_Close(fp); 1185 if (arg->argv[arg->argn][3] == '!') 1186 fp->open_mode = 0; /* Stay ST_CLOSED */ 1187 else 1188 fp->open_mode = OPEN_PASSIVE; /* Wait for the peer to start */ 1189 } 1190 } else 1191 return -1; 1192 } else 1193 return -1; 1194 1195 return 0; 1196 } 1197 1198 static int 1199 DownCommand(struct cmdargs const *arg) 1200 { 1201 if (arg->argc == arg->argn) { 1202 if (arg->cx) 1203 datalink_Down(arg->cx, CLOSE_STAYDOWN); 1204 else 1205 bundle_Down(arg->bundle, CLOSE_STAYDOWN); 1206 } else if (arg->argc == arg->argn + 1) { 1207 if (!strcasecmp(arg->argv[arg->argn], "lcp")) { 1208 if (arg->cx) 1209 datalink_Down(arg->cx, CLOSE_LCP); 1210 else 1211 bundle_Down(arg->bundle, CLOSE_LCP); 1212 } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) { 1213 struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm : 1214 &arg->bundle->ncp.mp.link.ccp.fsm; 1215 fsm2initial(fp); 1216 } else 1217 return -1; 1218 } else 1219 return -1; 1220 1221 return 0; 1222 } 1223 1224 static int 1225 SetModemSpeed(struct cmdargs const *arg) 1226 { 1227 long speed; 1228 char *end; 1229 1230 if (arg->argc > arg->argn && *arg->argv[arg->argn]) { 1231 if (arg->argc > arg->argn+1) { 1232 log_Printf(LogWARN, "SetModemSpeed: Too many arguments\n"); 1233 return -1; 1234 } 1235 if (strcasecmp(arg->argv[arg->argn], "sync") == 0) { 1236 physical_SetSync(arg->cx->physical); 1237 return 0; 1238 } 1239 end = NULL; 1240 speed = strtol(arg->argv[arg->argn], &end, 10); 1241 if (*end) { 1242 log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"", 1243 arg->argv[arg->argn]); 1244 return -1; 1245 } 1246 if (physical_SetSpeed(arg->cx->physical, speed)) 1247 return 0; 1248 log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]); 1249 } else 1250 log_Printf(LogWARN, "SetModemSpeed: No speed specified\n"); 1251 1252 return -1; 1253 } 1254 1255 static int 1256 SetStoppedTimeout(struct cmdargs const *arg) 1257 { 1258 struct link *l = &arg->cx->physical->link; 1259 1260 l->lcp.fsm.StoppedTimer.load = 0; 1261 l->ccp.fsm.StoppedTimer.load = 0; 1262 if (arg->argc <= arg->argn+2) { 1263 if (arg->argc > arg->argn) { 1264 l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS; 1265 if (arg->argc > arg->argn+1) 1266 l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS; 1267 } 1268 return 0; 1269 } 1270 return -1; 1271 } 1272 1273 static int 1274 SetServer(struct cmdargs const *arg) 1275 { 1276 int res = -1; 1277 1278 if (arg->argc > arg->argn && arg->argc < arg->argn+4) { 1279 const char *port, *passwd, *mask; 1280 int mlen; 1281 1282 /* What's what ? */ 1283 port = arg->argv[arg->argn]; 1284 if (arg->argc == arg->argn + 2) { 1285 passwd = arg->argv[arg->argn+1]; 1286 mask = NULL; 1287 } else if (arg->argc == arg->argn + 3) { 1288 passwd = arg->argv[arg->argn+1]; 1289 mask = arg->argv[arg->argn+2]; 1290 mlen = strlen(mask); 1291 if (mlen == 0 || mlen > 4 || strspn(mask, "01234567") != mlen || 1292 (mlen == 4 && *mask != '0')) { 1293 log_Printf(LogWARN, "%s %s: %s: Invalid mask\n", 1294 arg->argv[arg->argn - 2], arg->argv[arg->argn - 1], mask); 1295 return -1; 1296 } 1297 } else if (arg->argc != arg->argn + 1) 1298 return -1; 1299 else if (strcasecmp(port, "none") == 0) { 1300 if (server_Clear(arg->bundle)) 1301 log_Printf(LogPHASE, "Disabled server socket\n"); 1302 return 0; 1303 } else if (strcasecmp(port, "open") == 0) { 1304 switch (server_Reopen(arg->bundle)) { 1305 case SERVER_OK: 1306 return 0; 1307 case SERVER_FAILED: 1308 log_Printf(LogWARN, "Failed to reopen server port\n"); 1309 return 1; 1310 case SERVER_UNSET: 1311 log_Printf(LogWARN, "Cannot reopen unset server socket\n"); 1312 return 1; 1313 default: 1314 break; 1315 } 1316 return -1; 1317 } else if (strcasecmp(port, "closed") == 0) { 1318 if (server_Close(arg->bundle)) 1319 log_Printf(LogPHASE, "Closed server socket\n"); 1320 else 1321 log_Printf(LogWARN, "Server socket not open\n"); 1322 1323 return 0; 1324 } else 1325 return -1; 1326 1327 strncpy(server.cfg.passwd, passwd, sizeof server.cfg.passwd - 1); 1328 server.cfg.passwd[sizeof server.cfg.passwd - 1] = '\0'; 1329 1330 if (*port == '/') { 1331 mode_t imask; 1332 char *ptr, name[LINE_LEN + 12]; 1333 1334 if (mask == NULL) 1335 imask = (mode_t)-1; 1336 else for (imask = mlen = 0; mask[mlen]; mlen++) 1337 imask = (imask * 8) + mask[mlen] - '0'; 1338 1339 ptr = strstr(port, "%d"); 1340 if (ptr) { 1341 snprintf(name, sizeof name, "%.*s%d%s", 1342 (int)(ptr - port), port, arg->bundle->unit, ptr + 2); 1343 port = name; 1344 } 1345 res = server_LocalOpen(arg->bundle, port, imask); 1346 } else { 1347 int iport, add = 0; 1348 1349 if (mask != NULL) 1350 return -1; 1351 1352 if (*port == '+') { 1353 port++; 1354 add = 1; 1355 } 1356 if (strspn(port, "0123456789") != strlen(port)) { 1357 struct servent *s; 1358 1359 if ((s = getservbyname(port, "tcp")) == NULL) { 1360 iport = 0; 1361 log_Printf(LogWARN, "%s: Invalid port or service\n", port); 1362 } else 1363 iport = ntohs(s->s_port); 1364 } else 1365 iport = atoi(port); 1366 1367 if (iport) { 1368 if (add) 1369 iport += arg->bundle->unit; 1370 res = server_TcpOpen(arg->bundle, iport); 1371 } else 1372 res = -1; 1373 } 1374 } 1375 1376 return res; 1377 } 1378 1379 static int 1380 SetEscape(struct cmdargs const *arg) 1381 { 1382 int code; 1383 int argc = arg->argc - arg->argn; 1384 char const *const *argv = arg->argv + arg->argn; 1385 1386 for (code = 0; code < 33; code++) 1387 arg->cx->physical->async.cfg.EscMap[code] = 0; 1388 1389 while (argc-- > 0) { 1390 sscanf(*argv++, "%x", &code); 1391 code &= 0xff; 1392 arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7)); 1393 arg->cx->physical->async.cfg.EscMap[32] = 1; 1394 } 1395 return 0; 1396 } 1397 1398 static int 1399 SetInterfaceAddr(struct cmdargs const *arg) 1400 { 1401 struct ipcp *ipcp = &arg->bundle->ncp.ipcp; 1402 const char *hisaddr; 1403 1404 if (arg->argc > arg->argn + 4) 1405 return -1; 1406 1407 hisaddr = NULL; 1408 memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range); 1409 memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); 1410 ipcp->cfg.HaveTriggerAddress = 0; 1411 ipcp->cfg.netmask.s_addr = INADDR_ANY; 1412 iplist_reset(&ipcp->cfg.peer_list); 1413 1414 if (arg->argc > arg->argn) { 1415 if (!ParseAddr(ipcp, arg->argv[arg->argn], 1416 &ipcp->cfg.my_range.ipaddr, &ipcp->cfg.my_range.mask, 1417 &ipcp->cfg.my_range.width)) 1418 return 1; 1419 if (arg->argc > arg->argn+1) { 1420 hisaddr = arg->argv[arg->argn+1]; 1421 if (arg->argc > arg->argn+2) { 1422 ipcp->ifmask = ipcp->cfg.netmask = GetIpAddr(arg->argv[arg->argn+2]); 1423 if (arg->argc > arg->argn+3) { 1424 ipcp->cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]); 1425 ipcp->cfg.HaveTriggerAddress = 1; 1426 } 1427 } 1428 } 1429 } 1430 1431 /* 0.0.0.0 means any address (0 bits) */ 1432 if (ipcp->cfg.my_range.ipaddr.s_addr == INADDR_ANY) { 1433 ipcp->cfg.my_range.mask.s_addr = INADDR_ANY; 1434 ipcp->cfg.my_range.width = 0; 1435 } 1436 ipcp->my_ip.s_addr = ipcp->cfg.my_range.ipaddr.s_addr; 1437 bundle_AdjustFilters(arg->bundle, &ipcp->my_ip, NULL); 1438 1439 if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr, 1440 arg->bundle->phys_type.all & PHYS_AUTO)) 1441 return 4; 1442 1443 return 0; 1444 } 1445 1446 static int 1447 SetRetry(int argc, char const *const *argv, u_int *timeout, u_int *maxreq, 1448 u_int *maxtrm, int def) 1449 { 1450 if (argc == 0) { 1451 *timeout = DEF_FSMRETRY; 1452 *maxreq = def; 1453 if (maxtrm != NULL) 1454 *maxtrm = def; 1455 } else { 1456 long l = atol(argv[0]); 1457 1458 if (l < MIN_FSMRETRY) { 1459 log_Printf(LogWARN, "%ld: Invalid FSM retry period - min %d\n", 1460 l, MIN_FSMRETRY); 1461 return 1; 1462 } else 1463 *timeout = l; 1464 1465 if (argc > 1) { 1466 l = atol(argv[1]); 1467 if (l < 1) { 1468 log_Printf(LogWARN, "%ld: Invalid FSM REQ tries - changed to 1\n", l); 1469 l = 1; 1470 } 1471 *maxreq = l; 1472 1473 if (argc > 2 && maxtrm != NULL) { 1474 l = atol(argv[2]); 1475 if (l < 1) { 1476 log_Printf(LogWARN, "%ld: Invalid FSM TRM tries - changed to 1\n", l); 1477 l = 1; 1478 } 1479 *maxtrm = l; 1480 } 1481 } 1482 } 1483 1484 return 0; 1485 } 1486 1487 static int 1488 SetVariable(struct cmdargs const *arg) 1489 { 1490 long long_val, param = (long)arg->cmd->args; 1491 int mode, dummyint, f, first; 1492 u_short *change; 1493 const char *argp; 1494 struct datalink *cx = arg->cx; /* LOCAL_CX uses this */ 1495 const char *err = NULL; 1496 struct link *l = command_ChooseLink(arg); /* LOCAL_CX_OPT uses this */ 1497 struct in_addr dummyaddr, *addr; 1498 1499 if (arg->argc > arg->argn) 1500 argp = arg->argv[arg->argn]; 1501 else 1502 argp = ""; 1503 1504 if ((arg->cmd->lauth & LOCAL_CX) && !cx) { 1505 log_Printf(LogWARN, "set %s: No context (use the `link' command)\n", 1506 arg->cmd->name); 1507 return 1; 1508 } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) { 1509 log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n", 1510 arg->cmd->name, cx->name); 1511 cx = NULL; 1512 } 1513 1514 switch (param) { 1515 case VAR_AUTHKEY: 1516 strncpy(arg->bundle->cfg.auth.key, argp, 1517 sizeof arg->bundle->cfg.auth.key - 1); 1518 arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0'; 1519 break; 1520 1521 case VAR_AUTHNAME: 1522 switch (bundle_Phase(arg->bundle)) { 1523 default: 1524 log_Printf(LogWARN, "Altering authname while at phase %s\n", 1525 bundle_PhaseName(arg->bundle)); 1526 /* drop through */ 1527 case PHASE_DEAD: 1528 case PHASE_ESTABLISH: 1529 strncpy(arg->bundle->cfg.auth.name, argp, 1530 sizeof arg->bundle->cfg.auth.name - 1); 1531 arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name-1] = '\0'; 1532 break; 1533 } 1534 break; 1535 1536 case VAR_AUTOLOAD: 1537 if (arg->argc == arg->argn + 3) { 1538 int v1, v2, v3; 1539 char *end; 1540 1541 v1 = strtol(arg->argv[arg->argn], &end, 0); 1542 if (v1 < 0 || *end) { 1543 log_Printf(LogWARN, "autoload: %s: Invalid min percentage\n", 1544 arg->argv[arg->argn]); 1545 return 1; 1546 } 1547 1548 v2 = strtol(arg->argv[arg->argn + 1], &end, 0); 1549 if (v2 < 0 || *end) { 1550 log_Printf(LogWARN, "autoload: %s: Invalid max percentage\n", 1551 arg->argv[arg->argn + 1]); 1552 return 1; 1553 } 1554 if (v2 < v1) { 1555 v3 = v1; 1556 v1 = v2; 1557 v2 = v3; 1558 } 1559 1560 v3 = strtol(arg->argv[arg->argn + 2], &end, 0); 1561 if (v3 <= 0 || *end) { 1562 log_Printf(LogWARN, "autoload: %s: Invalid throughput period\n", 1563 arg->argv[arg->argn + 2]); 1564 return 1; 1565 } 1566 1567 arg->bundle->ncp.mp.cfg.autoload.min = v1; 1568 arg->bundle->ncp.mp.cfg.autoload.max = v2; 1569 arg->bundle->ncp.mp.cfg.autoload.period = v3; 1570 mp_RestartAutoloadTimer(&arg->bundle->ncp.mp); 1571 } else { 1572 err = "Set autoload requires three arguments\n"; 1573 log_Printf(LogWARN, "%s", err); 1574 } 1575 break; 1576 1577 case VAR_DIAL: 1578 strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1); 1579 cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0'; 1580 break; 1581 1582 case VAR_LOGIN: 1583 strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1); 1584 cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0'; 1585 break; 1586 1587 case VAR_WINSIZE: 1588 if (arg->argc > arg->argn) { 1589 l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]); 1590 if (l->ccp.cfg.deflate.out.winsize < 8 || 1591 l->ccp.cfg.deflate.out.winsize > 15) { 1592 log_Printf(LogWARN, "%d: Invalid outgoing window size\n", 1593 l->ccp.cfg.deflate.out.winsize); 1594 l->ccp.cfg.deflate.out.winsize = 15; 1595 } 1596 if (arg->argc > arg->argn+1) { 1597 l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]); 1598 if (l->ccp.cfg.deflate.in.winsize < 8 || 1599 l->ccp.cfg.deflate.in.winsize > 15) { 1600 log_Printf(LogWARN, "%d: Invalid incoming window size\n", 1601 l->ccp.cfg.deflate.in.winsize); 1602 l->ccp.cfg.deflate.in.winsize = 15; 1603 } 1604 } else 1605 l->ccp.cfg.deflate.in.winsize = 0; 1606 } else { 1607 err = "No window size specified\n"; 1608 log_Printf(LogWARN, "%s", err); 1609 } 1610 break; 1611 1612 #ifdef HAVE_DES 1613 case VAR_MPPE: 1614 if (arg->argc > arg->argn + 2) 1615 return -1; 1616 1617 if (arg->argc == arg->argn) { 1618 l->ccp.cfg.mppe.keybits = 0; 1619 l->ccp.cfg.mppe.state = MPPE_ANYSTATE; 1620 l->ccp.cfg.mppe.required = 0; 1621 break; 1622 } 1623 1624 if (!strcmp(argp, "*")) 1625 long_val = 0; 1626 else { 1627 long_val = atol(argp); 1628 if (long_val != 40 && long_val != 56 && long_val != 128) { 1629 log_Printf(LogWARN, "%s: Invalid bits value\n", argp); 1630 return -1; 1631 } 1632 } 1633 1634 if (arg->argc == arg->argn + 2) { 1635 if (!strcmp(arg->argv[arg->argn + 1], "*")) 1636 l->ccp.cfg.mppe.state = MPPE_ANYSTATE; 1637 else if (!strcasecmp(arg->argv[arg->argn + 1], "stateless")) 1638 l->ccp.cfg.mppe.state = MPPE_STATELESS; 1639 else if (!strcasecmp(arg->argv[arg->argn + 1], "statefull")) 1640 l->ccp.cfg.mppe.state = MPPE_STATEFUL; 1641 else { 1642 log_Printf(LogWARN, "%s: Invalid state value\n", 1643 arg->argv[arg->argn + 1]); 1644 return -1; 1645 } 1646 } else 1647 l->ccp.cfg.mppe.state = MPPE_ANYSTATE; 1648 l->ccp.cfg.mppe.keybits = long_val; 1649 l->ccp.cfg.mppe.required = 1; 1650 break; 1651 #endif 1652 1653 case VAR_DEVICE: 1654 physical_SetDeviceList(cx->physical, arg->argc - arg->argn, 1655 arg->argv + arg->argn); 1656 break; 1657 1658 case VAR_ACCMAP: 1659 if (arg->argc > arg->argn) { 1660 u_long ulong_val; 1661 sscanf(argp, "%lx", &ulong_val); 1662 cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val; 1663 } else { 1664 err = "No accmap specified\n"; 1665 log_Printf(LogWARN, "%s", err); 1666 } 1667 break; 1668 1669 case VAR_MODE: 1670 mode = Nam2mode(argp); 1671 if (mode == PHYS_NONE || mode == PHYS_ALL) { 1672 log_Printf(LogWARN, "%s: Invalid mode\n", argp); 1673 return -1; 1674 } 1675 bundle_SetMode(arg->bundle, cx, mode); 1676 break; 1677 1678 case VAR_MRRU: 1679 switch (bundle_Phase(arg->bundle)) { 1680 case PHASE_DEAD: 1681 break; 1682 case PHASE_ESTABLISH: 1683 /* Make sure none of our links are DATALINK_LCP or greater */ 1684 if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) { 1685 log_Printf(LogWARN, "mrru: Only changable before LCP negotiations\n"); 1686 return 1; 1687 } 1688 break; 1689 default: 1690 log_Printf(LogWARN, "mrru: Only changable at phase DEAD/ESTABLISH\n"); 1691 return 1; 1692 } 1693 long_val = atol(argp); 1694 if (long_val && long_val < MIN_MRU) { 1695 log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU); 1696 return 1; 1697 } else if (long_val > MAX_MRU) { 1698 log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU); 1699 return 1; 1700 } else 1701 arg->bundle->ncp.mp.cfg.mrru = long_val; 1702 break; 1703 1704 case VAR_MRU: 1705 switch(arg->argc - arg->argn) { 1706 case 1: 1707 if (argp[strspn(argp, "0123456789")] != '\0') 1708 return -1; 1709 case 0: 1710 long_val = atol(argp); 1711 change = &l->lcp.cfg.mru; 1712 if (long_val > l->lcp.cfg.max_mru) { 1713 log_Printf(LogWARN, "MRU %ld: too large - max set to %d\n", long_val, 1714 l->lcp.cfg.max_mru); 1715 return 1; 1716 } 1717 break; 1718 case 2: 1719 if (strcasecmp(argp, "max") && strcasecmp(argp, "maximum")) 1720 return -1; 1721 long_val = atol(arg->argv[arg->argn + 1]); 1722 change = &l->lcp.cfg.max_mru; 1723 if (long_val > MAX_MRU) { 1724 log_Printf(LogWARN, "MRU %ld: too large - maximum is %d\n", long_val, 1725 MAX_MRU); 1726 return 1; 1727 } 1728 break; 1729 default: 1730 return -1; 1731 } 1732 1733 if (long_val == 0) 1734 *change = DEF_MRU; 1735 else if (long_val < MIN_MRU) { 1736 log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU); 1737 return 1; 1738 } else if (long_val > MAX_MRU) { 1739 log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU); 1740 return 1; 1741 } else 1742 *change = long_val; 1743 if (l->lcp.cfg.mru > *change) 1744 l->lcp.cfg.mru = *change; 1745 break; 1746 1747 case VAR_MTU: 1748 switch(arg->argc - arg->argn) { 1749 case 1: 1750 if (argp[strspn(argp, "0123456789")] != '\0') 1751 return -1; 1752 case 0: 1753 long_val = atol(argp); 1754 change = &l->lcp.cfg.mtu; 1755 if (long_val > l->lcp.cfg.max_mtu) { 1756 log_Printf(LogWARN, "MTU %ld: too large - max set to %d\n", long_val, 1757 l->lcp.cfg.max_mtu); 1758 return 1; 1759 } 1760 break; 1761 case 2: 1762 if (strcasecmp(argp, "max") && strcasecmp(argp, "maximum")) 1763 return -1; 1764 long_val = atol(arg->argv[arg->argn + 1]); 1765 change = &l->lcp.cfg.max_mtu; 1766 if (long_val > MAX_MTU) { 1767 log_Printf(LogWARN, "MTU %ld: too large - maximum is %d\n", long_val, 1768 MAX_MTU); 1769 return 1; 1770 } 1771 break; 1772 default: 1773 return -1; 1774 } 1775 1776 if (long_val && long_val < MIN_MTU) { 1777 log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU); 1778 return 1; 1779 } else if (long_val > MAX_MTU) { 1780 log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU); 1781 return 1; 1782 } else 1783 *change = long_val; 1784 if (l->lcp.cfg.mtu > *change) 1785 l->lcp.cfg.mtu = *change; 1786 break; 1787 1788 case VAR_OPENMODE: 1789 if (strcasecmp(argp, "active") == 0) 1790 cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ? 1791 atoi(arg->argv[arg->argn+1]) : 1; 1792 else if (strcasecmp(argp, "passive") == 0) 1793 cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE; 1794 else { 1795 err = "%s: Invalid openmode\n"; 1796 log_Printf(LogWARN, err, argp); 1797 } 1798 break; 1799 1800 case VAR_PHONE: 1801 strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1); 1802 cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0'; 1803 cx->phone.alt = cx->phone.next = NULL; 1804 break; 1805 1806 case VAR_HANGUP: 1807 strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1); 1808 cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0'; 1809 break; 1810 1811 case VAR_IFQUEUE: 1812 long_val = atol(argp); 1813 arg->bundle->cfg.ifqueue = long_val < 0 ? 0 : long_val; 1814 break; 1815 1816 case VAR_LOGOUT: 1817 strncpy(cx->cfg.script.logout, argp, sizeof cx->cfg.script.logout - 1); 1818 cx->cfg.script.logout[sizeof cx->cfg.script.logout - 1] = '\0'; 1819 break; 1820 1821 case VAR_IDLETIMEOUT: 1822 if (arg->argc > arg->argn+2) 1823 err = "Too many idle timeout values\n"; 1824 else if (arg->argc == arg->argn) 1825 err = "Too few idle timeout values\n"; 1826 else { 1827 int timeout, min; 1828 1829 timeout = atoi(argp); 1830 min = arg->argc == arg->argn + 2 ? atoi(arg->argv[arg->argn + 1]) : -1; 1831 bundle_SetIdleTimer(arg->bundle, timeout, min); 1832 } 1833 if (err) 1834 log_Printf(LogWARN, "%s", err); 1835 break; 1836 1837 case VAR_LQRPERIOD: 1838 long_val = atol(argp); 1839 if (long_val < MIN_LQRPERIOD) { 1840 log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n", 1841 long_val, MIN_LQRPERIOD); 1842 return 1; 1843 } else 1844 l->lcp.cfg.lqrperiod = long_val; 1845 break; 1846 1847 case VAR_LCPRETRY: 1848 return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn, 1849 &cx->physical->link.lcp.cfg.fsm.timeout, 1850 &cx->physical->link.lcp.cfg.fsm.maxreq, 1851 &cx->physical->link.lcp.cfg.fsm.maxtrm, DEF_FSMTRIES); 1852 break; 1853 1854 case VAR_CHAPRETRY: 1855 return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn, 1856 &cx->chap.auth.cfg.fsm.timeout, 1857 &cx->chap.auth.cfg.fsm.maxreq, NULL, DEF_FSMAUTHTRIES); 1858 break; 1859 1860 case VAR_PAPRETRY: 1861 return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn, 1862 &cx->pap.cfg.fsm.timeout, &cx->pap.cfg.fsm.maxreq, 1863 NULL, DEF_FSMAUTHTRIES); 1864 break; 1865 1866 case VAR_CCPRETRY: 1867 return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn, 1868 &l->ccp.cfg.fsm.timeout, &l->ccp.cfg.fsm.maxreq, 1869 &l->ccp.cfg.fsm.maxtrm, DEF_FSMTRIES); 1870 break; 1871 1872 case VAR_IPCPRETRY: 1873 return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn, 1874 &arg->bundle->ncp.ipcp.cfg.fsm.timeout, 1875 &arg->bundle->ncp.ipcp.cfg.fsm.maxreq, 1876 &arg->bundle->ncp.ipcp.cfg.fsm.maxtrm, DEF_FSMTRIES); 1877 break; 1878 1879 case VAR_NBNS: 1880 case VAR_DNS: 1881 if (param == VAR_DNS) { 1882 addr = arg->bundle->ncp.ipcp.cfg.ns.dns; 1883 addr[0].s_addr = addr[1].s_addr = INADDR_NONE; 1884 } else { 1885 addr = arg->bundle->ncp.ipcp.cfg.ns.nbns; 1886 addr[0].s_addr = addr[1].s_addr = INADDR_ANY; 1887 } 1888 1889 if (arg->argc > arg->argn) { 1890 ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn], 1891 addr, &dummyaddr, &dummyint); 1892 if (arg->argc > arg->argn+1) 1893 ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn + 1], 1894 addr + 1, &dummyaddr, &dummyint); 1895 1896 if (addr[0].s_addr == INADDR_ANY) { 1897 addr[0].s_addr = addr[1].s_addr; 1898 addr[1].s_addr = INADDR_ANY; 1899 } 1900 if (addr[0].s_addr == INADDR_NONE) { 1901 addr[0].s_addr = addr[1].s_addr; 1902 addr[1].s_addr = INADDR_NONE; 1903 } 1904 } 1905 break; 1906 1907 case VAR_CALLBACK: 1908 cx->cfg.callback.opmask = 0; 1909 for (dummyint = arg->argn; dummyint < arg->argc; dummyint++) { 1910 if (!strcasecmp(arg->argv[dummyint], "auth")) 1911 cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_AUTH); 1912 else if (!strcasecmp(arg->argv[dummyint], "cbcp")) 1913 cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_CBCP); 1914 else if (!strcasecmp(arg->argv[dummyint], "e.164")) { 1915 if (dummyint == arg->argc - 1) 1916 log_Printf(LogWARN, "No E.164 arg (E.164 ignored) !\n"); 1917 else { 1918 cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_E164); 1919 strncpy(cx->cfg.callback.msg, arg->argv[++dummyint], 1920 sizeof cx->cfg.callback.msg - 1); 1921 cx->cfg.callback.msg[sizeof cx->cfg.callback.msg - 1] = '\0'; 1922 } 1923 } else if (!strcasecmp(arg->argv[dummyint], "none")) 1924 cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_NONE); 1925 else 1926 return -1; 1927 } 1928 if (cx->cfg.callback.opmask == CALLBACK_BIT(CALLBACK_NONE)) 1929 cx->cfg.callback.opmask = 0; 1930 break; 1931 1932 case VAR_CBCP: 1933 cx->cfg.cbcp.delay = 0; 1934 *cx->cfg.cbcp.phone = '\0'; 1935 cx->cfg.cbcp.fsmretry = DEF_FSMRETRY; 1936 if (arg->argc > arg->argn) { 1937 strncpy(cx->cfg.cbcp.phone, arg->argv[arg->argn], 1938 sizeof cx->cfg.cbcp.phone - 1); 1939 cx->cfg.cbcp.phone[sizeof cx->cfg.cbcp.phone - 1] = '\0'; 1940 if (arg->argc > arg->argn + 1) { 1941 cx->cfg.cbcp.delay = atoi(arg->argv[arg->argn + 1]); 1942 if (arg->argc > arg->argn + 2) { 1943 long_val = atol(arg->argv[arg->argn + 2]); 1944 if (long_val < MIN_FSMRETRY) 1945 log_Printf(LogWARN, "%ld: Invalid CBCP FSM retry period - min %d\n", 1946 long_val, MIN_FSMRETRY); 1947 else 1948 cx->cfg.cbcp.fsmretry = long_val; 1949 } 1950 } 1951 } 1952 break; 1953 1954 case VAR_CHOKED: 1955 arg->bundle->cfg.choked.timeout = atoi(argp); 1956 if (arg->bundle->cfg.choked.timeout <= 0) 1957 arg->bundle->cfg.choked.timeout = CHOKED_TIMEOUT; 1958 break; 1959 1960 case VAR_SENDPIPE: 1961 long_val = atol(argp); 1962 arg->bundle->ncp.ipcp.cfg.sendpipe = long_val; 1963 break; 1964 1965 case VAR_RECVPIPE: 1966 long_val = atol(argp); 1967 arg->bundle->ncp.ipcp.cfg.recvpipe = long_val; 1968 break; 1969 1970 #ifndef NORADIUS 1971 case VAR_RADIUS: 1972 if (!*argp) 1973 *arg->bundle->radius.cfg.file = '\0'; 1974 else if (access(argp, R_OK)) { 1975 log_Printf(LogWARN, "%s: %s\n", argp, strerror(errno)); 1976 return 1; 1977 } else { 1978 strncpy(arg->bundle->radius.cfg.file, argp, 1979 sizeof arg->bundle->radius.cfg.file - 1); 1980 arg->bundle->radius.cfg.file 1981 [sizeof arg->bundle->radius.cfg.file - 1] = '\0'; 1982 } 1983 break; 1984 #endif 1985 1986 case VAR_CD: 1987 if (*argp) { 1988 if (strcasecmp(argp, "off")) { 1989 long_val = atol(argp); 1990 if (long_val < 0) 1991 long_val = 0; 1992 cx->physical->cfg.cd.delay = long_val; 1993 cx->physical->cfg.cd.necessity = argp[strlen(argp)-1] == '!' ? 1994 CD_REQUIRED : CD_VARIABLE; 1995 } else 1996 cx->physical->cfg.cd.necessity = CD_NOTREQUIRED; 1997 } else { 1998 cx->physical->cfg.cd.delay = 0; 1999 cx->physical->cfg.cd.necessity = CD_DEFAULT; 2000 } 2001 break; 2002 2003 case VAR_PARITY: 2004 if (arg->argc == arg->argn + 1) 2005 return physical_SetParity(arg->cx->physical, argp); 2006 else { 2007 err = "Parity value must be odd, even or none\n"; 2008 log_Printf(LogWARN, "%s", err); 2009 } 2010 break; 2011 2012 case VAR_CRTSCTS: 2013 if (strcasecmp(argp, "on") == 0) 2014 physical_SetRtsCts(arg->cx->physical, 1); 2015 else if (strcasecmp(argp, "off") == 0) 2016 physical_SetRtsCts(arg->cx->physical, 0); 2017 else { 2018 err = "RTS/CTS value must be on or off\n"; 2019 log_Printf(LogWARN, "%s", err); 2020 } 2021 break; 2022 2023 case VAR_URGENTPORTS: 2024 if (arg->argn == arg->argc) { 2025 ipcp_SetUrgentTOS(&arg->bundle->ncp.ipcp); 2026 ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp); 2027 ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp); 2028 } else if (!strcasecmp(arg->argv[arg->argn], "udp")) { 2029 ipcp_SetUrgentTOS(&arg->bundle->ncp.ipcp); 2030 if (arg->argn == arg->argc - 1) 2031 ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp); 2032 else for (f = arg->argn + 1; f < arg->argc; f++) 2033 if (*arg->argv[f] == '+') 2034 ipcp_AddUrgentUdpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f] + 1)); 2035 else if (*arg->argv[f] == '-') 2036 ipcp_RemoveUrgentUdpPort(&arg->bundle->ncp.ipcp, 2037 atoi(arg->argv[f] + 1)); 2038 else { 2039 if (f == arg->argn) 2040 ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp); 2041 ipcp_AddUrgentUdpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f])); 2042 } 2043 } else if (arg->argn == arg->argc - 1 && 2044 !strcasecmp(arg->argv[arg->argn], "none")) { 2045 ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp); 2046 ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp); 2047 ipcp_ClearUrgentTOS(&arg->bundle->ncp.ipcp); 2048 } else { 2049 ipcp_SetUrgentTOS(&arg->bundle->ncp.ipcp); 2050 first = arg->argn; 2051 if (!strcasecmp(arg->argv[first], "tcp") && ++first == arg->argc) 2052 ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp); 2053 2054 for (f = first; f < arg->argc; f++) 2055 if (*arg->argv[f] == '+') 2056 ipcp_AddUrgentTcpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f] + 1)); 2057 else if (*arg->argv[f] == '-') 2058 ipcp_RemoveUrgentTcpPort(&arg->bundle->ncp.ipcp, 2059 atoi(arg->argv[f] + 1)); 2060 else { 2061 if (f == first) 2062 ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp); 2063 ipcp_AddUrgentTcpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f])); 2064 } 2065 } 2066 break; 2067 } 2068 2069 return err ? 1 : 0; 2070 } 2071 2072 static struct cmdtab const SetCommands[] = { 2073 {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 2074 "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP}, 2075 {"authkey", "key", SetVariable, LOCAL_AUTH, 2076 "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY}, 2077 {"authname", NULL, SetVariable, LOCAL_AUTH, 2078 "authentication name", "set authname name", (const void *)VAR_AUTHNAME}, 2079 {"autoload", NULL, SetVariable, LOCAL_AUTH, 2080 "auto link [de]activation", "set autoload maxtime maxload mintime minload", 2081 (const void *)VAR_AUTOLOAD}, 2082 {"bandwidth", NULL, mp_SetDatalinkBandwidth, LOCAL_AUTH | LOCAL_CX, 2083 "datalink bandwidth", "set bandwidth value"}, 2084 {"callback", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 2085 "callback control", "set callback [none|auth|cbcp|" 2086 "E.164 *|number[,number]...]...", (const void *)VAR_CALLBACK}, 2087 {"cbcp", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 2088 "CBCP control", "set cbcp [*|phone[,phone...] [delay [timeout]]]", 2089 (const void *)VAR_CBCP}, 2090 {"ccpretry", "ccpretries", SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, 2091 "CCP retries", "set ccpretry value [attempts]", (const void *)VAR_CCPRETRY}, 2092 {"cd", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "Carrier delay requirement", 2093 "set cd value[!]", (const void *)VAR_CD}, 2094 {"chapretry", "chapretries", SetVariable, LOCAL_AUTH | LOCAL_CX, 2095 "CHAP retries", "set chapretry value [attempts]", 2096 (const void *)VAR_CHAPRETRY}, 2097 {"choked", NULL, SetVariable, LOCAL_AUTH, 2098 "choked timeout", "set choked [secs]", (const void *)VAR_CHOKED}, 2099 {"ctsrts", "crtscts", SetVariable, LOCAL_AUTH | LOCAL_CX, 2100 "Use hardware flow control", "set ctsrts [on|off]", 2101 (const char *)VAR_CRTSCTS}, 2102 {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, 2103 "deflate window sizes", "set deflate out-winsize in-winsize", 2104 (const void *) VAR_WINSIZE}, 2105 #ifdef HAVE_DES 2106 {"mppe", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, 2107 "MPPE key size and state", "set mppe [40|56|128|* [statefull|stateless|*]]", 2108 (const void *) VAR_MPPE}, 2109 #endif 2110 {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX, 2111 "physical device name", "set device|line device-name[,device-name]", 2112 (const void *) VAR_DEVICE}, 2113 {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 2114 "dialing script", "set dial chat-script", (const void *) VAR_DIAL}, 2115 {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server", 2116 "set dns pri-addr [sec-addr]", (const void *)VAR_DNS}, 2117 {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH, 2118 "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]"}, 2119 {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX, 2120 "escape characters", "set escape hex-digit ..."}, 2121 {"filter", NULL, filter_Set, LOCAL_AUTH, 2122 "packet filters", "set filter alive|dial|in|out rule-no permit|deny " 2123 "[src_addr[/width]] [dst_addr[/width]] [tcp|udp|icmp|ospf|igmp " 2124 "[src [lt|eq|gt port]] [dst [lt|eq|gt port]] [estab] [syn] [finrst]]"}, 2125 {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 2126 "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP}, 2127 {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address", 2128 "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"}, 2129 {"ifqueue", NULL, SetVariable, LOCAL_AUTH, "interface queue", 2130 "set ifqueue packets", (const void *)VAR_IFQUEUE}, 2131 {"ipcpretry", "ipcpretries", SetVariable, LOCAL_AUTH, "IPCP retries", 2132 "set ipcpretry value [attempts]", (const void *)VAR_IPCPRETRY}, 2133 {"lcpretry", "lcpretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "LCP retries", 2134 "set lcpretry value [attempts]", (const void *)VAR_LCPRETRY}, 2135 {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level", 2136 "set log [local] [+|-]all|async|cbcp|ccp|chat|command|connect|debug|dns|hdlc|" 2137 "id0|ipcp|lcp|lqm|phase|physical|sync|tcp/ip|timer|tun..."}, 2138 {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 2139 "login script", "set login chat-script", (const void *) VAR_LOGIN}, 2140 {"logout", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 2141 "logout script", "set logout chat-script", (const void *) VAR_LOGOUT}, 2142 {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, 2143 "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD}, 2144 {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value", 2145 "set mode interactive|auto|ddial|background", (const void *)VAR_MODE}, 2146 {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value", 2147 "set mrru value", (const void *)VAR_MRRU}, 2148 {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, 2149 "MRU value", "set mru [max[imum]] [value]", (const void *)VAR_MRU}, 2150 {"mtu", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 2151 "interface MTU value", "set mtu [max[imum]] [value]", (const void *)VAR_MTU}, 2152 {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server", 2153 "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS}, 2154 {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode", 2155 "set openmode active|passive [secs]", (const void *)VAR_OPENMODE}, 2156 {"papretry", "papretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "PAP retries", 2157 "set papretry value [attempts]", (const void *)VAR_PAPRETRY}, 2158 {"parity", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "serial parity", 2159 "set parity [odd|even|none]", (const void *)VAR_PARITY}, 2160 {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)", 2161 "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE}, 2162 {"proctitle", "title", SetProcTitle, LOCAL_AUTH, 2163 "Process title", "set proctitle [value]"}, 2164 #ifndef NORADIUS 2165 {"radius", NULL, SetVariable, LOCAL_AUTH, 2166 "RADIUS Config", "set radius cfgfile", (const void *)VAR_RADIUS}, 2167 #endif 2168 {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX, 2169 "Reconnect timeout", "set reconnect value ntries"}, 2170 {"recvpipe", NULL, SetVariable, LOCAL_AUTH, 2171 "RECVPIPE value", "set recvpipe value", (const void *)VAR_RECVPIPE}, 2172 {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX, 2173 "Redial timeout", "set redial secs[+inc[-incmax]][.next] [attempts]"}, 2174 {"sendpipe", NULL, SetVariable, LOCAL_AUTH, 2175 "SENDPIPE value", "set sendpipe value", (const void *)VAR_SENDPIPE}, 2176 {"server", "socket", SetServer, LOCAL_AUTH, "diagnostic port", 2177 "set server|socket TcpPort|LocalName|none|open|closed [password [mask]]"}, 2178 {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX, 2179 "physical speed", "set speed value|sync"}, 2180 {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX, 2181 "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"}, 2182 {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout", 2183 "set timeout idletime", (const void *)VAR_IDLETIMEOUT}, 2184 {"urgent", NULL, SetVariable, LOCAL_AUTH, "urgent ports", 2185 "set urgent [tcp|udp] [+|-]port...", (const void *)VAR_URGENTPORTS}, 2186 {"vj", NULL, ipcp_vjset, LOCAL_AUTH, 2187 "vj values", "set vj slots|slotcomp [value]"}, 2188 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 2189 "Display this message", "set help|? [command]", SetCommands}, 2190 {NULL, NULL, NULL}, 2191 }; 2192 2193 static int 2194 SetCommand(struct cmdargs const *arg) 2195 { 2196 if (arg->argc > arg->argn) 2197 FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv, 2198 arg->prompt, arg->cx); 2199 else if (arg->prompt) 2200 prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for" 2201 " syntax help.\n"); 2202 else 2203 log_Printf(LogWARN, "set command must have arguments\n"); 2204 2205 return 0; 2206 } 2207 2208 static int 2209 AddCommand(struct cmdargs const *arg) 2210 { 2211 struct in_addr dest, gateway, netmask; 2212 int gw, addrs; 2213 2214 if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2) 2215 return -1; 2216 2217 addrs = 0; 2218 if (arg->argc == arg->argn+2) { 2219 if (!strcasecmp(arg->argv[arg->argn], "default")) 2220 dest.s_addr = netmask.s_addr = INADDR_ANY; 2221 else { 2222 int width; 2223 2224 if (!ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn], 2225 &dest, &netmask, &width)) 2226 return -1; 2227 if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6)) 2228 addrs = ROUTE_DSTMYADDR; 2229 else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7)) 2230 addrs = ROUTE_DSTHISADDR; 2231 else if (!strncasecmp(arg->argv[arg->argn], "DNS0", 4)) 2232 addrs = ROUTE_DSTDNS0; 2233 else if (!strncasecmp(arg->argv[arg->argn], "DNS1", 4)) 2234 addrs = ROUTE_DSTDNS1; 2235 } 2236 gw = 1; 2237 } else { 2238 if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) { 2239 addrs = ROUTE_DSTMYADDR; 2240 dest = arg->bundle->ncp.ipcp.my_ip; 2241 } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) { 2242 addrs = ROUTE_DSTHISADDR; 2243 dest = arg->bundle->ncp.ipcp.peer_ip; 2244 } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) { 2245 addrs = ROUTE_DSTDNS0; 2246 dest = arg->bundle->ncp.ipcp.ns.dns[0]; 2247 } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) { 2248 addrs = ROUTE_DSTDNS1; 2249 dest = arg->bundle->ncp.ipcp.ns.dns[1]; 2250 } else { 2251 dest = GetIpAddr(arg->argv[arg->argn]); 2252 if (dest.s_addr == INADDR_NONE) { 2253 log_Printf(LogWARN, "%s: Invalid destination address\n", 2254 arg->argv[arg->argn]); 2255 return -1; 2256 } 2257 } 2258 netmask = GetIpAddr(arg->argv[arg->argn+1]); 2259 gw = 2; 2260 } 2261 2262 if (strcasecmp(arg->argv[arg->argn+gw], "HISADDR") == 0) { 2263 gateway = arg->bundle->ncp.ipcp.peer_ip; 2264 addrs |= ROUTE_GWHISADDR; 2265 } else { 2266 gateway = GetIpAddr(arg->argv[arg->argn+gw]); 2267 if (gateway.s_addr == INADDR_NONE) { 2268 log_Printf(LogWARN, "%s: Invalid gateway address\n", 2269 arg->argv[arg->argn + gw]); 2270 return -1; 2271 } 2272 } 2273 2274 if (rt_Set(arg->bundle, RTM_ADD, dest, gateway, netmask, 2275 arg->cmd->args ? 1 : 0, (addrs & ROUTE_GWHISADDR) ? 1 : 0) 2276 && addrs != ROUTE_STATIC) 2277 route_Add(&arg->bundle->ncp.ipcp.route, addrs, dest, netmask, gateway); 2278 2279 return 0; 2280 } 2281 2282 static int 2283 DeleteCommand(struct cmdargs const *arg) 2284 { 2285 struct in_addr dest, none; 2286 int addrs; 2287 2288 if (arg->argc == arg->argn+1) { 2289 if(strcasecmp(arg->argv[arg->argn], "all") == 0) { 2290 route_IfDelete(arg->bundle, 0); 2291 route_DeleteAll(&arg->bundle->ncp.ipcp.route); 2292 } else { 2293 addrs = 0; 2294 if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) { 2295 dest = arg->bundle->ncp.ipcp.my_ip; 2296 addrs = ROUTE_DSTMYADDR; 2297 } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) { 2298 dest = arg->bundle->ncp.ipcp.peer_ip; 2299 addrs = ROUTE_DSTHISADDR; 2300 } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) { 2301 dest = arg->bundle->ncp.ipcp.ns.dns[0]; 2302 addrs = ROUTE_DSTDNS0; 2303 } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) { 2304 dest = arg->bundle->ncp.ipcp.ns.dns[1]; 2305 addrs = ROUTE_DSTDNS1; 2306 } else { 2307 dest = GetIpAddr(arg->argv[arg->argn]); 2308 if (dest.s_addr == INADDR_NONE) { 2309 log_Printf(LogWARN, "%s: Invalid IP address\n", arg->argv[arg->argn]); 2310 return -1; 2311 } 2312 addrs = ROUTE_STATIC; 2313 } 2314 none.s_addr = INADDR_ANY; 2315 rt_Set(arg->bundle, RTM_DELETE, dest, none, none, 2316 arg->cmd->args ? 1 : 0, 0); 2317 route_Delete(&arg->bundle->ncp.ipcp.route, addrs, dest); 2318 } 2319 } else 2320 return -1; 2321 2322 return 0; 2323 } 2324 2325 #ifndef NONAT 2326 static int 2327 NatEnable(struct cmdargs const *arg) 2328 { 2329 if (arg->argc == arg->argn+1) { 2330 if (strcasecmp(arg->argv[arg->argn], "yes") == 0) { 2331 if (!arg->bundle->NatEnabled) { 2332 if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED) 2333 PacketAliasSetAddress(arg->bundle->ncp.ipcp.my_ip); 2334 arg->bundle->NatEnabled = 1; 2335 } 2336 return 0; 2337 } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) { 2338 arg->bundle->NatEnabled = 0; 2339 arg->bundle->cfg.opt &= ~OPT_IFACEALIAS; 2340 /* Don't iface_Clear() - there may be manually configured addresses */ 2341 return 0; 2342 } 2343 } 2344 2345 return -1; 2346 } 2347 2348 2349 static int 2350 NatOption(struct cmdargs const *arg) 2351 { 2352 long param = (long)arg->cmd->args; 2353 2354 if (arg->argc == arg->argn+1) { 2355 if (strcasecmp(arg->argv[arg->argn], "yes") == 0) { 2356 if (arg->bundle->NatEnabled) { 2357 PacketAliasSetMode(param, param); 2358 return 0; 2359 } 2360 log_Printf(LogWARN, "nat not enabled\n"); 2361 } else if (strcmp(arg->argv[arg->argn], "no") == 0) { 2362 if (arg->bundle->NatEnabled) { 2363 PacketAliasSetMode(0, param); 2364 return 0; 2365 } 2366 log_Printf(LogWARN, "nat not enabled\n"); 2367 } 2368 } 2369 return -1; 2370 } 2371 #endif /* #ifndef NONAT */ 2372 2373 static int 2374 LinkCommand(struct cmdargs const *arg) 2375 { 2376 if (arg->argc > arg->argn+1) { 2377 char namelist[LINE_LEN]; 2378 struct datalink *cx; 2379 char *name; 2380 int result = 0; 2381 2382 if (!strcmp(arg->argv[arg->argn], "*")) { 2383 struct datalink *dl; 2384 2385 cx = arg->bundle->links; 2386 while (cx) { 2387 /* Watch it, the command could be a ``remove'' */ 2388 dl = cx->next; 2389 FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv, 2390 arg->prompt, cx); 2391 for (cx = arg->bundle->links; cx; cx = cx->next) 2392 if (cx == dl) 2393 break; /* Pointer's still valid ! */ 2394 } 2395 } else { 2396 strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1); 2397 namelist[sizeof namelist - 1] = '\0'; 2398 for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) 2399 if (!bundle2datalink(arg->bundle, name)) { 2400 log_Printf(LogWARN, "link: %s: Invalid link name\n", name); 2401 return 1; 2402 } 2403 2404 strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1); 2405 namelist[sizeof namelist - 1] = '\0'; 2406 for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) { 2407 cx = bundle2datalink(arg->bundle, name); 2408 if (cx) 2409 FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv, 2410 arg->prompt, cx); 2411 else { 2412 log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name); 2413 result++; 2414 } 2415 } 2416 } 2417 return result; 2418 } 2419 2420 log_Printf(LogWARN, "Usage: %s\n", arg->cmd->syntax); 2421 return 2; 2422 } 2423 2424 struct link * 2425 command_ChooseLink(struct cmdargs const *arg) 2426 { 2427 if (arg->cx) 2428 return &arg->cx->physical->link; 2429 else if (!arg->bundle->ncp.mp.cfg.mrru) { 2430 struct datalink *dl = bundle2datalink(arg->bundle, NULL); 2431 if (dl) 2432 return &dl->physical->link; 2433 } 2434 return &arg->bundle->ncp.mp.link; 2435 } 2436 2437 static const char * 2438 ident_cmd(const char *cmd, unsigned *keep, unsigned *add) 2439 { 2440 const char *result; 2441 2442 switch (*cmd) { 2443 case 'A': 2444 case 'a': 2445 result = "accept"; 2446 *keep = NEG_MYMASK; 2447 *add = NEG_ACCEPTED; 2448 break; 2449 case 'D': 2450 case 'd': 2451 switch (cmd[1]) { 2452 case 'E': 2453 case 'e': 2454 result = "deny"; 2455 *keep = NEG_MYMASK; 2456 *add = 0; 2457 break; 2458 case 'I': 2459 case 'i': 2460 result = "disable"; 2461 *keep = NEG_HISMASK; 2462 *add = 0; 2463 break; 2464 default: 2465 return NULL; 2466 } 2467 break; 2468 case 'E': 2469 case 'e': 2470 result = "enable"; 2471 *keep = NEG_HISMASK; 2472 *add = NEG_ENABLED; 2473 break; 2474 default: 2475 return NULL; 2476 } 2477 2478 return result; 2479 } 2480 2481 static int 2482 OptSet(struct cmdargs const *arg) 2483 { 2484 int bit = (int)(long)arg->cmd->args; 2485 const char *cmd; 2486 unsigned keep; /* Keep these bits */ 2487 unsigned add; /* Add these bits */ 2488 2489 if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL) 2490 return 1; 2491 2492 if (add) 2493 arg->bundle->cfg.opt |= bit; 2494 else 2495 arg->bundle->cfg.opt &= ~bit; 2496 return 0; 2497 } 2498 2499 static int 2500 IfaceAliasOptSet(struct cmdargs const *arg) 2501 { 2502 unsigned save = arg->bundle->cfg.opt; 2503 int result = OptSet(arg); 2504 2505 if (result == 0) 2506 if (Enabled(arg->bundle, OPT_IFACEALIAS) && !arg->bundle->NatEnabled) { 2507 arg->bundle->cfg.opt = save; 2508 log_Printf(LogWARN, "Cannot enable iface-alias without NAT\n"); 2509 result = 2; 2510 } 2511 2512 return result; 2513 } 2514 2515 static int 2516 NegotiateSet(struct cmdargs const *arg) 2517 { 2518 long param = (long)arg->cmd->args; 2519 struct link *l = command_ChooseLink(arg); /* LOCAL_CX_OPT uses this */ 2520 struct datalink *cx = arg->cx; /* LOCAL_CX uses this */ 2521 const char *cmd; 2522 unsigned keep; /* Keep these bits */ 2523 unsigned add; /* Add these bits */ 2524 2525 if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL) 2526 return 1; 2527 2528 if ((arg->cmd->lauth & LOCAL_CX) && !cx) { 2529 log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n", 2530 cmd, arg->cmd->name); 2531 return 2; 2532 } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) { 2533 log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n", 2534 cmd, arg->cmd->name, cx->name); 2535 cx = NULL; 2536 } 2537 2538 switch (param) { 2539 case NEG_ACFCOMP: 2540 cx->physical->link.lcp.cfg.acfcomp &= keep; 2541 cx->physical->link.lcp.cfg.acfcomp |= add; 2542 break; 2543 case NEG_CHAP05: 2544 cx->physical->link.lcp.cfg.chap05 &= keep; 2545 cx->physical->link.lcp.cfg.chap05 |= add; 2546 break; 2547 #ifdef HAVE_DES 2548 case NEG_CHAP80: 2549 cx->physical->link.lcp.cfg.chap80nt &= keep; 2550 cx->physical->link.lcp.cfg.chap80nt |= add; 2551 break; 2552 case NEG_CHAP80LM: 2553 cx->physical->link.lcp.cfg.chap80lm &= keep; 2554 cx->physical->link.lcp.cfg.chap80lm |= add; 2555 break; 2556 case NEG_CHAP81: 2557 cx->physical->link.lcp.cfg.chap81 &= keep; 2558 cx->physical->link.lcp.cfg.chap81 |= add; 2559 break; 2560 case NEG_MPPE: 2561 l->ccp.cfg.neg[CCP_NEG_MPPE] &= keep; 2562 l->ccp.cfg.neg[CCP_NEG_MPPE] |= add; 2563 break; 2564 #endif 2565 case NEG_DEFLATE: 2566 l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep; 2567 l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add; 2568 break; 2569 case NEG_DNS: 2570 arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep; 2571 arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add; 2572 break; 2573 case NEG_ENDDISC: 2574 arg->bundle->ncp.mp.cfg.negenddisc &= keep; 2575 arg->bundle->ncp.mp.cfg.negenddisc |= add; 2576 break; 2577 case NEG_LQR: 2578 cx->physical->link.lcp.cfg.lqr &= keep; 2579 cx->physical->link.lcp.cfg.lqr |= add; 2580 break; 2581 case NEG_PAP: 2582 cx->physical->link.lcp.cfg.pap &= keep; 2583 cx->physical->link.lcp.cfg.pap |= add; 2584 break; 2585 case NEG_PPPDDEFLATE: 2586 l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep; 2587 l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add; 2588 break; 2589 case NEG_PRED1: 2590 l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep; 2591 l->ccp.cfg.neg[CCP_NEG_PRED1] |= add; 2592 break; 2593 case NEG_PROTOCOMP: 2594 cx->physical->link.lcp.cfg.protocomp &= keep; 2595 cx->physical->link.lcp.cfg.protocomp |= add; 2596 break; 2597 case NEG_SHORTSEQ: 2598 switch (bundle_Phase(arg->bundle)) { 2599 case PHASE_DEAD: 2600 break; 2601 case PHASE_ESTABLISH: 2602 /* Make sure none of our links are DATALINK_LCP or greater */ 2603 if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) { 2604 log_Printf(LogWARN, "shortseq: Only changable before" 2605 " LCP negotiations\n"); 2606 return 1; 2607 } 2608 break; 2609 default: 2610 log_Printf(LogWARN, "shortseq: Only changable at phase" 2611 " DEAD/ESTABLISH\n"); 2612 return 1; 2613 } 2614 arg->bundle->ncp.mp.cfg.shortseq &= keep; 2615 arg->bundle->ncp.mp.cfg.shortseq |= add; 2616 break; 2617 case NEG_VJCOMP: 2618 arg->bundle->ncp.ipcp.cfg.vj.neg &= keep; 2619 arg->bundle->ncp.ipcp.cfg.vj.neg |= add; 2620 break; 2621 } 2622 2623 return 0; 2624 } 2625 2626 static struct cmdtab const NegotiateCommands[] = { 2627 {"filter-decapsulation", NULL, OptSet, LOCAL_AUTH, 2628 "filter on PPPoUDP payloads", "disable|enable", 2629 (const void *)OPT_FILTERDECAP}, 2630 {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids", 2631 "disable|enable", (const void *)OPT_IDCHECK}, 2632 {"iface-alias", NULL, IfaceAliasOptSet, LOCAL_AUTH, 2633 "retain interface addresses", "disable|enable", 2634 (const void *)OPT_IFACEALIAS}, 2635 {"keep-session", NULL, OptSet, LOCAL_AUTH, "Retain device session leader", 2636 "disable|enable", (const void *)OPT_KEEPSESSION}, 2637 {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface", 2638 "disable|enable", (const void *)OPT_LOOPBACK}, 2639 {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file", 2640 "disable|enable", (const void *)OPT_PASSWDAUTH}, 2641 {"proxy", NULL, OptSet, LOCAL_AUTH, "Create a proxy ARP entry", 2642 "disable|enable", (const void *)OPT_PROXY}, 2643 {"proxyall", NULL, OptSet, LOCAL_AUTH, "Proxy ARP for all remote hosts", 2644 "disable|enable", (const void *)OPT_PROXYALL}, 2645 {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes", 2646 "disable|enable", (const void *)OPT_SROUTES}, 2647 {"tcpmssfixup", "mssfixup", OptSet, LOCAL_AUTH, "Modify MSS options", 2648 "disable|enable", (const void *)OPT_TCPMSSFIXUP}, 2649 {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput", 2650 "disable|enable", (const void *)OPT_THROUGHPUT}, 2651 {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp", 2652 "disable|enable", (const void *)OPT_UTMP}, 2653 2654 #define OPT_MAX 11 /* accept/deny allowed below and not above */ 2655 2656 {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2657 "Address & Control field compression", "accept|deny|disable|enable", 2658 (const void *)NEG_ACFCOMP}, 2659 {"chap", "chap05", NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2660 "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable", 2661 (const void *)NEG_CHAP05}, 2662 #ifdef HAVE_DES 2663 {"mschap", "chap80nt", NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2664 "Microsoft (NT) CHAP", "accept|deny|disable|enable", 2665 (const void *)NEG_CHAP80}, 2666 {"LANMan", "chap80lm", NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2667 "Microsoft (NT) CHAP", "accept|deny|disable|enable", 2668 (const void *)NEG_CHAP80LM}, 2669 {"mschapv2", "chap81", NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2670 "Microsoft CHAP v2", "accept|deny|disable|enable", 2671 (const void *)NEG_CHAP81}, 2672 {"mppe", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT, 2673 "MPPE encryption", "accept|deny|disable|enable", 2674 (const void *)NEG_MPPE}, 2675 #endif 2676 {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT, 2677 "Deflate compression", "accept|deny|disable|enable", 2678 (const void *)NEG_DEFLATE}, 2679 {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT, 2680 "Deflate (type 24) compression", "accept|deny|disable|enable", 2681 (const void *)NEG_PPPDDEFLATE}, 2682 {"dns", NULL, NegotiateSet, LOCAL_AUTH, 2683 "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS}, 2684 {"enddisc", NULL, NegotiateSet, LOCAL_AUTH, "ENDDISC negotiation", 2685 "accept|deny|disable|enable", (const void *)NEG_ENDDISC}, 2686 {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2687 "Link Quality Reports", "accept|deny|disable|enable", 2688 (const void *)NEG_LQR}, 2689 {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2690 "Password Authentication protocol", "accept|deny|disable|enable", 2691 (const void *)NEG_PAP}, 2692 {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT, 2693 "Predictor 1 compression", "accept|deny|disable|enable", 2694 (const void *)NEG_PRED1}, 2695 {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2696 "Protocol field compression", "accept|deny|disable|enable", 2697 (const void *)NEG_PROTOCOMP}, 2698 {"shortseq", NULL, NegotiateSet, LOCAL_AUTH, 2699 "MP Short Sequence Numbers", "accept|deny|disable|enable", 2700 (const void *)NEG_SHORTSEQ}, 2701 {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH, 2702 "Van Jacobson header compression", "accept|deny|disable|enable", 2703 (const void *)NEG_VJCOMP}, 2704 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 2705 "Display this message", "accept|deny|disable|enable help|? [value]", 2706 NegotiateCommands}, 2707 {NULL, NULL, NULL}, 2708 }; 2709 2710 static int 2711 NegotiateCommand(struct cmdargs const *arg) 2712 { 2713 if (arg->argc > arg->argn) { 2714 char const *argv[3]; 2715 unsigned keep, add; 2716 int n; 2717 2718 if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL) 2719 return -1; 2720 argv[2] = NULL; 2721 2722 for (n = arg->argn; n < arg->argc; n++) { 2723 argv[1] = arg->argv[n]; 2724 FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ? 2725 0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx); 2726 } 2727 } else if (arg->prompt) 2728 prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n", 2729 arg->argv[arg->argn-1]); 2730 else 2731 log_Printf(LogWARN, "%s command must have arguments\n", 2732 arg->argv[arg->argn] ); 2733 2734 return 0; 2735 } 2736 2737 const char * 2738 command_ShowNegval(unsigned val) 2739 { 2740 switch (val&3) { 2741 case 1: return "disabled & accepted"; 2742 case 2: return "enabled & denied"; 2743 case 3: return "enabled & accepted"; 2744 } 2745 return "disabled & denied"; 2746 } 2747 2748 static int 2749 ClearCommand(struct cmdargs const *arg) 2750 { 2751 struct pppThroughput *t; 2752 struct datalink *cx; 2753 int i, clear_type; 2754 2755 if (arg->argc < arg->argn + 1) 2756 return -1; 2757 2758 if (strcasecmp(arg->argv[arg->argn], "physical") == 0) { 2759 cx = arg->cx; 2760 if (!cx) 2761 cx = bundle2datalink(arg->bundle, NULL); 2762 if (!cx) { 2763 log_Printf(LogWARN, "A link must be specified for ``clear physical''\n"); 2764 return 1; 2765 } 2766 t = &cx->physical->link.stats.total; 2767 } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0) 2768 t = &arg->bundle->ncp.ipcp.throughput; 2769 else 2770 return -1; 2771 2772 if (arg->argc > arg->argn + 1) { 2773 clear_type = 0; 2774 for (i = arg->argn + 1; i < arg->argc; i++) 2775 if (strcasecmp(arg->argv[i], "overall") == 0) 2776 clear_type |= THROUGHPUT_OVERALL; 2777 else if (strcasecmp(arg->argv[i], "current") == 0) 2778 clear_type |= THROUGHPUT_CURRENT; 2779 else if (strcasecmp(arg->argv[i], "peak") == 0) 2780 clear_type |= THROUGHPUT_PEAK; 2781 else 2782 return -1; 2783 } else 2784 clear_type = THROUGHPUT_ALL; 2785 2786 throughput_clear(t, clear_type, arg->prompt); 2787 return 0; 2788 } 2789 2790 static int 2791 RunListCommand(struct cmdargs const *arg) 2792 { 2793 const char *cmd = arg->argc ? arg->argv[arg->argc - 1] : "???"; 2794 2795 #ifndef NONAT 2796 if (arg->cmd->args == NatCommands && 2797 tolower(*arg->argv[arg->argn - 1]) == 'a') { 2798 if (arg->prompt) 2799 prompt_Printf(arg->prompt, "The alias command is deprecated\n"); 2800 else 2801 log_Printf(LogWARN, "The alias command is deprecated\n"); 2802 } 2803 #endif 2804 2805 if (arg->argc > arg->argn) 2806 FindExec(arg->bundle, arg->cmd->args, arg->argc, arg->argn, arg->argv, 2807 arg->prompt, arg->cx); 2808 else if (arg->prompt) 2809 prompt_Printf(arg->prompt, "Use `%s help' to get a list or `%s help" 2810 " <option>' for syntax help.\n", cmd, cmd); 2811 else 2812 log_Printf(LogWARN, "%s command must have arguments\n", cmd); 2813 2814 return 0; 2815 } 2816 2817 static int 2818 IfaceAddCommand(struct cmdargs const *arg) 2819 { 2820 int bits, n, how; 2821 struct in_addr ifa, mask, brd; 2822 2823 if (arg->argc == arg->argn + 1) { 2824 if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL)) 2825 return -1; 2826 mask.s_addr = brd.s_addr = INADDR_BROADCAST; 2827 } else { 2828 if (arg->argc == arg->argn + 2) { 2829 if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, &mask, &bits)) 2830 return -1; 2831 n = 1; 2832 } else if (arg->argc == arg->argn + 3) { 2833 if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL)) 2834 return -1; 2835 if (!ParseAddr(NULL, arg->argv[arg->argn + 1], &mask, NULL, NULL)) 2836 return -1; 2837 n = 2; 2838 } else 2839 return -1; 2840 2841 if (!ParseAddr(NULL, arg->argv[arg->argn + n], &brd, NULL, NULL)) 2842 return -1; 2843 } 2844 2845 how = IFACE_ADD_LAST; 2846 if (arg->cmd->args) 2847 how |= IFACE_FORCE_ADD; 2848 2849 return !iface_inAdd(arg->bundle->iface, ifa, mask, brd, how); 2850 } 2851 2852 static int 2853 IfaceDeleteCommand(struct cmdargs const *arg) 2854 { 2855 struct in_addr ifa; 2856 int ok; 2857 2858 if (arg->argc != arg->argn + 1) 2859 return -1; 2860 2861 if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL)) 2862 return -1; 2863 2864 if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED && 2865 arg->bundle->ncp.ipcp.my_ip.s_addr == ifa.s_addr) { 2866 log_Printf(LogWARN, "%s: Cannot remove active interface address\n", 2867 inet_ntoa(ifa)); 2868 return 1; 2869 } 2870 2871 ok = iface_inDelete(arg->bundle->iface, ifa); 2872 if (!ok) { 2873 if (arg->cmd->args) 2874 ok = 1; 2875 else if (arg->prompt) 2876 prompt_Printf(arg->prompt, "%s: No such address\n", inet_ntoa(ifa)); 2877 else 2878 log_Printf(LogWARN, "%s: No such address\n", inet_ntoa(ifa)); 2879 } 2880 2881 return !ok; 2882 } 2883 2884 static int 2885 IfaceClearCommand(struct cmdargs const *arg) 2886 { 2887 int how; 2888 2889 if (arg->argc != arg->argn) 2890 return -1; 2891 2892 how = arg->bundle->ncp.ipcp.fsm.state == ST_OPENED || 2893 arg->bundle->phys_type.all & PHYS_AUTO ? 2894 IFACE_CLEAR_ALIASES : IFACE_CLEAR_ALL; 2895 iface_Clear(arg->bundle->iface, how); 2896 2897 return 0; 2898 } 2899 2900 static int 2901 SetProcTitle(struct cmdargs const *arg) 2902 { 2903 static char title[LINE_LEN]; 2904 char *argv[MAXARGS], *ptr; 2905 int len, remaining, f, argc = arg->argc - arg->argn; 2906 2907 if (arg->argc == arg->argn) { 2908 SetTitle(NULL); 2909 return 0; 2910 } 2911 2912 if (argc >= sizeof argv / sizeof argv[0]) { 2913 argc = sizeof argv / sizeof argv[0] - 1; 2914 log_Printf(LogWARN, "Truncating proc title to %d args\n", argc); 2915 } 2916 command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 1, getpid()); 2917 2918 ptr = title; 2919 remaining = sizeof title - 1; 2920 for (f = 0; f < argc && remaining; f++) { 2921 if (f) { 2922 *ptr++ = ' '; 2923 remaining--; 2924 } 2925 len = strlen(argv[f]); 2926 if (len > remaining) 2927 len = remaining; 2928 memcpy(ptr, argv[f], len); 2929 remaining -= len; 2930 ptr += len; 2931 } 2932 *ptr = '\0'; 2933 2934 SetTitle(title); 2935 2936 return 0; 2937 } 2938