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