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