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