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