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