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