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