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