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