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