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