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