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