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