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