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