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