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