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