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