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