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