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