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