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