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