command.c revision 65550
1243789Sdim/* 2243789Sdim * PPP User command processing module 3243789Sdim * 4243789Sdim * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5243789Sdim * 6243789Sdim * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7243789Sdim * 8243789Sdim * Redistribution and use in source and binary forms are permitted 9243789Sdim * provided that the above copyright notice and this paragraph are 10243789Sdim * duplicated in all such forms and that any documentation, 11252723Sdim * advertising materials, and other materials related to such 12252723Sdim * distribution and use acknowledge that the software was developed 13252723Sdim * by the Internet Initiative Japan, Inc. The name of the 14252723Sdim * IIJ may not be used to endorse or promote products derived 15252723Sdim * from this software without specific prior written permission. 16252723Sdim * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17243789Sdim * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18243789Sdim * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19243789Sdim * 20243789Sdim * $FreeBSD: head/usr.sbin/ppp/command.c 65550 2000-09-06 21:02:06Z brian $ 21243789Sdim * 22263509Sdim */ 23243789Sdim#include <sys/param.h> 24252723Sdim#include <netinet/in_systm.h> 25252723Sdim#include <netinet/in.h> 26252723Sdim#include <netinet/ip.h> 27252723Sdim#include <arpa/inet.h> 28252723Sdim#include <sys/socket.h> 29243789Sdim#include <net/route.h> 30263509Sdim#include <netdb.h> 31243789Sdim#include <sys/un.h> 32243789Sdim 33243789Sdim#include <ctype.h> 34243789Sdim#include <errno.h> 35263509Sdim#include <fcntl.h> 36263509Sdim#include <paths.h> 37263509Sdim#include <stdio.h> 38263509Sdim#include <stdlib.h> 39243789Sdim#include <string.h> 40243789Sdim#include <sys/wait.h> 41243789Sdim#include <termios.h> 42243789Sdim#include <unistd.h> 43243789Sdim 44252723Sdim#ifndef NONAT 45243789Sdim#ifdef LOCALNAT 46243789Sdim#include "alias.h" 47243789Sdim#else 48243789Sdim#include <alias.h> 49243789Sdim#endif 50243789Sdim#endif 51243789Sdim 52243789Sdim#include "layer.h" 53252723Sdim#include "defs.h" 54243789Sdim#include "command.h" 55243789Sdim#include "mbuf.h" 56243789Sdim#include "log.h" 57243789Sdim#include "timer.h" 58243789Sdim#include "fsm.h" 59243789Sdim#include "iplist.h" 60243789Sdim#include "throughput.h" 61243789Sdim#include "slcompress.h" 62252723Sdim#include "lqr.h" 63252723Sdim#include "hdlc.h" 64243789Sdim#include "lcp.h" 65243789Sdim#include "ipcp.h" 66243789Sdim#ifndef NONAT 67243789Sdim#include "nat_cmd.h" 68243789Sdim#endif 69243789Sdim#include "systems.h" 70243789Sdim#include "filter.h" 71243789Sdim#include "descriptor.h" 72243789Sdim#include "main.h" 73243789Sdim#include "route.h" 74243789Sdim#include "ccp.h" 75243789Sdim#include "auth.h" 76243789Sdim#include "async.h" 77243789Sdim#include "link.h" 78243789Sdim#include "physical.h" 79243789Sdim#include "mp.h" 80243789Sdim#ifndef NORADIUS 81243789Sdim#include "radius.h" 82243789Sdim#endif 83243789Sdim#include "bundle.h" 84243789Sdim#include "server.h" 85243789Sdim#include "prompt.h" 86243789Sdim#include "chat.h" 87243789Sdim#include "chap.h" 88243789Sdim#include "cbcp.h" 89243789Sdim#include "datalink.h" 90263509Sdim#include "iface.h" 91252723Sdim#include "id.h" 92252723Sdim 93252723Sdim/* ``set'' values */ 94252723Sdim#define VAR_AUTHKEY 0 95252723Sdim#define VAR_DIAL 1 96252723Sdim#define VAR_LOGIN 2 97252723Sdim#define VAR_AUTHNAME 3 98252723Sdim#define VAR_AUTOLOAD 4 99252723Sdim#define VAR_WINSIZE 5 100252723Sdim#define VAR_DEVICE 6 101252723Sdim#define VAR_ACCMAP 7 102252723Sdim#define VAR_MRRU 8 103252723Sdim#define VAR_MRU 9 104252723Sdim#define VAR_MTU 10 105252723Sdim#define VAR_OPENMODE 11 106252723Sdim#define VAR_PHONE 12 107252723Sdim#define VAR_HANGUP 13 108252723Sdim#define VAR_IDLETIMEOUT 14 109252723Sdim#define VAR_LQRPERIOD 15 110252723Sdim#define VAR_LCPRETRY 16 111252723Sdim#define VAR_CHAPRETRY 17 112252723Sdim#define VAR_PAPRETRY 18 113252723Sdim#define VAR_CCPRETRY 19 114263509Sdim#define VAR_IPCPRETRY 20 115263509Sdim#define VAR_DNS 21 116263509Sdim#define VAR_NBNS 22 117263509Sdim#define VAR_MODE 23 118263509Sdim#define VAR_CALLBACK 24 119263509Sdim#define VAR_CBCP 25 120263509Sdim#define VAR_CHOKED 26 121263509Sdim#define VAR_SENDPIPE 27 122263509Sdim#define VAR_RECVPIPE 28 123263509Sdim#define VAR_RADIUS 29 124263509Sdim#define VAR_CD 30 125263509Sdim#define VAR_PARITY 31 126263509Sdim#define VAR_CRTSCTS 32 127263509Sdim#define VAR_URGENTPORTS 33 128263509Sdim#define VAR_LOGOUT 34 129263509Sdim#define VAR_IFQUEUE 35 130263509Sdim 131263509Sdim/* ``accept|deny|disable|enable'' masks */ 132263509Sdim#define NEG_HISMASK (1) 133263509Sdim#define NEG_MYMASK (2) 134263509Sdim 135263509Sdim/* ``accept|deny|disable|enable'' values */ 136263509Sdim#define NEG_ACFCOMP 40 137263509Sdim#define NEG_CHAP05 41 138263509Sdim#define NEG_CHAP80 42 139263509Sdim#define NEG_CHAP80LM 43 140263509Sdim#define NEG_DEFLATE 44 141263509Sdim#define NEG_DNS 45 142263509Sdim#define NEG_ENDDISC 46 143263509Sdim#define NEG_LQR 47 144263509Sdim#define NEG_PAP 48 145263509Sdim#define NEG_PPPDDEFLATE 49 146263509Sdim#define NEG_PRED1 50 147263509Sdim#define NEG_PROTOCOMP 51 148263509Sdim#define NEG_SHORTSEQ 52 149263509Sdim#define NEG_VJCOMP 53 150263509Sdim 151263509Sdimconst char Version[] = "2.27"; 152263509Sdim 153263509Sdimstatic int ShowCommand(struct cmdargs const *); 154263509Sdimstatic int TerminalCommand(struct cmdargs const *); 155263509Sdimstatic int QuitCommand(struct cmdargs const *); 156263509Sdimstatic int OpenCommand(struct cmdargs const *); 157263509Sdimstatic int CloseCommand(struct cmdargs const *); 158263509Sdimstatic int DownCommand(struct cmdargs const *); 159263509Sdimstatic int SetCommand(struct cmdargs const *); 160263509Sdimstatic int LinkCommand(struct cmdargs const *); 161263509Sdimstatic int AddCommand(struct cmdargs const *); 162263509Sdimstatic int DeleteCommand(struct cmdargs const *); 163263509Sdimstatic int NegotiateCommand(struct cmdargs const *); 164263509Sdimstatic int ClearCommand(struct cmdargs const *); 165263509Sdimstatic int RunListCommand(struct cmdargs const *); 166263509Sdimstatic int IfaceAddCommand(struct cmdargs const *); 167263509Sdimstatic int IfaceDeleteCommand(struct cmdargs const *); 168263509Sdimstatic int IfaceClearCommand(struct cmdargs const *); 169263509Sdimstatic int SetProcTitle(struct cmdargs const *); 170263509Sdim#ifndef NONAT 171263509Sdimstatic int NatEnable(struct cmdargs const *); 172263509Sdimstatic int NatOption(struct cmdargs const *); 173263509Sdim#endif 174263509Sdim 175263509Sdimstatic const char * 176263509Sdimshowcx(struct cmdtab const *cmd) 177263509Sdim{ 178263509Sdim if (cmd->lauth & LOCAL_CX) 179263509Sdim return "(c)"; 180263509Sdim else if (cmd->lauth & LOCAL_CX_OPT) 181263509Sdim return "(o)"; 182263509Sdim 183263509Sdim return ""; 184263509Sdim} 185263509Sdim 186263509Sdimstatic int 187263509SdimHelpCommand(struct cmdargs const *arg) 188263509Sdim{ 189263509Sdim struct cmdtab const *cmd; 190263509Sdim int n, cmax, dmax, cols, cxlen; 191263509Sdim const char *cx; 192263509Sdim 193263509Sdim if (!arg->prompt) { 194263509Sdim log_Printf(LogWARN, "help: Cannot help without a prompt\n"); 195263509Sdim return 0; 196263509Sdim } 197263509Sdim 198263509Sdim if (arg->argc > arg->argn) { 199263509Sdim for (cmd = arg->cmdtab; cmd->name || cmd->alias; cmd++) 200263509Sdim if ((cmd->lauth & arg->prompt->auth) && 201263509Sdim ((cmd->name && !strcasecmp(cmd->name, arg->argv[arg->argn])) || 202263509Sdim (cmd->alias && !strcasecmp(cmd->alias, arg->argv[arg->argn])))) { 203263509Sdim prompt_Printf(arg->prompt, "%s %s\n", cmd->syntax, showcx(cmd)); 204263509Sdim return 0; 205263509Sdim } 206263509Sdim return -1; 207263509Sdim } 208263509Sdim 209263509Sdim cmax = dmax = 0; 210263509Sdim for (cmd = arg->cmdtab; cmd->func; cmd++) 211263509Sdim if (cmd->name && (cmd->lauth & arg->prompt->auth)) { 212263509Sdim if ((n = strlen(cmd->name) + strlen(showcx(cmd))) > cmax) 213263509Sdim cmax = n; 214263509Sdim if ((n = strlen(cmd->helpmes)) > dmax) 215263509Sdim dmax = n; 216263509Sdim } 217263509Sdim 218263509Sdim cols = 80 / (dmax + cmax + 3); 219263509Sdim n = 0; 220263509Sdim prompt_Printf(arg->prompt, "(o) = Optional context," 221263509Sdim " (c) = Context required\n"); 222263509Sdim for (cmd = arg->cmdtab; cmd->func; cmd++) 223263509Sdim if (cmd->name && (cmd->lauth & arg->prompt->auth)) { 224263509Sdim cx = showcx(cmd); 225263509Sdim cxlen = cmax - strlen(cmd->name); 226263509Sdim if (n % cols != 0) 227263509Sdim prompt_Printf(arg->prompt, " "); 228263509Sdim prompt_Printf(arg->prompt, "%s%-*.*s: %-*.*s", 229263509Sdim cmd->name, cxlen, cxlen, cx, dmax, dmax, cmd->helpmes); 230263509Sdim if (++n % cols == 0) 231263509Sdim prompt_Printf(arg->prompt, "\n"); 232263509Sdim } 233263509Sdim if (n % cols != 0) 234263509Sdim prompt_Printf(arg->prompt, "\n"); 235263509Sdim 236263509Sdim return 0; 237263509Sdim} 238263509Sdim 239263509Sdimstatic int 240263509SdimIdentCommand(struct cmdargs const *arg) 241263509Sdim{ 242263509Sdim int f, pos; 243263509Sdim 244263509Sdim *arg->cx->physical->link.lcp.cfg.ident = '\0'; 245263509Sdim 246263509Sdim for (pos = 0, f = arg->argn; f < arg->argc; f++) 247263509Sdim pos += snprintf(arg->cx->physical->link.lcp.cfg.ident + pos, 248263509Sdim sizeof arg->cx->physical->link.lcp.cfg.ident - pos, "%s%s", 249263509Sdim f == arg->argn ? "" : " ", arg->argv[f]); 250263509Sdim 251263509Sdim return 0; 252263509Sdim} 253263509Sdim 254263509Sdimstatic int 255263509SdimSendIdentification(struct cmdargs const *arg) 256263509Sdim{ 257263509Sdim if (arg->cx->state < DATALINK_LCP) { 258263509Sdim log_Printf(LogWARN, "sendident: link has not reached LCP\n"); 259263509Sdim return 2; 260263509Sdim } 261263509Sdim return lcp_SendIdentification(&arg->cx->physical->link.lcp) ? 0 : 1; 262263509Sdim} 263263509Sdim 264263509Sdimstatic int 265263509SdimCloneCommand(struct cmdargs const *arg) 266263509Sdim{ 267263509Sdim char namelist[LINE_LEN]; 268263509Sdim char *name; 269263509Sdim int f; 270263509Sdim 271263509Sdim if (arg->argc == arg->argn) 272263509Sdim return -1; 273263509Sdim 274263509Sdim namelist[sizeof namelist - 1] = '\0'; 275263509Sdim for (f = arg->argn; f < arg->argc; f++) { 276263509Sdim strncpy(namelist, arg->argv[f], sizeof namelist - 1); 277263509Sdim for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) 278263509Sdim bundle_DatalinkClone(arg->bundle, arg->cx, name); 279263509Sdim } 280263509Sdim 281263509Sdim return 0; 282263509Sdim} 283263509Sdim 284263509Sdimstatic int 285263509SdimRemoveCommand(struct cmdargs const *arg) 286263509Sdim{ 287263509Sdim if (arg->argc != arg->argn) 288263509Sdim return -1; 289263509Sdim 290263509Sdim if (arg->cx->state != DATALINK_CLOSED) { 291263509Sdim log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n"); 292263509Sdim return 2; 293263509Sdim } 294263509Sdim 295263509Sdim bundle_DatalinkRemove(arg->bundle, arg->cx); 296263509Sdim return 0; 297263509Sdim} 298263509Sdim 299263509Sdimstatic int 300263509SdimRenameCommand(struct cmdargs const *arg) 301263509Sdim{ 302263509Sdim if (arg->argc != arg->argn + 1) 303263509Sdim return -1; 304263509Sdim 305263509Sdim if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn])) 306263509Sdim return 0; 307263509Sdim 308263509Sdim log_Printf(LogWARN, "%s -> %s: target name already exists\n", 309263509Sdim arg->cx->name, arg->argv[arg->argn]); 310263509Sdim return 1; 311263509Sdim} 312263509Sdim 313263509Sdimint 314263509SdimLoadCommand(struct cmdargs const *arg) 315263509Sdim{ 316263509Sdim const char *err; 317263509Sdim int n, mode; 318263509Sdim 319263509Sdim mode = arg->bundle->phys_type.all; 320263509Sdim 321263509Sdim if (arg->argn < arg->argc) { 322263509Sdim for (n = arg->argn; n < arg->argc; n++) 323263509Sdim if ((err = system_IsValid(arg->argv[n], arg->prompt, mode)) != NULL) { 324263509Sdim log_Printf(LogWARN, "%s: %s\n", arg->argv[n], err); 325263509Sdim return 1; 326263509Sdim } 327263509Sdim 328263509Sdim for (n = arg->argn; n < arg->argc; n++) { 329263509Sdim bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]); 330263509Sdim system_Select(arg->bundle, arg->argv[n], CONFFILE, arg->prompt, arg->cx); 331263509Sdim } 332263509Sdim bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]); 333263509Sdim } else if ((err = system_IsValid("default", arg->prompt, mode)) != NULL) { 334263509Sdim log_Printf(LogWARN, "default: %s\n", err); 335263509Sdim return 1; 336263509Sdim } else { 337263509Sdim bundle_SetLabel(arg->bundle, "default"); 338263509Sdim system_Select(arg->bundle, "default", CONFFILE, arg->prompt, arg->cx); 339263509Sdim bundle_SetLabel(arg->bundle, "default"); 340263509Sdim } 341263509Sdim 342263509Sdim return 0; 343263509Sdim} 344263509Sdim 345263509Sdimint 346263509SdimSaveCommand(struct cmdargs const *arg) 347263509Sdim{ 348263509Sdim log_Printf(LogWARN, "save command is not implemented (yet).\n"); 349263509Sdim return 1; 350263509Sdim} 351263509Sdim 352263509Sdimstatic int 353263509SdimDialCommand(struct cmdargs const *arg) 354263509Sdim{ 355263509Sdim int res; 356263509Sdim 357263509Sdim if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO))) 358263509Sdim || (!arg->cx && 359263509Sdim (arg->bundle->phys_type.all & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) { 360263509Sdim log_Printf(LogWARN, "Manual dial is only available for auto and" 361263509Sdim " interactive links\n"); 362263509Sdim return 1; 363263509Sdim } 364263509Sdim 365263509Sdim if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0) 366263509Sdim return res; 367263509Sdim 368252723Sdim bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1); 369252723Sdim 370243789Sdim return 0; 371243789Sdim} 372243789Sdim 373252723Sdim#define isinword(ch) (isalnum(ch) || (ch) == '_') 374252723Sdim 375252723Sdimstatic char * 376252723Sdimstrstrword(char *big, const char *little) 377252723Sdim{ 378243789Sdim /* Get the first occurance of the word ``little'' in ``big'' */ 379243789Sdim char *pos; 380243789Sdim int len; 381252723Sdim 382243789Sdim pos = big; 383243789Sdim len = strlen(little); 384243789Sdim 385243789Sdim while ((pos = strstr(pos, little)) != NULL) 386243789Sdim if ((pos != big && isinword(pos[-1])) || isinword(pos[len])) 387243789Sdim pos++; 388243789Sdim else if (pos != big && pos[-1] == '\\') 389243789Sdim memmove(pos - 1, pos, strlen(pos) + 1); 390243789Sdim else 391243789Sdim break; 392243789Sdim 393243789Sdim return pos; 394243789Sdim} 395243789Sdim 396243789Sdimstatic char * 397243789Sdimsubst(char *tgt, const char *oldstr, const char *newstr) 398243789Sdim{ 399243789Sdim /* tgt is a malloc()d area... realloc() as necessary */ 400243789Sdim char *word, *ntgt; 401252723Sdim int ltgt, loldstr, lnewstr, pos; 402252723Sdim 403252723Sdim if ((word = strstrword(tgt, oldstr)) == NULL) 404252723Sdim return tgt; 405252723Sdim 406252723Sdim ltgt = strlen(tgt) + 1; 407243789Sdim loldstr = strlen(oldstr); 408243789Sdim lnewstr = strlen(newstr); 409252723Sdim do { 410243789Sdim pos = word - tgt; 411252723Sdim if (loldstr > lnewstr) 412243789Sdim bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr); 413243789Sdim if (loldstr != lnewstr) { 414243789Sdim ntgt = realloc(tgt, ltgt += lnewstr - loldstr); 415243789Sdim if (ntgt == NULL) 416252723Sdim break; /* Oh wonderful ! */ 417243789Sdim word = ntgt + pos; 418243789Sdim tgt = ntgt; 419252723Sdim } 420243789Sdim if (lnewstr > loldstr) 421252723Sdim bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr); 422243789Sdim bcopy(newstr, word, lnewstr); 423243789Sdim } while ((word = strstrword(word, oldstr))); 424243789Sdim 425243789Sdim return tgt; 426252723Sdim} 427252723Sdim 428243789Sdimvoid 429243789Sdimcommand_Expand(char **nargv, int argc, char const *const *oargv, 430243789Sdim struct bundle *bundle, int inc0, pid_t pid) 431243789Sdim{ 432243789Sdim int arg; 433243789Sdim char pidstr[12]; 434243789Sdim 435243789Sdim if (inc0) 436243789Sdim arg = 0; /* Start at arg 0 */ 437243789Sdim else { 438243789Sdim nargv[0] = strdup(oargv[0]); 439243789Sdim arg = 1; 440243789Sdim } 441243789Sdim snprintf(pidstr, sizeof pidstr, "%d", (int)pid); 442243789Sdim for (; arg < argc; arg++) { 443243789Sdim nargv[arg] = strdup(oargv[arg]); 444252723Sdim nargv[arg] = subst(nargv[arg], "HISADDR", 445243789Sdim inet_ntoa(bundle->ncp.ipcp.peer_ip)); 446243789Sdim nargv[arg] = subst(nargv[arg], "AUTHNAME", bundle->cfg.auth.name); 447252723Sdim nargv[arg] = subst(nargv[arg], "INTERFACE", bundle->iface->name); 448243789Sdim nargv[arg] = subst(nargv[arg], "MYADDR", inet_ntoa(bundle->ncp.ipcp.my_ip)); 449243789Sdim nargv[arg] = subst(nargv[arg], "USER", bundle->ncp.mp.peer.authname); 450243789Sdim nargv[arg] = subst(nargv[arg], "PEER_ENDDISC", 451243789Sdim mp_Enddisc(bundle->ncp.mp.peer.enddisc.class, 452263509Sdim bundle->ncp.mp.peer.enddisc.address, 453263509Sdim bundle->ncp.mp.peer.enddisc.len)); 454263509Sdim nargv[arg] = subst(nargv[arg], "ENDDISC", 455263509Sdim mp_Enddisc(bundle->ncp.mp.cfg.enddisc.class, 456263509Sdim bundle->ncp.mp.cfg.enddisc.address, 457263509Sdim bundle->ncp.mp.cfg.enddisc.len)); 458263509Sdim nargv[arg] = subst(nargv[arg], "PROCESSID", pidstr); 459263509Sdim nargv[arg] = subst(nargv[arg], "LABEL", bundle_GetLabel(bundle)); 460263509Sdim nargv[arg] = subst(nargv[arg], "DNS0", 461263509Sdim inet_ntoa(bundle->ncp.ipcp.ns.dns[0])); 462263509Sdim nargv[arg] = subst(nargv[arg], "DNS1", 463252723Sdim inet_ntoa(bundle->ncp.ipcp.ns.dns[1])); 464252723Sdim nargv[arg] = subst(nargv[arg], "VERSION", Version); 465243789Sdim nargv[arg] = subst(nargv[arg], "COMPILATIONDATE", __DATE__); 466243789Sdim } 467263509Sdim nargv[arg] = NULL; 468263509Sdim} 469263509Sdim 470263509Sdimstatic int 471263509SdimShellCommand(struct cmdargs const *arg, int bg) 472263509Sdim{ 473263509Sdim const char *shell; 474263509Sdim pid_t shpid, pid; 475252723Sdim 476252723Sdim#ifdef SHELL_ONLY_INTERACTIVELY 477252723Sdim /* we're only allowed to shell when we run ppp interactively */ 478252723Sdim if (arg->prompt && arg->prompt->owner) { 479252723Sdim log_Printf(LogWARN, "Can't start a shell from a network connection\n"); 480252723Sdim return 1; 481252723Sdim } 482252723Sdim#endif 483252723Sdim 484252723Sdim if (arg->argc == arg->argn) { 485252723Sdim if (!arg->prompt) { 486252723Sdim log_Printf(LogWARN, "Can't start an interactive shell from" 487252723Sdim " a config file\n"); 488252723Sdim return 1; 489252723Sdim } else if (arg->prompt->owner) { 490252723Sdim log_Printf(LogWARN, "Can't start an interactive shell from" 491252723Sdim " a socket connection\n"); 492252723Sdim return 1; 493252723Sdim } else if (bg) { 494252723Sdim log_Printf(LogWARN, "Can only start an interactive shell in" 495252723Sdim " the foreground mode\n"); 496243789Sdim return 1; 497243789Sdim } 498243789Sdim } 499243789Sdim 500243789Sdim pid = getpid(); 501243789Sdim if ((shpid = fork()) == 0) { 502243789Sdim int i, fd; 503243789Sdim 504243789Sdim if ((shell = getenv("SHELL")) == 0) 505243789Sdim shell = _PATH_BSHELL; 506243789Sdim 507243789Sdim timer_TermService(); 508243789Sdim 509243789Sdim if (arg->prompt) 510243789Sdim fd = arg->prompt->fd_out; 511243789Sdim else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) { 512243789Sdim log_Printf(LogALERT, "Failed to open %s: %s\n", 513243789Sdim _PATH_DEVNULL, strerror(errno)); 514243789Sdim exit(1); 515243789Sdim } 516243789Sdim dup2(fd, STDIN_FILENO); 517243789Sdim dup2(fd, STDOUT_FILENO); 518243789Sdim dup2(fd, STDERR_FILENO); 519 for (i = getdtablesize(); i > STDERR_FILENO; i--) 520 fcntl(i, F_SETFD, 1); 521 522#ifndef NOSUID 523 setuid(ID0realuid()); 524#endif 525 if (arg->argc > arg->argn) { 526 /* substitute pseudo args */ 527 char *argv[MAXARGS]; 528 int argc = arg->argc - arg->argn; 529 530 if (argc >= sizeof argv / sizeof argv[0]) { 531 argc = sizeof argv / sizeof argv[0] - 1; 532 log_Printf(LogWARN, "Truncating shell command to %d args\n", argc); 533 } 534 command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 0, pid); 535 if (bg) { 536 pid_t p; 537 538 p = getpid(); 539 if (daemon(1, 1) == -1) { 540 log_Printf(LogERROR, "%d: daemon: %s\n", (int)p, strerror(errno)); 541 exit(1); 542 } 543 } else if (arg->prompt) 544 printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]); 545 execvp(argv[0], argv); 546 } else { 547 if (arg->prompt) 548 printf("ppp: Pausing until %s finishes\n", shell); 549 prompt_TtyOldMode(arg->prompt); 550 execl(shell, shell, NULL); 551 } 552 553 log_Printf(LogWARN, "exec() of %s failed: %s\n", 554 arg->argc > arg->argn ? arg->argv[arg->argn] : shell, 555 strerror(errno)); 556 _exit(255); 557 } 558 559 if (shpid == (pid_t) - 1) 560 log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno)); 561 else { 562 int status; 563 waitpid(shpid, &status, 0); 564 } 565 566 if (arg->prompt && !arg->prompt->owner) 567 prompt_TtyCommandMode(arg->prompt); 568 569 return 0; 570} 571 572static int 573BgShellCommand(struct cmdargs const *arg) 574{ 575 if (arg->argc == arg->argn) 576 return -1; 577 return ShellCommand(arg, 1); 578} 579 580static int 581FgShellCommand(struct cmdargs const *arg) 582{ 583 return ShellCommand(arg, 0); 584} 585 586static int 587ResolvCommand(struct cmdargs const *arg) 588{ 589 if (arg->argc == arg->argn + 1) { 590 if (!strcasecmp(arg->argv[arg->argn], "reload")) 591 ipcp_LoadDNS(&arg->bundle->ncp.ipcp); 592 else if (!strcasecmp(arg->argv[arg->argn], "restore")) 593 ipcp_RestoreDNS(&arg->bundle->ncp.ipcp); 594 else if (!strcasecmp(arg->argv[arg->argn], "rewrite")) 595 ipcp_WriteDNS(&arg->bundle->ncp.ipcp); 596 else if (!strcasecmp(arg->argv[arg->argn], "readonly")) 597 arg->bundle->ncp.ipcp.ns.writable = 0; 598 else if (!strcasecmp(arg->argv[arg->argn], "writable")) 599 arg->bundle->ncp.ipcp.ns.writable = 1; 600 else 601 return -1; 602 603 return 0; 604 } 605 606 return -1; 607} 608 609#ifndef NONAT 610static struct cmdtab const NatCommands[] = 611{ 612 {"addr", NULL, nat_RedirectAddr, LOCAL_AUTH, 613 "static address translation", "nat addr [addr_local addr_alias]"}, 614 {"deny_incoming", NULL, NatOption, LOCAL_AUTH, 615 "stop incoming connections", "nat deny_incoming yes|no", 616 (const void *) PKT_ALIAS_DENY_INCOMING}, 617 {"enable", NULL, NatEnable, LOCAL_AUTH, 618 "enable NAT", "nat enable yes|no"}, 619 {"log", NULL, NatOption, LOCAL_AUTH, 620 "log NAT link creation", "nat log yes|no", 621 (const void *) PKT_ALIAS_LOG}, 622 {"port", NULL, nat_RedirectPort, LOCAL_AUTH, "port redirection", 623 "nat port proto localaddr:port[-port] aliasport[-aliasport]"}, 624 {"proxy", NULL, nat_ProxyRule, LOCAL_AUTH, 625 "proxy control", "nat proxy server host[:port] ..."}, 626 {"same_ports", NULL, NatOption, LOCAL_AUTH, 627 "try to leave port numbers unchanged", "nat same_ports yes|no", 628 (const void *) PKT_ALIAS_SAME_PORTS}, 629 {"target", NULL, nat_SetTarget, LOCAL_AUTH, 630 "Default address for incoming connections", "nat target addr" }, 631 {"unregistered_only", NULL, NatOption, LOCAL_AUTH, 632 "translate unregistered (private) IP address space only", 633 "nat unregistered_only yes|no", 634 (const void *) PKT_ALIAS_UNREGISTERED_ONLY}, 635 {"use_sockets", NULL, NatOption, LOCAL_AUTH, 636 "allocate host sockets", "nat use_sockets yes|no", 637 (const void *) PKT_ALIAS_USE_SOCKETS}, 638 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 639 "Display this message", "nat help|? [command]", NatCommands}, 640 {NULL, NULL, NULL}, 641}; 642#endif 643 644static struct cmdtab const AllowCommands[] = { 645 {"modes", "mode", AllowModes, LOCAL_AUTH, 646 "Only allow certain ppp modes", "allow modes mode..."}, 647 {"users", "user", AllowUsers, LOCAL_AUTH, 648 "Only allow ppp access to certain users", "allow users logname..."}, 649 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 650 "Display this message", "allow help|? [command]", AllowCommands}, 651 {NULL, NULL, NULL}, 652}; 653 654static struct cmdtab const IfaceCommands[] = 655{ 656 {"add", NULL, IfaceAddCommand, LOCAL_AUTH, 657 "Add iface address", "iface add addr[/bits| mask] peer", NULL}, 658 {NULL, "add!", IfaceAddCommand, LOCAL_AUTH, 659 "Add or change an iface address", "iface add! addr[/bits| mask] peer", 660 (void *)1}, 661 {"clear", NULL, IfaceClearCommand, LOCAL_AUTH, 662 "Clear iface address(es)", "iface clear"}, 663 {"delete", "rm", IfaceDeleteCommand, LOCAL_AUTH, 664 "Delete iface address", "iface delete addr", NULL}, 665 {NULL, "rm!", IfaceDeleteCommand, LOCAL_AUTH, 666 "Delete iface address", "iface delete addr", (void *)1}, 667 {NULL, "delete!", IfaceDeleteCommand, LOCAL_AUTH, 668 "Delete iface address", "iface delete addr", (void *)1}, 669 {"show", NULL, iface_Show, LOCAL_AUTH, 670 "Show iface address(es)", "iface show"}, 671 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 672 "Display this message", "nat help|? [command]", IfaceCommands}, 673 {NULL, NULL, NULL}, 674}; 675 676static struct cmdtab const Commands[] = { 677 {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT, 678 "accept option request", "accept option .."}, 679 {"add", NULL, AddCommand, LOCAL_AUTH, 680 "add route", "add dest mask gateway", NULL}, 681 {NULL, "add!", AddCommand, LOCAL_AUTH, 682 "add or change route", "add! dest mask gateway", (void *)1}, 683 {"allow", "auth", RunListCommand, LOCAL_AUTH, 684 "Allow ppp access", "allow users|modes ....", AllowCommands}, 685 {"bg", "!bg", BgShellCommand, LOCAL_AUTH, 686 "Run a background command", "[!]bg command"}, 687 {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT, 688 "Clear throughput statistics", 689 "clear ipcp|physical [current|overall|peak]..."}, 690 {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX, 691 "Clone a link", "clone newname..."}, 692 {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT, 693 "Close an FSM", "close [lcp|ccp]"}, 694 {"delete", NULL, DeleteCommand, LOCAL_AUTH, 695 "delete route", "delete dest", NULL}, 696 {NULL, "delete!", DeleteCommand, LOCAL_AUTH, 697 "delete a route if it exists", "delete! dest", (void *)1}, 698 {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT, 699 "Deny option request", "deny option .."}, 700 {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT, 701 "Dial and login", "dial|call [system ...]", NULL}, 702 {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT, 703 "Disable option", "disable option .."}, 704 {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT, 705 "Generate a down event", "down [ccp|lcp]"}, 706 {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT, 707 "Enable option", "enable option .."}, 708 {"ident", NULL, IdentCommand, LOCAL_AUTH | LOCAL_CX, 709 "Set the link identity", "ident text..."}, 710 {"iface", "interface", RunListCommand, LOCAL_AUTH, 711 "interface control", "iface option ...", IfaceCommands}, 712 {"link", "datalink", LinkCommand, LOCAL_AUTH, 713 "Link specific commands", "link name command ..."}, 714 {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT, 715 "Load settings", "load [system ...]"}, 716#ifndef NONAT 717 {"nat", "alias", RunListCommand, LOCAL_AUTH, 718 "NAT control", "nat option yes|no", NatCommands}, 719#endif 720 {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT, 721 "Open an FSM", "open! [lcp|ccp|ipcp]", (void *)1}, 722 {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH, 723 "Password for manipulation", "passwd LocalPassword"}, 724 {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 725 "Quit PPP program", "quit|bye [all]"}, 726 {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX, 727 "Remove a link", "remove"}, 728 {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX, 729 "Rename a link", "rename name"}, 730 {"resolv", NULL, ResolvCommand, LOCAL_AUTH, 731 "Manipulate resolv.conf", "resolv readonly|reload|restore|rewrite|writable"}, 732 {"save", NULL, SaveCommand, LOCAL_AUTH, 733 "Save settings", "save"}, 734 {"sendident", NULL, SendIdentification, LOCAL_AUTH | LOCAL_CX, 735 "Transmit the link identity", "sendident"}, 736 {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT, 737 "Set parameters", "set[up] var value"}, 738 {"shell", "!", FgShellCommand, LOCAL_AUTH, 739 "Run a subshell", "shell|! [sh command]"}, 740 {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT, 741 "Show status and stats", "show var"}, 742 {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX, 743 "Enter terminal mode", "term"}, 744 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 745 "Display this message", "help|? [command]", Commands}, 746 {NULL, NULL, NULL}, 747}; 748 749static int 750ShowEscape(struct cmdargs const *arg) 751{ 752 if (arg->cx->physical->async.cfg.EscMap[32]) { 753 int code, bit; 754 const char *sep = ""; 755 756 for (code = 0; code < 32; code++) 757 if (arg->cx->physical->async.cfg.EscMap[code]) 758 for (bit = 0; bit < 8; bit++) 759 if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) { 760 prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit); 761 sep = ", "; 762 } 763 prompt_Printf(arg->prompt, "\n"); 764 } 765 return 0; 766} 767 768static int 769ShowTimerList(struct cmdargs const *arg) 770{ 771 timer_Show(0, arg->prompt); 772 return 0; 773} 774 775static int 776ShowStopped(struct cmdargs const *arg) 777{ 778 prompt_Printf(arg->prompt, " Stopped Timer: LCP: "); 779 if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load) 780 prompt_Printf(arg->prompt, "Disabled"); 781 else 782 prompt_Printf(arg->prompt, "%ld secs", 783 arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS); 784 785 prompt_Printf(arg->prompt, ", CCP: "); 786 if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load) 787 prompt_Printf(arg->prompt, "Disabled"); 788 else 789 prompt_Printf(arg->prompt, "%ld secs", 790 arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS); 791 792 prompt_Printf(arg->prompt, "\n"); 793 794 return 0; 795} 796 797static int 798ShowVersion(struct cmdargs const *arg) 799{ 800 prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, __DATE__); 801 return 0; 802} 803 804static int 805ShowProtocolStats(struct cmdargs const *arg) 806{ 807 struct link *l = command_ChooseLink(arg); 808 809 prompt_Printf(arg->prompt, "%s:\n", l->name); 810 link_ReportProtocolStatus(l, arg->prompt); 811 return 0; 812} 813 814static struct cmdtab const ShowCommands[] = { 815 {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH, 816 "bundle details", "show bundle"}, 817 {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT, 818 "CCP status", "show cpp"}, 819 {"compress", NULL, sl_Show, LOCAL_AUTH, 820 "VJ compression stats", "show compress"}, 821 {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX, 822 "escape characters", "show escape"}, 823 {"filter", NULL, filter_Show, LOCAL_AUTH, 824 "packet filters", "show filter [in|out|dial|alive]"}, 825 {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX, 826 "HDLC errors", "show hdlc"}, 827 {"iface", "interface", iface_Show, LOCAL_AUTH, 828 "Interface status", "show iface"}, 829 {"ipcp", NULL, ipcp_Show, LOCAL_AUTH, 830 "IPCP status", "show ipcp"}, 831 {"layers", NULL, link_ShowLayers, LOCAL_AUTH | LOCAL_CX_OPT, 832 "Protocol layers", "show layers"}, 833 {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX, 834 "LCP status", "show lcp"}, 835 {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX, 836 "(high-level) link info", "show link"}, 837 {"links", NULL, bundle_ShowLinks, LOCAL_AUTH, 838 "available link names", "show links"}, 839 {"log", NULL, log_ShowLevel, LOCAL_AUTH, 840 "log levels", "show log"}, 841 {"mem", NULL, mbuf_Show, LOCAL_AUTH, 842 "mbuf allocations", "show mem"}, 843 {"physical", NULL, physical_ShowStatus, LOCAL_AUTH | LOCAL_CX, 844 "(low-level) link info", "show physical"}, 845 {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH, 846 "multilink setup", "show mp"}, 847 {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT, 848 "protocol summary", "show proto"}, 849 {"route", NULL, route_Show, LOCAL_AUTH, 850 "routing table", "show route"}, 851 {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX, 852 "STOPPED timeout", "show stopped"}, 853 {"timers", NULL, ShowTimerList, LOCAL_AUTH, 854 "alarm timers", "show timers"}, 855 {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH, 856 "version string", "show version"}, 857 {"who", NULL, log_ShowWho, LOCAL_AUTH, 858 "client list", "show who"}, 859 {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH, 860 "Display this message", "show help|? [command]", ShowCommands}, 861 {NULL, NULL, NULL}, 862}; 863 864static struct cmdtab const * 865FindCommand(struct cmdtab const *cmds, const char *str, int *pmatch) 866{ 867 int nmatch; 868 int len; 869 struct cmdtab const *found; 870 871 found = NULL; 872 len = strlen(str); 873 nmatch = 0; 874 while (cmds->func) { 875 if (cmds->name && strncasecmp(str, cmds->name, len) == 0) { 876 if (cmds->name[len] == '\0') { 877 *pmatch = 1; 878 return cmds; 879 } 880 nmatch++; 881 found = cmds; 882 } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) { 883 if (cmds->alias[len] == '\0') { 884 *pmatch = 1; 885 return cmds; 886 } 887 nmatch++; 888 found = cmds; 889 } 890 cmds++; 891 } 892 *pmatch = nmatch; 893 return found; 894} 895 896static const char * 897mkPrefix(int argc, char const *const *argv, char *tgt, int sz) 898{ 899 int f, tlen, len; 900 901 tlen = 0; 902 for (f = 0; f < argc && tlen < sz - 2; f++) { 903 if (f) 904 tgt[tlen++] = ' '; 905 len = strlen(argv[f]); 906 if (len > sz - tlen - 1) 907 len = sz - tlen - 1; 908 strncpy(tgt+tlen, argv[f], len); 909 tlen += len; 910 } 911 tgt[tlen] = '\0'; 912 return tgt; 913} 914 915static int 916FindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn, 917 char const *const *argv, struct prompt *prompt, struct datalink *cx) 918{ 919 struct cmdtab const *cmd; 920 int val = 1; 921 int nmatch; 922 struct cmdargs arg; 923 char prefix[100]; 924 925 cmd = FindCommand(cmds, argv[argn], &nmatch); 926 if (nmatch > 1) 927 log_Printf(LogWARN, "%s: Ambiguous command\n", 928 mkPrefix(argn+1, argv, prefix, sizeof prefix)); 929 else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) { 930 if ((cmd->lauth & LOCAL_CX) && !cx) 931 /* We've got no context, but we require it */ 932 cx = bundle2datalink(bundle, NULL); 933 934 if ((cmd->lauth & LOCAL_CX) && !cx) 935 log_Printf(LogWARN, "%s: No context (use the `link' command)\n", 936 mkPrefix(argn+1, argv, prefix, sizeof prefix)); 937 else { 938 if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) { 939 log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n", 940 mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name); 941 cx = NULL; 942 } 943 arg.cmdtab = cmds; 944 arg.cmd = cmd; 945 arg.argc = argc; 946 arg.argn = argn+1; 947 arg.argv = argv; 948 arg.bundle = bundle; 949 arg.cx = cx; 950 arg.prompt = prompt; 951 val = (*cmd->func) (&arg); 952 } 953 } else 954 log_Printf(LogWARN, "%s: Invalid command\n", 955 mkPrefix(argn+1, argv, prefix, sizeof prefix)); 956 957 if (val == -1) 958 log_Printf(LogWARN, "Usage: %s\n", cmd->syntax); 959 else if (val) 960 log_Printf(LogWARN, "%s: Failed %d\n", 961 mkPrefix(argn+1, argv, prefix, sizeof prefix), val); 962 963 return val; 964} 965 966int 967command_Expand_Interpret(char *buff, int nb, char *argv[MAXARGS], int offset) 968{ 969 char buff2[LINE_LEN-offset]; 970 971 InterpretArg(buff, buff2); 972 strncpy(buff, buff2, LINE_LEN - offset - 1); 973 buff[LINE_LEN - offset - 1] = '\0'; 974 975 return command_Interpret(buff, nb, argv); 976} 977 978int 979command_Interpret(char *buff, int nb, char *argv[MAXARGS]) 980{ 981 char *cp; 982 983 if (nb > 0) { 984 cp = buff + strcspn(buff, "\r\n"); 985 if (cp) 986 *cp = '\0'; 987 return MakeArgs(buff, argv, MAXARGS, PARSE_REDUCE); 988 } 989 return 0; 990} 991 992static int 993arghidden(int argc, char const *const *argv, int n) 994{ 995 /* Is arg n of the given command to be hidden from the log ? */ 996 997 /* set authkey xxxxx */ 998 /* set key xxxxx */ 999 if (n == 2 && !strncasecmp(argv[0], "se", 2) && 1000 (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2))) 1001 return 1; 1002 1003 /* passwd xxxxx */ 1004 if (n == 1 && !strncasecmp(argv[0], "p", 1)) 1005 return 1; 1006 1007 /* set server port xxxxx .... */ 1008 if (n == 3 && !strncasecmp(argv[0], "se", 2) && 1009 !strncasecmp(argv[1], "se", 2)) 1010 return 1; 1011 1012 return 0; 1013} 1014 1015void 1016command_Run(struct bundle *bundle, int argc, char const *const *argv, 1017 struct prompt *prompt, const char *label, struct datalink *cx) 1018{ 1019 if (argc > 0) { 1020 if (log_IsKept(LogCOMMAND)) { 1021 char buf[LINE_LEN]; 1022 int f, n; 1023 1024 if (label) { 1025 strncpy(buf, label, sizeof buf - 3); 1026 buf[sizeof buf - 3] = '\0'; 1027 strcat(buf, ": "); 1028 n = strlen(buf); 1029 } else { 1030 *buf = '\0'; 1031 n = 0; 1032 } 1033 buf[sizeof buf - 1] = '\0'; /* In case we run out of room in buf */ 1034 1035 for (f = 0; f < argc; f++) { 1036 if (n < sizeof buf - 1 && f) 1037 buf[n++] = ' '; 1038 if (arghidden(argc, argv, f)) 1039 strncpy(buf+n, "********", sizeof buf - n - 1); 1040 else 1041 strncpy(buf+n, argv[f], sizeof buf - n - 1); 1042 n += strlen(buf+n); 1043 } 1044 log_Printf(LogCOMMAND, "%s\n", buf); 1045 } 1046 FindExec(bundle, Commands, argc, 0, argv, prompt, cx); 1047 } 1048} 1049 1050int 1051command_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt, 1052 const char *label) 1053{ 1054 int argc; 1055 char *argv[MAXARGS]; 1056 1057 if ((argc = command_Expand_Interpret(buff, nb, argv, 0)) < 0) 1058 return 0; 1059 1060 command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL); 1061 return 1; 1062} 1063 1064static int 1065ShowCommand(struct cmdargs const *arg) 1066{ 1067 if (!arg->prompt) 1068 log_Printf(LogWARN, "show: Cannot show without a prompt\n"); 1069 else if (arg->argc > arg->argn) 1070 FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv, 1071 arg->prompt, arg->cx); 1072 else 1073 prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n"); 1074 1075 return 0; 1076} 1077 1078static int 1079TerminalCommand(struct cmdargs const *arg) 1080{ 1081 if (!arg->prompt) { 1082 log_Printf(LogWARN, "term: Need a prompt\n"); 1083 return 1; 1084 } 1085 1086 if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) { 1087 prompt_Printf(arg->prompt, "LCP state is [%s]\n", 1088 State2Nam(arg->cx->physical->link.lcp.fsm.state)); 1089 return 1; 1090 } 1091 1092 datalink_Up(arg->cx, 0, 0); 1093 prompt_TtyTermMode(arg->prompt, arg->cx); 1094 return 0; 1095} 1096 1097static int 1098QuitCommand(struct cmdargs const *arg) 1099{ 1100 if (!arg->prompt || prompt_IsController(arg->prompt) || 1101 (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") && 1102 (arg->prompt->auth & LOCAL_AUTH))) 1103 Cleanup(EX_NORMAL); 1104 if (arg->prompt) 1105 prompt_Destroy(arg->prompt, 1); 1106 1107 return 0; 1108} 1109 1110static int 1111OpenCommand(struct cmdargs const *arg) 1112{ 1113 if (arg->argc == arg->argn) 1114 bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1); 1115 else if (arg->argc == arg->argn + 1) { 1116 if (!strcasecmp(arg->argv[arg->argn], "lcp")) { 1117 struct datalink *cx = arg->cx ? 1118 arg->cx : bundle2datalink(arg->bundle, NULL); 1119 if (cx) { 1120 if (cx->physical->link.lcp.fsm.state == ST_OPENED) 1121 fsm_Reopen(&cx->physical->link.lcp.fsm); 1122 else 1123 bundle_Open(arg->bundle, cx->name, PHYS_ALL, 1); 1124 } else 1125 log_Printf(LogWARN, "open lcp: You must specify a link\n"); 1126 } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) { 1127 struct fsm *fp; 1128 1129 fp = &command_ChooseLink(arg)->ccp.fsm; 1130 if (fp->link->lcp.fsm.state != ST_OPENED) 1131 log_Printf(LogWARN, "open: LCP must be open before opening CCP\n"); 1132 else if (fp->state == ST_OPENED) 1133 fsm_Reopen(fp); 1134 else { 1135 fp->open_mode = 0; /* Not passive any more */ 1136 if (fp->state == ST_STOPPED) { 1137 fsm_Down(fp); 1138 fsm_Up(fp); 1139 } else { 1140 fsm_Up(fp); 1141 fsm_Open(fp); 1142 } 1143 } 1144 } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) { 1145 if (arg->cx) 1146 log_Printf(LogWARN, "open ipcp: You need not specify a link\n"); 1147 if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED) 1148 fsm_Reopen(&arg->bundle->ncp.ipcp.fsm); 1149 else 1150 bundle_Open(arg->bundle, NULL, PHYS_ALL, 1); 1151 } else 1152 return -1; 1153 } else 1154 return -1; 1155 1156 return 0; 1157} 1158 1159static int 1160CloseCommand(struct cmdargs const *arg) 1161{ 1162 if (arg->argc == arg->argn) 1163 bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN); 1164 else if (arg->argc == arg->argn + 1) { 1165 if (!strcasecmp(arg->argv[arg->argn], "lcp")) 1166 bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP); 1167 else if (!strcasecmp(arg->argv[arg->argn], "ccp") || 1168 !strcasecmp(arg->argv[arg->argn], "ccp!")) { 1169 struct fsm *fp; 1170 1171 fp = &command_ChooseLink(arg)->ccp.fsm; 1172 if (fp->state == ST_OPENED) { 1173 fsm_Close(fp); 1174 if (arg->argv[arg->argn][3] == '!') 1175 fp->open_mode = 0; /* Stay ST_CLOSED */ 1176 else 1177 fp->open_mode = OPEN_PASSIVE; /* Wait for the peer to start */ 1178 } 1179 } else 1180 return -1; 1181 } else 1182 return -1; 1183 1184 return 0; 1185} 1186 1187static int 1188DownCommand(struct cmdargs const *arg) 1189{ 1190 if (arg->argc == arg->argn) { 1191 if (arg->cx) 1192 datalink_Down(arg->cx, CLOSE_STAYDOWN); 1193 else 1194 bundle_Down(arg->bundle, CLOSE_STAYDOWN); 1195 } else if (arg->argc == arg->argn + 1) { 1196 if (!strcasecmp(arg->argv[arg->argn], "lcp")) { 1197 if (arg->cx) 1198 datalink_Down(arg->cx, CLOSE_LCP); 1199 else 1200 bundle_Down(arg->bundle, CLOSE_LCP); 1201 } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) { 1202 struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm : 1203 &arg->bundle->ncp.mp.link.ccp.fsm; 1204 fsm2initial(fp); 1205 } else 1206 return -1; 1207 } else 1208 return -1; 1209 1210 return 0; 1211} 1212 1213static int 1214SetModemSpeed(struct cmdargs const *arg) 1215{ 1216 long speed; 1217 char *end; 1218 1219 if (arg->argc > arg->argn && *arg->argv[arg->argn]) { 1220 if (arg->argc > arg->argn+1) { 1221 log_Printf(LogWARN, "SetModemSpeed: Too many arguments\n"); 1222 return -1; 1223 } 1224 if (strcasecmp(arg->argv[arg->argn], "sync") == 0) { 1225 physical_SetSync(arg->cx->physical); 1226 return 0; 1227 } 1228 end = NULL; 1229 speed = strtol(arg->argv[arg->argn], &end, 10); 1230 if (*end) { 1231 log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"", 1232 arg->argv[arg->argn]); 1233 return -1; 1234 } 1235 if (physical_SetSpeed(arg->cx->physical, speed)) 1236 return 0; 1237 log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]); 1238 } else 1239 log_Printf(LogWARN, "SetModemSpeed: No speed specified\n"); 1240 1241 return -1; 1242} 1243 1244static int 1245SetStoppedTimeout(struct cmdargs const *arg) 1246{ 1247 struct link *l = &arg->cx->physical->link; 1248 1249 l->lcp.fsm.StoppedTimer.load = 0; 1250 l->ccp.fsm.StoppedTimer.load = 0; 1251 if (arg->argc <= arg->argn+2) { 1252 if (arg->argc > arg->argn) { 1253 l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS; 1254 if (arg->argc > arg->argn+1) 1255 l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS; 1256 } 1257 return 0; 1258 } 1259 return -1; 1260} 1261 1262static int 1263SetServer(struct cmdargs const *arg) 1264{ 1265 int res = -1; 1266 1267 if (arg->argc > arg->argn && arg->argc < arg->argn+4) { 1268 const char *port, *passwd, *mask; 1269 int mlen; 1270 1271 /* What's what ? */ 1272 port = arg->argv[arg->argn]; 1273 if (arg->argc == arg->argn + 2) { 1274 passwd = arg->argv[arg->argn+1]; 1275 mask = NULL; 1276 } else if (arg->argc == arg->argn + 3) { 1277 passwd = arg->argv[arg->argn+1]; 1278 mask = arg->argv[arg->argn+2]; 1279 mlen = strlen(mask); 1280 if (mlen == 0 || mlen > 4 || strspn(mask, "01234567") != mlen || 1281 (mlen == 4 && *mask != '0')) { 1282 log_Printf(LogWARN, "%s %s: %s: Invalid mask\n", 1283 arg->argv[arg->argn - 2], arg->argv[arg->argn - 1], mask); 1284 return -1; 1285 } 1286 } else if (strcasecmp(port, "none") == 0) { 1287 if (server_Close(arg->bundle)) 1288 log_Printf(LogPHASE, "Disabled server port.\n"); 1289 return 0; 1290 } else 1291 return -1; 1292 1293 strncpy(server.passwd, passwd, sizeof server.passwd - 1); 1294 server.passwd[sizeof server.passwd - 1] = '\0'; 1295 1296 if (*port == '/') { 1297 mode_t imask; 1298 char *ptr, name[LINE_LEN + 12]; 1299 1300 if (mask == NULL) 1301 imask = (mode_t)-1; 1302 else for (imask = mlen = 0; mask[mlen]; mlen++) 1303 imask = (imask * 8) + mask[mlen] - '0'; 1304 1305 ptr = strstr(port, "%d"); 1306 if (ptr) { 1307 snprintf(name, sizeof name, "%.*s%d%s", 1308 (int)(ptr - port), port, arg->bundle->unit, ptr + 2); 1309 port = name; 1310 } 1311 res = server_LocalOpen(arg->bundle, port, imask); 1312 } else { 1313 int iport, add = 0; 1314 1315 if (mask != NULL) 1316 return -1; 1317 1318 if (*port == '+') { 1319 port++; 1320 add = 1; 1321 } 1322 if (strspn(port, "0123456789") != strlen(port)) { 1323 struct servent *s; 1324 1325 if ((s = getservbyname(port, "tcp")) == NULL) { 1326 iport = 0; 1327 log_Printf(LogWARN, "%s: Invalid port or service\n", port); 1328 } else 1329 iport = ntohs(s->s_port); 1330 } else 1331 iport = atoi(port); 1332 1333 if (iport) { 1334 if (add) 1335 iport += arg->bundle->unit; 1336 res = server_TcpOpen(arg->bundle, iport); 1337 } else 1338 res = -1; 1339 } 1340 } 1341 1342 return res; 1343} 1344 1345static int 1346SetEscape(struct cmdargs const *arg) 1347{ 1348 int code; 1349 int argc = arg->argc - arg->argn; 1350 char const *const *argv = arg->argv + arg->argn; 1351 1352 for (code = 0; code < 33; code++) 1353 arg->cx->physical->async.cfg.EscMap[code] = 0; 1354 1355 while (argc-- > 0) { 1356 sscanf(*argv++, "%x", &code); 1357 code &= 0xff; 1358 arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7)); 1359 arg->cx->physical->async.cfg.EscMap[32] = 1; 1360 } 1361 return 0; 1362} 1363 1364static int 1365SetInterfaceAddr(struct cmdargs const *arg) 1366{ 1367 struct ipcp *ipcp = &arg->bundle->ncp.ipcp; 1368 const char *hisaddr; 1369 1370 if (arg->argc > arg->argn + 4) 1371 return -1; 1372 1373 hisaddr = NULL; 1374 memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range); 1375 memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); 1376 ipcp->cfg.HaveTriggerAddress = 0; 1377 ipcp->cfg.netmask.s_addr = INADDR_ANY; 1378 iplist_reset(&ipcp->cfg.peer_list); 1379 1380 if (arg->argc > arg->argn) { 1381 if (!ParseAddr(ipcp, arg->argv[arg->argn], 1382 &ipcp->cfg.my_range.ipaddr, &ipcp->cfg.my_range.mask, 1383 &ipcp->cfg.my_range.width)) 1384 return 1; 1385 if (arg->argc > arg->argn+1) { 1386 hisaddr = arg->argv[arg->argn+1]; 1387 if (arg->argc > arg->argn+2) { 1388 ipcp->ifmask = ipcp->cfg.netmask = GetIpAddr(arg->argv[arg->argn+2]); 1389 if (arg->argc > arg->argn+3) { 1390 ipcp->cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]); 1391 ipcp->cfg.HaveTriggerAddress = 1; 1392 } 1393 } 1394 } 1395 } 1396 1397 /* 0.0.0.0 means any address (0 bits) */ 1398 if (ipcp->cfg.my_range.ipaddr.s_addr == INADDR_ANY) { 1399 ipcp->cfg.my_range.mask.s_addr = INADDR_ANY; 1400 ipcp->cfg.my_range.width = 0; 1401 } 1402 ipcp->my_ip.s_addr = ipcp->cfg.my_range.ipaddr.s_addr; 1403 bundle_AdjustFilters(arg->bundle, &ipcp->my_ip, NULL); 1404 1405 if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr, 1406 arg->bundle->phys_type.all & PHYS_AUTO)) 1407 return 4; 1408 1409 return 0; 1410} 1411 1412static int 1413SetRetry(int argc, char const *const *argv, u_int *timeout, u_int *maxreq, 1414 u_int *maxtrm, int def) 1415{ 1416 if (argc == 0) { 1417 *timeout = DEF_FSMRETRY; 1418 *maxreq = def; 1419 if (maxtrm != NULL) 1420 *maxtrm = def; 1421 } else { 1422 long l = atol(argv[0]); 1423 1424 if (l < MIN_FSMRETRY) { 1425 log_Printf(LogWARN, "%ld: Invalid FSM retry period - min %d\n", 1426 l, MIN_FSMRETRY); 1427 return 1; 1428 } else 1429 *timeout = l; 1430 1431 if (argc > 1) { 1432 l = atol(argv[1]); 1433 if (l < 1) { 1434 log_Printf(LogWARN, "%ld: Invalid FSM REQ tries - changed to 1\n", l); 1435 l = 1; 1436 } 1437 *maxreq = l; 1438 1439 if (argc > 2 && maxtrm != NULL) { 1440 l = atol(argv[2]); 1441 if (l < 1) { 1442 log_Printf(LogWARN, "%ld: Invalid FSM TRM tries - changed to 1\n", l); 1443 l = 1; 1444 } 1445 *maxtrm = l; 1446 } 1447 } 1448 } 1449 1450 return 0; 1451} 1452 1453static int 1454SetVariable(struct cmdargs const *arg) 1455{ 1456 long long_val, param = (long)arg->cmd->args; 1457 int mode, dummyint, f, first; 1458 const char *argp; 1459 struct datalink *cx = arg->cx; /* LOCAL_CX uses this */ 1460 const char *err = NULL; 1461 struct link *l = command_ChooseLink(arg); /* LOCAL_CX_OPT uses this */ 1462 struct in_addr dummyaddr, *addr; 1463 1464 if (arg->argc > arg->argn) 1465 argp = arg->argv[arg->argn]; 1466 else 1467 argp = ""; 1468 1469 if ((arg->cmd->lauth & LOCAL_CX) && !cx) { 1470 log_Printf(LogWARN, "set %s: No context (use the `link' command)\n", 1471 arg->cmd->name); 1472 return 1; 1473 } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) { 1474 log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n", 1475 arg->cmd->name, cx->name); 1476 cx = NULL; 1477 } 1478 1479 switch (param) { 1480 case VAR_AUTHKEY: 1481 strncpy(arg->bundle->cfg.auth.key, argp, 1482 sizeof arg->bundle->cfg.auth.key - 1); 1483 arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0'; 1484 break; 1485 1486 case VAR_AUTHNAME: 1487 switch (bundle_Phase(arg->bundle)) { 1488 default: 1489 log_Printf(LogWARN, "Altering authname while at phase %s\n", 1490 bundle_PhaseName(arg->bundle)); 1491 /* drop through */ 1492 case PHASE_DEAD: 1493 case PHASE_ESTABLISH: 1494 strncpy(arg->bundle->cfg.auth.name, argp, 1495 sizeof arg->bundle->cfg.auth.name - 1); 1496 arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name-1] = '\0'; 1497 break; 1498 } 1499 break; 1500 1501 case VAR_AUTOLOAD: 1502 if (arg->argc == arg->argn + 3) { 1503 int v1, v2, v3; 1504 char *end; 1505 1506 v1 = strtol(arg->argv[arg->argn], &end, 0); 1507 if (v1 < 0 || *end) { 1508 log_Printf(LogWARN, "autoload: %s: Invalid min percentage\n", 1509 arg->argv[arg->argn]); 1510 return 1; 1511 } 1512 1513 v2 = strtol(arg->argv[arg->argn + 1], &end, 0); 1514 if (v2 < 0 || *end) { 1515 log_Printf(LogWARN, "autoload: %s: Invalid max percentage\n", 1516 arg->argv[arg->argn + 1]); 1517 return 1; 1518 } 1519 if (v2 < v1) { 1520 v3 = v1; 1521 v1 = v2; 1522 v2 = v3; 1523 } 1524 1525 v3 = strtol(arg->argv[arg->argn + 2], &end, 0); 1526 if (v3 <= 0 || *end) { 1527 log_Printf(LogWARN, "autoload: %s: Invalid throughput period\n", 1528 arg->argv[arg->argn + 2]); 1529 return 1; 1530 } 1531 1532 arg->bundle->ncp.mp.cfg.autoload.min = v1; 1533 arg->bundle->ncp.mp.cfg.autoload.max = v2; 1534 arg->bundle->ncp.mp.cfg.autoload.period = v3; 1535 mp_RestartAutoloadTimer(&arg->bundle->ncp.mp); 1536 } else { 1537 err = "Set autoload requires three arguments\n"; 1538 log_Printf(LogWARN, err); 1539 } 1540 break; 1541 1542 case VAR_DIAL: 1543 strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1); 1544 cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0'; 1545 break; 1546 1547 case VAR_LOGIN: 1548 strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1); 1549 cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0'; 1550 break; 1551 1552 case VAR_WINSIZE: 1553 if (arg->argc > arg->argn) { 1554 l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]); 1555 if (l->ccp.cfg.deflate.out.winsize < 8 || 1556 l->ccp.cfg.deflate.out.winsize > 15) { 1557 log_Printf(LogWARN, "%d: Invalid outgoing window size\n", 1558 l->ccp.cfg.deflate.out.winsize); 1559 l->ccp.cfg.deflate.out.winsize = 15; 1560 } 1561 if (arg->argc > arg->argn+1) { 1562 l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]); 1563 if (l->ccp.cfg.deflate.in.winsize < 8 || 1564 l->ccp.cfg.deflate.in.winsize > 15) { 1565 log_Printf(LogWARN, "%d: Invalid incoming window size\n", 1566 l->ccp.cfg.deflate.in.winsize); 1567 l->ccp.cfg.deflate.in.winsize = 15; 1568 } 1569 } else 1570 l->ccp.cfg.deflate.in.winsize = 0; 1571 } else { 1572 err = "No window size specified\n"; 1573 log_Printf(LogWARN, err); 1574 } 1575 break; 1576 1577 case VAR_DEVICE: 1578 physical_SetDeviceList(cx->physical, arg->argc - arg->argn, 1579 arg->argv + arg->argn); 1580 break; 1581 1582 case VAR_ACCMAP: 1583 if (arg->argc > arg->argn) { 1584 u_long ulong_val; 1585 sscanf(argp, "%lx", &ulong_val); 1586 cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val; 1587 } else { 1588 err = "No accmap specified\n"; 1589 log_Printf(LogWARN, err); 1590 } 1591 break; 1592 1593 case VAR_MODE: 1594 mode = Nam2mode(argp); 1595 if (mode == PHYS_NONE || mode == PHYS_ALL) { 1596 log_Printf(LogWARN, "%s: Invalid mode\n", argp); 1597 return -1; 1598 } 1599 bundle_SetMode(arg->bundle, cx, mode); 1600 break; 1601 1602 case VAR_MRRU: 1603 switch (bundle_Phase(arg->bundle)) { 1604 case PHASE_DEAD: 1605 break; 1606 case PHASE_ESTABLISH: 1607 /* Make sure none of our links are DATALINK_LCP or greater */ 1608 if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) { 1609 log_Printf(LogWARN, "mrru: Only changable before LCP negotiations\n"); 1610 return 1; 1611 } 1612 break; 1613 default: 1614 log_Printf(LogWARN, "mrru: Only changable at phase DEAD/ESTABLISH\n"); 1615 return 1; 1616 } 1617 long_val = atol(argp); 1618 if (long_val && long_val < MIN_MRU) { 1619 log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU); 1620 return 1; 1621 } else if (long_val > MAX_MRU) { 1622 log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU); 1623 return 1; 1624 } else 1625 arg->bundle->ncp.mp.cfg.mrru = long_val; 1626 break; 1627 1628 case VAR_MRU: 1629 long_val = atol(argp); 1630 if (long_val == 0) 1631 l->lcp.cfg.mru = DEF_MRU; 1632 else if (long_val < MIN_MRU) { 1633 log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU); 1634 return 1; 1635 } else if (long_val > MAX_MRU) { 1636 log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU); 1637 return 1; 1638 } else 1639 l->lcp.cfg.mru = long_val; 1640 break; 1641 1642 case VAR_MTU: 1643 long_val = atol(argp); 1644 if (long_val && long_val < MIN_MTU) { 1645 log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU); 1646 return 1; 1647 } else if (long_val > MAX_MTU) { 1648 log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU); 1649 return 1; 1650 } else 1651 arg->bundle->cfg.mtu = long_val; 1652 break; 1653 1654 case VAR_OPENMODE: 1655 if (strcasecmp(argp, "active") == 0) 1656 cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ? 1657 atoi(arg->argv[arg->argn+1]) : 1; 1658 else if (strcasecmp(argp, "passive") == 0) 1659 cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE; 1660 else { 1661 err = "%s: Invalid openmode\n"; 1662 log_Printf(LogWARN, err, argp); 1663 } 1664 break; 1665 1666 case VAR_PHONE: 1667 strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1); 1668 cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0'; 1669 cx->phone.alt = cx->phone.next = NULL; 1670 break; 1671 1672 case VAR_HANGUP: 1673 strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1); 1674 cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0'; 1675 break; 1676 1677 case VAR_IFQUEUE: 1678 long_val = atol(argp); 1679 arg->bundle->cfg.ifqueue = long_val < 0 ? 0 : long_val; 1680 break; 1681 1682 case VAR_LOGOUT: 1683 strncpy(cx->cfg.script.logout, argp, sizeof cx->cfg.script.logout - 1); 1684 cx->cfg.script.logout[sizeof cx->cfg.script.logout - 1] = '\0'; 1685 break; 1686 1687 case VAR_IDLETIMEOUT: 1688 if (arg->argc > arg->argn+2) 1689 err = "Too many idle timeout values\n"; 1690 else if (arg->argc == arg->argn) 1691 err = "Too few idle timeout values\n"; 1692 else { 1693 int timeout, min; 1694 1695 timeout = atoi(argp); 1696 min = arg->argc == arg->argn + 2 ? atoi(arg->argv[arg->argn + 1]) : -1; 1697 bundle_SetIdleTimer(arg->bundle, timeout, min); 1698 } 1699 if (err) 1700 log_Printf(LogWARN, err); 1701 break; 1702 1703 case VAR_LQRPERIOD: 1704 long_val = atol(argp); 1705 if (long_val < MIN_LQRPERIOD) { 1706 log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n", 1707 long_val, MIN_LQRPERIOD); 1708 return 1; 1709 } else 1710 l->lcp.cfg.lqrperiod = long_val; 1711 break; 1712 1713 case VAR_LCPRETRY: 1714 return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn, 1715 &cx->physical->link.lcp.cfg.fsm.timeout, 1716 &cx->physical->link.lcp.cfg.fsm.maxreq, 1717 &cx->physical->link.lcp.cfg.fsm.maxtrm, DEF_FSMTRIES); 1718 break; 1719 1720 case VAR_CHAPRETRY: 1721 return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn, 1722 &cx->chap.auth.cfg.fsm.timeout, 1723 &cx->chap.auth.cfg.fsm.maxreq, NULL, DEF_FSMAUTHTRIES); 1724 break; 1725 1726 case VAR_PAPRETRY: 1727 return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn, 1728 &cx->pap.cfg.fsm.timeout, &cx->pap.cfg.fsm.maxreq, 1729 NULL, DEF_FSMAUTHTRIES); 1730 break; 1731 1732 case VAR_CCPRETRY: 1733 return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn, 1734 &l->ccp.cfg.fsm.timeout, &l->ccp.cfg.fsm.maxreq, 1735 &l->ccp.cfg.fsm.maxtrm, DEF_FSMTRIES); 1736 break; 1737 1738 case VAR_IPCPRETRY: 1739 return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn, 1740 &arg->bundle->ncp.ipcp.cfg.fsm.timeout, 1741 &arg->bundle->ncp.ipcp.cfg.fsm.maxreq, 1742 &arg->bundle->ncp.ipcp.cfg.fsm.maxtrm, DEF_FSMTRIES); 1743 break; 1744 1745 case VAR_NBNS: 1746 case VAR_DNS: 1747 if (param == VAR_DNS) { 1748 addr = arg->bundle->ncp.ipcp.cfg.ns.dns; 1749 addr[0].s_addr = addr[1].s_addr = INADDR_NONE; 1750 } else { 1751 addr = arg->bundle->ncp.ipcp.cfg.ns.nbns; 1752 addr[0].s_addr = addr[1].s_addr = INADDR_ANY; 1753 } 1754 1755 if (arg->argc > arg->argn) { 1756 ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn], 1757 addr, &dummyaddr, &dummyint); 1758 if (arg->argc > arg->argn+1) 1759 ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn + 1], 1760 addr + 1, &dummyaddr, &dummyint); 1761 1762 if (addr[0].s_addr == INADDR_ANY) { 1763 addr[0].s_addr = addr[1].s_addr; 1764 addr[1].s_addr = INADDR_ANY; 1765 } 1766 if (addr[0].s_addr == INADDR_NONE) { 1767 addr[0].s_addr = addr[1].s_addr; 1768 addr[1].s_addr = INADDR_NONE; 1769 } 1770 } 1771 break; 1772 1773 case VAR_CALLBACK: 1774 cx->cfg.callback.opmask = 0; 1775 for (dummyint = arg->argn; dummyint < arg->argc; dummyint++) { 1776 if (!strcasecmp(arg->argv[dummyint], "auth")) 1777 cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_AUTH); 1778 else if (!strcasecmp(arg->argv[dummyint], "cbcp")) 1779 cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_CBCP); 1780 else if (!strcasecmp(arg->argv[dummyint], "e.164")) { 1781 if (dummyint == arg->argc - 1) 1782 log_Printf(LogWARN, "No E.164 arg (E.164 ignored) !\n"); 1783 else { 1784 cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_E164); 1785 strncpy(cx->cfg.callback.msg, arg->argv[++dummyint], 1786 sizeof cx->cfg.callback.msg - 1); 1787 cx->cfg.callback.msg[sizeof cx->cfg.callback.msg - 1] = '\0'; 1788 } 1789 } else if (!strcasecmp(arg->argv[dummyint], "none")) 1790 cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_NONE); 1791 else 1792 return -1; 1793 } 1794 if (cx->cfg.callback.opmask == CALLBACK_BIT(CALLBACK_NONE)) 1795 cx->cfg.callback.opmask = 0; 1796 break; 1797 1798 case VAR_CBCP: 1799 cx->cfg.cbcp.delay = 0; 1800 *cx->cfg.cbcp.phone = '\0'; 1801 cx->cfg.cbcp.fsmretry = DEF_FSMRETRY; 1802 if (arg->argc > arg->argn) { 1803 strncpy(cx->cfg.cbcp.phone, arg->argv[arg->argn], 1804 sizeof cx->cfg.cbcp.phone - 1); 1805 cx->cfg.cbcp.phone[sizeof cx->cfg.cbcp.phone - 1] = '\0'; 1806 if (arg->argc > arg->argn + 1) { 1807 cx->cfg.cbcp.delay = atoi(arg->argv[arg->argn + 1]); 1808 if (arg->argc > arg->argn + 2) { 1809 long_val = atol(arg->argv[arg->argn + 2]); 1810 if (long_val < MIN_FSMRETRY) 1811 log_Printf(LogWARN, "%ld: Invalid CBCP FSM retry period - min %d\n", 1812 long_val, MIN_FSMRETRY); 1813 else 1814 cx->cfg.cbcp.fsmretry = long_val; 1815 } 1816 } 1817 } 1818 break; 1819 1820 case VAR_CHOKED: 1821 arg->bundle->cfg.choked.timeout = atoi(argp); 1822 if (arg->bundle->cfg.choked.timeout <= 0) 1823 arg->bundle->cfg.choked.timeout = CHOKED_TIMEOUT; 1824 break; 1825 1826 case VAR_SENDPIPE: 1827 long_val = atol(argp); 1828 arg->bundle->ncp.ipcp.cfg.sendpipe = long_val; 1829 break; 1830 1831 case VAR_RECVPIPE: 1832 long_val = atol(argp); 1833 arg->bundle->ncp.ipcp.cfg.recvpipe = long_val; 1834 break; 1835 1836#ifndef NORADIUS 1837 case VAR_RADIUS: 1838 if (!*argp) 1839 *arg->bundle->radius.cfg.file = '\0'; 1840 else if (access(argp, R_OK)) { 1841 log_Printf(LogWARN, "%s: %s\n", argp, strerror(errno)); 1842 return 1; 1843 } else { 1844 strncpy(arg->bundle->radius.cfg.file, argp, 1845 sizeof arg->bundle->radius.cfg.file - 1); 1846 arg->bundle->radius.cfg.file 1847 [sizeof arg->bundle->radius.cfg.file - 1] = '\0'; 1848 } 1849 break; 1850#endif 1851 1852 case VAR_CD: 1853 if (*argp) { 1854 if (strcasecmp(argp, "off")) { 1855 long_val = atol(argp); 1856 if (long_val < 0) 1857 long_val = 0; 1858 cx->physical->cfg.cd.delay = long_val; 1859 cx->physical->cfg.cd.necessity = argp[strlen(argp)-1] == '!' ? 1860 CD_REQUIRED : CD_VARIABLE; 1861 } else 1862 cx->physical->cfg.cd.necessity = CD_NOTREQUIRED; 1863 } else { 1864 cx->physical->cfg.cd.delay = 0; 1865 cx->physical->cfg.cd.necessity = CD_DEFAULT; 1866 } 1867 break; 1868 1869 case VAR_PARITY: 1870 if (arg->argc == arg->argn + 1) 1871 return physical_SetParity(arg->cx->physical, argp); 1872 else { 1873 err = "Parity value must be odd, even or none\n"; 1874 log_Printf(LogWARN, err); 1875 } 1876 break; 1877 1878 case VAR_CRTSCTS: 1879 if (strcasecmp(argp, "on") == 0) 1880 physical_SetRtsCts(arg->cx->physical, 1); 1881 else if (strcasecmp(argp, "off") == 0) 1882 physical_SetRtsCts(arg->cx->physical, 0); 1883 else { 1884 err = "RTS/CTS value must be on or off\n"; 1885 log_Printf(LogWARN, err); 1886 } 1887 break; 1888 1889 case VAR_URGENTPORTS: 1890 if (arg->argn == arg->argc) { 1891 ipcp_SetUrgentTOS(&arg->bundle->ncp.ipcp); 1892 ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp); 1893 ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp); 1894 } else if (!strcasecmp(arg->argv[arg->argn], "udp")) { 1895 ipcp_SetUrgentTOS(&arg->bundle->ncp.ipcp); 1896 if (arg->argn == arg->argc - 1) 1897 ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp); 1898 else for (f = arg->argn + 1; f < arg->argc; f++) 1899 if (*arg->argv[f] == '+') 1900 ipcp_AddUrgentUdpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f] + 1)); 1901 else if (*arg->argv[f] == '-') 1902 ipcp_RemoveUrgentUdpPort(&arg->bundle->ncp.ipcp, 1903 atoi(arg->argv[f] + 1)); 1904 else { 1905 if (f == arg->argn) 1906 ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp); 1907 ipcp_AddUrgentUdpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f])); 1908 } 1909 } else if (arg->argn == arg->argc - 1 && 1910 !strcasecmp(arg->argv[arg->argn], "none")) { 1911 ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp); 1912 ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp); 1913 ipcp_ClearUrgentTOS(&arg->bundle->ncp.ipcp); 1914 } else { 1915 ipcp_SetUrgentTOS(&arg->bundle->ncp.ipcp); 1916 first = arg->argn; 1917 if (!strcasecmp(arg->argv[first], "tcp") && ++first == arg->argc) 1918 ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp); 1919 1920 for (f = first; f < arg->argc; f++) 1921 if (*arg->argv[f] == '+') 1922 ipcp_AddUrgentTcpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f] + 1)); 1923 else if (*arg->argv[f] == '-') 1924 ipcp_RemoveUrgentTcpPort(&arg->bundle->ncp.ipcp, 1925 atoi(arg->argv[f] + 1)); 1926 else { 1927 if (f == first) 1928 ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp); 1929 ipcp_AddUrgentTcpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f])); 1930 } 1931 } 1932 break; 1933 } 1934 1935 return err ? 1 : 0; 1936} 1937 1938static struct cmdtab const SetCommands[] = { 1939 {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 1940 "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP}, 1941 {"authkey", "key", SetVariable, LOCAL_AUTH, 1942 "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY}, 1943 {"authname", NULL, SetVariable, LOCAL_AUTH, 1944 "authentication name", "set authname name", (const void *)VAR_AUTHNAME}, 1945 {"autoload", NULL, SetVariable, LOCAL_AUTH, 1946 "auto link [de]activation", "set autoload maxtime maxload mintime minload", 1947 (const void *)VAR_AUTOLOAD}, 1948 {"bandwidth", NULL, mp_SetDatalinkBandwidth, LOCAL_AUTH | LOCAL_CX, 1949 "datalink bandwidth", "set bandwidth value"}, 1950 {"callback", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 1951 "callback control", "set callback [none|auth|cbcp|" 1952 "E.164 *|number[,number]...]...", (const void *)VAR_CALLBACK}, 1953 {"cbcp", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 1954 "CBCP control", "set cbcp [*|phone[,phone...] [delay [timeout]]]", 1955 (const void *)VAR_CBCP}, 1956 {"ccpretry", "ccpretries", SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, 1957 "CCP retries", "set ccpretry value [attempts]", (const void *)VAR_CCPRETRY}, 1958 {"cd", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "Carrier delay requirement", 1959 "set cd value[!]", (const void *)VAR_CD}, 1960 {"chapretry", "chapretries", SetVariable, LOCAL_AUTH | LOCAL_CX, 1961 "CHAP retries", "set chapretry value [attempts]", 1962 (const void *)VAR_CHAPRETRY}, 1963 {"choked", NULL, SetVariable, LOCAL_AUTH, 1964 "choked timeout", "set choked [secs]", (const void *)VAR_CHOKED}, 1965 {"ctsrts", "crtscts", SetVariable, LOCAL_AUTH | LOCAL_CX, 1966 "Use hardware flow control", "set ctsrts [on|off]", 1967 (const char *)VAR_CRTSCTS}, 1968 {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, 1969 "deflate window sizes", "set deflate out-winsize in-winsize", 1970 (const void *) VAR_WINSIZE}, 1971 {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX, 1972 "physical device name", "set device|line device-name[,device-name]", 1973 (const void *) VAR_DEVICE}, 1974 {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 1975 "dialing script", "set dial chat-script", (const void *) VAR_DIAL}, 1976 {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server", 1977 "set dns pri-addr [sec-addr]", (const void *)VAR_DNS}, 1978 {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH, 1979 "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]"}, 1980 {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX, 1981 "escape characters", "set escape hex-digit ..."}, 1982 {"filter", NULL, filter_Set, LOCAL_AUTH, 1983 "packet filters", "set filter alive|dial|in|out rule-no permit|deny " 1984 "[src_addr[/width]] [dst_addr[/width]] [tcp|udp|icmp|ospf|igmp " 1985 "[src [lt|eq|gt port]] [dst [lt|eq|gt port]] [estab] [syn] [finrst]]"}, 1986 {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 1987 "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP}, 1988 {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address", 1989 "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"}, 1990 {"ifqueue", NULL, SetVariable, LOCAL_AUTH, "interface queue", 1991 "set ifqueue packets", (const void *)VAR_IFQUEUE}, 1992 {"ipcpretry", "ipcpretries", SetVariable, LOCAL_AUTH, "IPCP retries", 1993 "set ipcpretry value [attempts]", (const void *)VAR_IPCPRETRY}, 1994 {"lcpretry", "lcpretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "LCP retries", 1995 "set lcpretry value [attempts]", (const void *)VAR_LCPRETRY}, 1996 {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level", 1997 "set log [local] [+|-]async|cbcp|ccp|chat|command|connect|debug|dns|hdlc|" 1998 "id0|ipcp|lcp|lqm|phase|physical|sync|tcp/ip|timer|tun..."}, 1999 {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 2000 "login script", "set login chat-script", (const void *) VAR_LOGIN}, 2001 {"logout", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 2002 "logout script", "set logout chat-script", (const void *) VAR_LOGOUT}, 2003 {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, 2004 "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD}, 2005 {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value", 2006 "set mode interactive|auto|ddial|background", (const void *)VAR_MODE}, 2007 {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value", 2008 "set mrru value", (const void *)VAR_MRRU}, 2009 {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, 2010 "MRU value", "set mru value", (const void *)VAR_MRU}, 2011 {"mtu", NULL, SetVariable, LOCAL_AUTH, 2012 "interface MTU value", "set mtu value", (const void *)VAR_MTU}, 2013 {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server", 2014 "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS}, 2015 {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode", 2016 "set openmode active|passive [secs]", (const void *)VAR_OPENMODE}, 2017 {"papretry", "papretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "PAP retries", 2018 "set papretry value [attempts]", (const void *)VAR_PAPRETRY}, 2019 {"parity", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "serial parity", 2020 "set parity [odd|even|none]", (const void *)VAR_PARITY}, 2021 {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)", 2022 "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE}, 2023 {"proctitle", "title", SetProcTitle, LOCAL_AUTH, 2024 "Process title", "set proctitle [value]"}, 2025#ifndef NORADIUS 2026 {"radius", NULL, SetVariable, LOCAL_AUTH, 2027 "RADIUS Config", "set radius cfgfile", (const void *)VAR_RADIUS}, 2028#endif 2029 {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX, 2030 "Reconnect timeout", "set reconnect value ntries"}, 2031 {"recvpipe", NULL, SetVariable, LOCAL_AUTH, 2032 "RECVPIPE value", "set recvpipe value", (const void *)VAR_RECVPIPE}, 2033 {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX, 2034 "Redial timeout", "set redial secs[+inc[-incmax]][.next] [attempts]"}, 2035 {"sendpipe", NULL, SetVariable, LOCAL_AUTH, 2036 "SENDPIPE value", "set sendpipe value", (const void *)VAR_SENDPIPE}, 2037 {"server", "socket", SetServer, LOCAL_AUTH, 2038 "server port", "set server|socket TcpPort|LocalName|none password [mask]"}, 2039 {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX, 2040 "physical speed", "set speed value|sync"}, 2041 {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX, 2042 "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"}, 2043 {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout", 2044 "set timeout idletime", (const void *)VAR_IDLETIMEOUT}, 2045 {"urgent", NULL, SetVariable, LOCAL_AUTH, "urgent ports", 2046 "set urgent [tcp|udp] [+|-]port...", (const void *)VAR_URGENTPORTS}, 2047 {"vj", NULL, ipcp_vjset, LOCAL_AUTH, 2048 "vj values", "set vj slots|slotcomp [value]"}, 2049 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 2050 "Display this message", "set help|? [command]", SetCommands}, 2051 {NULL, NULL, NULL}, 2052}; 2053 2054static int 2055SetCommand(struct cmdargs const *arg) 2056{ 2057 if (arg->argc > arg->argn) 2058 FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv, 2059 arg->prompt, arg->cx); 2060 else if (arg->prompt) 2061 prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for" 2062 " syntax help.\n"); 2063 else 2064 log_Printf(LogWARN, "set command must have arguments\n"); 2065 2066 return 0; 2067} 2068 2069static int 2070AddCommand(struct cmdargs const *arg) 2071{ 2072 struct in_addr dest, gateway, netmask; 2073 int gw, addrs; 2074 2075 if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2) 2076 return -1; 2077 2078 addrs = 0; 2079 if (arg->argc == arg->argn+2) { 2080 if (!strcasecmp(arg->argv[arg->argn], "default")) 2081 dest.s_addr = netmask.s_addr = INADDR_ANY; 2082 else { 2083 int width; 2084 2085 if (!ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn], 2086 &dest, &netmask, &width)) 2087 return -1; 2088 if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6)) 2089 addrs = ROUTE_DSTMYADDR; 2090 else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7)) 2091 addrs = ROUTE_DSTHISADDR; 2092 else if (!strncasecmp(arg->argv[arg->argn], "DNS0", 4)) 2093 addrs = ROUTE_DSTDNS0; 2094 else if (!strncasecmp(arg->argv[arg->argn], "DNS1", 4)) 2095 addrs = ROUTE_DSTDNS1; 2096 } 2097 gw = 1; 2098 } else { 2099 if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) { 2100 addrs = ROUTE_DSTMYADDR; 2101 dest = arg->bundle->ncp.ipcp.my_ip; 2102 } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) { 2103 addrs = ROUTE_DSTHISADDR; 2104 dest = arg->bundle->ncp.ipcp.peer_ip; 2105 } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) { 2106 addrs = ROUTE_DSTDNS0; 2107 dest = arg->bundle->ncp.ipcp.ns.dns[0]; 2108 } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) { 2109 addrs = ROUTE_DSTDNS1; 2110 dest = arg->bundle->ncp.ipcp.ns.dns[1]; 2111 } else { 2112 dest = GetIpAddr(arg->argv[arg->argn]); 2113 if (dest.s_addr == INADDR_NONE) { 2114 log_Printf(LogWARN, "%s: Invalid destination address\n", 2115 arg->argv[arg->argn]); 2116 return -1; 2117 } 2118 } 2119 netmask = GetIpAddr(arg->argv[arg->argn+1]); 2120 gw = 2; 2121 } 2122 2123 if (strcasecmp(arg->argv[arg->argn+gw], "HISADDR") == 0) { 2124 gateway = arg->bundle->ncp.ipcp.peer_ip; 2125 addrs |= ROUTE_GWHISADDR; 2126 } else { 2127 gateway = GetIpAddr(arg->argv[arg->argn+gw]); 2128 if (gateway.s_addr == INADDR_NONE) { 2129 log_Printf(LogWARN, "%s: Invalid gateway address\n", 2130 arg->argv[arg->argn + gw]); 2131 return -1; 2132 } 2133 } 2134 2135 if (bundle_SetRoute(arg->bundle, RTM_ADD, dest, gateway, netmask, 2136 arg->cmd->args ? 1 : 0, (addrs & ROUTE_GWHISADDR) ? 1 : 0) 2137 && addrs != ROUTE_STATIC) 2138 route_Add(&arg->bundle->ncp.ipcp.route, addrs, dest, netmask, gateway); 2139 2140 return 0; 2141} 2142 2143static int 2144DeleteCommand(struct cmdargs const *arg) 2145{ 2146 struct in_addr dest, none; 2147 int addrs; 2148 2149 if (arg->argc == arg->argn+1) { 2150 if(strcasecmp(arg->argv[arg->argn], "all") == 0) { 2151 route_IfDelete(arg->bundle, 0); 2152 route_DeleteAll(&arg->bundle->ncp.ipcp.route); 2153 } else { 2154 addrs = 0; 2155 if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) { 2156 dest = arg->bundle->ncp.ipcp.my_ip; 2157 addrs = ROUTE_DSTMYADDR; 2158 } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) { 2159 dest = arg->bundle->ncp.ipcp.peer_ip; 2160 addrs = ROUTE_DSTHISADDR; 2161 } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) { 2162 dest = arg->bundle->ncp.ipcp.ns.dns[0]; 2163 addrs = ROUTE_DSTDNS0; 2164 } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) { 2165 dest = arg->bundle->ncp.ipcp.ns.dns[1]; 2166 addrs = ROUTE_DSTDNS1; 2167 } else { 2168 dest = GetIpAddr(arg->argv[arg->argn]); 2169 if (dest.s_addr == INADDR_NONE) { 2170 log_Printf(LogWARN, "%s: Invalid IP address\n", arg->argv[arg->argn]); 2171 return -1; 2172 } 2173 addrs = ROUTE_STATIC; 2174 } 2175 none.s_addr = INADDR_ANY; 2176 bundle_SetRoute(arg->bundle, RTM_DELETE, dest, none, none, 2177 arg->cmd->args ? 1 : 0, 0); 2178 route_Delete(&arg->bundle->ncp.ipcp.route, addrs, dest); 2179 } 2180 } else 2181 return -1; 2182 2183 return 0; 2184} 2185 2186#ifndef NONAT 2187static int 2188NatEnable(struct cmdargs const *arg) 2189{ 2190 if (arg->argc == arg->argn+1) { 2191 if (strcasecmp(arg->argv[arg->argn], "yes") == 0) { 2192 if (!arg->bundle->NatEnabled) { 2193 if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED) 2194 PacketAliasSetAddress(arg->bundle->ncp.ipcp.my_ip); 2195 arg->bundle->NatEnabled = 1; 2196 } 2197 return 0; 2198 } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) { 2199 arg->bundle->NatEnabled = 0; 2200 arg->bundle->cfg.opt &= ~OPT_IFACEALIAS; 2201 /* Don't iface_Clear() - there may be manually configured addresses */ 2202 return 0; 2203 } 2204 } 2205 2206 return -1; 2207} 2208 2209 2210static int 2211NatOption(struct cmdargs const *arg) 2212{ 2213 long param = (long)arg->cmd->args; 2214 2215 if (arg->argc == arg->argn+1) { 2216 if (strcasecmp(arg->argv[arg->argn], "yes") == 0) { 2217 if (arg->bundle->NatEnabled) { 2218 PacketAliasSetMode(param, param); 2219 return 0; 2220 } 2221 log_Printf(LogWARN, "nat not enabled\n"); 2222 } else if (strcmp(arg->argv[arg->argn], "no") == 0) { 2223 if (arg->bundle->NatEnabled) { 2224 PacketAliasSetMode(0, param); 2225 return 0; 2226 } 2227 log_Printf(LogWARN, "nat not enabled\n"); 2228 } 2229 } 2230 return -1; 2231} 2232#endif /* #ifndef NONAT */ 2233 2234static int 2235LinkCommand(struct cmdargs const *arg) 2236{ 2237 if (arg->argc > arg->argn+1) { 2238 char namelist[LINE_LEN]; 2239 struct datalink *cx; 2240 char *name; 2241 int result = 0; 2242 2243 if (!strcmp(arg->argv[arg->argn], "*")) { 2244 struct datalink *dl; 2245 2246 cx = arg->bundle->links; 2247 while (cx) { 2248 /* Watch it, the command could be a ``remove'' */ 2249 dl = cx->next; 2250 FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv, 2251 arg->prompt, cx); 2252 for (cx = arg->bundle->links; cx; cx = cx->next) 2253 if (cx == dl) 2254 break; /* Pointer's still valid ! */ 2255 } 2256 } else { 2257 strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1); 2258 namelist[sizeof namelist - 1] = '\0'; 2259 for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) 2260 if (!bundle2datalink(arg->bundle, name)) { 2261 log_Printf(LogWARN, "link: %s: Invalid link name\n", name); 2262 return 1; 2263 } 2264 2265 strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1); 2266 namelist[sizeof namelist - 1] = '\0'; 2267 for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) { 2268 cx = bundle2datalink(arg->bundle, name); 2269 if (cx) 2270 FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv, 2271 arg->prompt, cx); 2272 else { 2273 log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name); 2274 result++; 2275 } 2276 } 2277 } 2278 return result; 2279 } 2280 2281 log_Printf(LogWARN, "Usage: %s\n", arg->cmd->syntax); 2282 return 2; 2283} 2284 2285struct link * 2286command_ChooseLink(struct cmdargs const *arg) 2287{ 2288 if (arg->cx) 2289 return &arg->cx->physical->link; 2290 else if (!arg->bundle->ncp.mp.cfg.mrru) { 2291 struct datalink *dl = bundle2datalink(arg->bundle, NULL); 2292 if (dl) 2293 return &dl->physical->link; 2294 } 2295 return &arg->bundle->ncp.mp.link; 2296} 2297 2298static const char * 2299ident_cmd(const char *cmd, unsigned *keep, unsigned *add) 2300{ 2301 const char *result; 2302 2303 switch (*cmd) { 2304 case 'A': 2305 case 'a': 2306 result = "accept"; 2307 *keep = NEG_MYMASK; 2308 *add = NEG_ACCEPTED; 2309 break; 2310 case 'D': 2311 case 'd': 2312 switch (cmd[1]) { 2313 case 'E': 2314 case 'e': 2315 result = "deny"; 2316 *keep = NEG_MYMASK; 2317 *add = 0; 2318 break; 2319 case 'I': 2320 case 'i': 2321 result = "disable"; 2322 *keep = NEG_HISMASK; 2323 *add = 0; 2324 break; 2325 default: 2326 return NULL; 2327 } 2328 break; 2329 case 'E': 2330 case 'e': 2331 result = "enable"; 2332 *keep = NEG_HISMASK; 2333 *add = NEG_ENABLED; 2334 break; 2335 default: 2336 return NULL; 2337 } 2338 2339 return result; 2340} 2341 2342static int 2343OptSet(struct cmdargs const *arg) 2344{ 2345 int bit = (int)(long)arg->cmd->args; 2346 const char *cmd; 2347 unsigned keep; /* Keep these bits */ 2348 unsigned add; /* Add these bits */ 2349 2350 if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL) 2351 return 1; 2352 2353 if (add) 2354 arg->bundle->cfg.opt |= bit; 2355 else 2356 arg->bundle->cfg.opt &= ~bit; 2357 return 0; 2358} 2359 2360static int 2361IfaceAliasOptSet(struct cmdargs const *arg) 2362{ 2363 unsigned save = arg->bundle->cfg.opt; 2364 int result = OptSet(arg); 2365 2366 if (result == 0) 2367 if (Enabled(arg->bundle, OPT_IFACEALIAS) && !arg->bundle->NatEnabled) { 2368 arg->bundle->cfg.opt = save; 2369 log_Printf(LogWARN, "Cannot enable iface-alias without NAT\n"); 2370 result = 2; 2371 } 2372 2373 return result; 2374} 2375 2376static int 2377NegotiateSet(struct cmdargs const *arg) 2378{ 2379 long param = (long)arg->cmd->args; 2380 struct link *l = command_ChooseLink(arg); /* LOCAL_CX_OPT uses this */ 2381 struct datalink *cx = arg->cx; /* LOCAL_CX uses this */ 2382 const char *cmd; 2383 unsigned keep; /* Keep these bits */ 2384 unsigned add; /* Add these bits */ 2385 2386 if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL) 2387 return 1; 2388 2389 if ((arg->cmd->lauth & LOCAL_CX) && !cx) { 2390 log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n", 2391 cmd, arg->cmd->name); 2392 return 2; 2393 } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) { 2394 log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n", 2395 cmd, arg->cmd->name, cx->name); 2396 cx = NULL; 2397 } 2398 2399 switch (param) { 2400 case NEG_ACFCOMP: 2401 cx->physical->link.lcp.cfg.acfcomp &= keep; 2402 cx->physical->link.lcp.cfg.acfcomp |= add; 2403 break; 2404 case NEG_CHAP05: 2405 cx->physical->link.lcp.cfg.chap05 &= keep; 2406 cx->physical->link.lcp.cfg.chap05 |= add; 2407 break; 2408#ifdef HAVE_DES 2409 case NEG_CHAP80: 2410 cx->physical->link.lcp.cfg.chap80nt &= keep; 2411 cx->physical->link.lcp.cfg.chap80nt |= add; 2412 break; 2413 case NEG_CHAP80LM: 2414 cx->physical->link.lcp.cfg.chap80lm &= keep; 2415 cx->physical->link.lcp.cfg.chap80lm |= add; 2416 break; 2417#endif 2418 case NEG_DEFLATE: 2419 l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep; 2420 l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add; 2421 break; 2422 case NEG_DNS: 2423 arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep; 2424 arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add; 2425 break; 2426 case NEG_ENDDISC: 2427 arg->bundle->ncp.mp.cfg.negenddisc &= keep; 2428 arg->bundle->ncp.mp.cfg.negenddisc |= add; 2429 break; 2430 case NEG_LQR: 2431 cx->physical->link.lcp.cfg.lqr &= keep; 2432 cx->physical->link.lcp.cfg.lqr |= add; 2433 break; 2434 case NEG_PAP: 2435 cx->physical->link.lcp.cfg.pap &= keep; 2436 cx->physical->link.lcp.cfg.pap |= add; 2437 break; 2438 case NEG_PPPDDEFLATE: 2439 l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep; 2440 l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add; 2441 break; 2442 case NEG_PRED1: 2443 l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep; 2444 l->ccp.cfg.neg[CCP_NEG_PRED1] |= add; 2445 break; 2446 case NEG_PROTOCOMP: 2447 cx->physical->link.lcp.cfg.protocomp &= keep; 2448 cx->physical->link.lcp.cfg.protocomp |= add; 2449 break; 2450 case NEG_SHORTSEQ: 2451 switch (bundle_Phase(arg->bundle)) { 2452 case PHASE_DEAD: 2453 break; 2454 case PHASE_ESTABLISH: 2455 /* Make sure none of our links are DATALINK_LCP or greater */ 2456 if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) { 2457 log_Printf(LogWARN, "shortseq: Only changable before" 2458 " LCP negotiations\n"); 2459 return 1; 2460 } 2461 break; 2462 default: 2463 log_Printf(LogWARN, "shortseq: Only changable at phase" 2464 " DEAD/ESTABLISH\n"); 2465 return 1; 2466 } 2467 arg->bundle->ncp.mp.cfg.shortseq &= keep; 2468 arg->bundle->ncp.mp.cfg.shortseq |= add; 2469 break; 2470 case NEG_VJCOMP: 2471 arg->bundle->ncp.ipcp.cfg.vj.neg &= keep; 2472 arg->bundle->ncp.ipcp.cfg.vj.neg |= add; 2473 break; 2474 } 2475 2476 return 0; 2477} 2478 2479static struct cmdtab const NegotiateCommands[] = { 2480 {"filter-decapsulation", NULL, OptSet, LOCAL_AUTH, 2481 "filter on PPPoUDP payloads", "disable|enable", 2482 (const void *)OPT_FILTERDECAP}, 2483 {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids", 2484 "disable|enable", (const void *)OPT_IDCHECK}, 2485 {"iface-alias", NULL, IfaceAliasOptSet, LOCAL_AUTH, 2486 "retain interface addresses", "disable|enable", 2487 (const void *)OPT_IFACEALIAS}, 2488 {"keep-session", NULL, OptSet, LOCAL_AUTH, "Retain device session leader", 2489 "disable|enable", (const void *)OPT_KEEPSESSION}, 2490 {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface", 2491 "disable|enable", (const void *)OPT_LOOPBACK}, 2492 {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file", 2493 "disable|enable", (const void *)OPT_PASSWDAUTH}, 2494 {"proxy", NULL, OptSet, LOCAL_AUTH, "Create a proxy ARP entry", 2495 "disable|enable", (const void *)OPT_PROXY}, 2496 {"proxyall", NULL, OptSet, LOCAL_AUTH, "Proxy ARP for all remote hosts", 2497 "disable|enable", (const void *)OPT_PROXYALL}, 2498 {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes", 2499 "disable|enable", (const void *)OPT_SROUTES}, 2500 {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput", 2501 "disable|enable", (const void *)OPT_THROUGHPUT}, 2502 {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp", 2503 "disable|enable", (const void *)OPT_UTMP}, 2504 2505#define OPT_MAX 10 /* accept/deny allowed below and not above */ 2506 2507 {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2508 "Address & Control field compression", "accept|deny|disable|enable", 2509 (const void *)NEG_ACFCOMP}, 2510 {"chap", "chap05", NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2511 "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable", 2512 (const void *)NEG_CHAP05}, 2513#ifdef HAVE_DES 2514 {"mschap", "chap80nt", NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2515 "Microsoft (NT) CHAP", "accept|deny|disable|enable", 2516 (const void *)NEG_CHAP80}, 2517 {"LANMan", "chap80lm", NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2518 "Microsoft (NT) CHAP", "accept|deny|disable|enable", 2519 (const void *)NEG_CHAP80LM}, 2520#endif 2521 {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT, 2522 "Deflate compression", "accept|deny|disable|enable", 2523 (const void *)NEG_DEFLATE}, 2524 {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT, 2525 "Deflate (type 24) compression", "accept|deny|disable|enable", 2526 (const void *)NEG_PPPDDEFLATE}, 2527 {"dns", NULL, NegotiateSet, LOCAL_AUTH, 2528 "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS}, 2529 {"enddisc", NULL, NegotiateSet, LOCAL_AUTH, "ENDDISC negotiation", 2530 "accept|deny|disable|enable", (const void *)NEG_ENDDISC}, 2531 {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2532 "Link Quality Reports", "accept|deny|disable|enable", 2533 (const void *)NEG_LQR}, 2534 {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2535 "Password Authentication protocol", "accept|deny|disable|enable", 2536 (const void *)NEG_PAP}, 2537 {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT, 2538 "Predictor 1 compression", "accept|deny|disable|enable", 2539 (const void *)NEG_PRED1}, 2540 {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2541 "Protocol field compression", "accept|deny|disable|enable", 2542 (const void *)NEG_PROTOCOMP}, 2543 {"shortseq", NULL, NegotiateSet, LOCAL_AUTH, 2544 "MP Short Sequence Numbers", "accept|deny|disable|enable", 2545 (const void *)NEG_SHORTSEQ}, 2546 {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH, 2547 "Van Jacobson header compression", "accept|deny|disable|enable", 2548 (const void *)NEG_VJCOMP}, 2549 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 2550 "Display this message", "accept|deny|disable|enable help|? [value]", 2551 NegotiateCommands}, 2552 {NULL, NULL, NULL}, 2553}; 2554 2555static int 2556NegotiateCommand(struct cmdargs const *arg) 2557{ 2558 if (arg->argc > arg->argn) { 2559 char const *argv[3]; 2560 unsigned keep, add; 2561 int n; 2562 2563 if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL) 2564 return -1; 2565 argv[2] = NULL; 2566 2567 for (n = arg->argn; n < arg->argc; n++) { 2568 argv[1] = arg->argv[n]; 2569 FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ? 2570 0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx); 2571 } 2572 } else if (arg->prompt) 2573 prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n", 2574 arg->argv[arg->argn-1]); 2575 else 2576 log_Printf(LogWARN, "%s command must have arguments\n", 2577 arg->argv[arg->argn] ); 2578 2579 return 0; 2580} 2581 2582const char * 2583command_ShowNegval(unsigned val) 2584{ 2585 switch (val&3) { 2586 case 1: return "disabled & accepted"; 2587 case 2: return "enabled & denied"; 2588 case 3: return "enabled & accepted"; 2589 } 2590 return "disabled & denied"; 2591} 2592 2593static int 2594ClearCommand(struct cmdargs const *arg) 2595{ 2596 struct pppThroughput *t; 2597 struct datalink *cx; 2598 int i, clear_type; 2599 2600 if (arg->argc < arg->argn + 1) 2601 return -1; 2602 2603 if (strcasecmp(arg->argv[arg->argn], "physical") == 0) { 2604 cx = arg->cx; 2605 if (!cx) 2606 cx = bundle2datalink(arg->bundle, NULL); 2607 if (!cx) { 2608 log_Printf(LogWARN, "A link must be specified for ``clear physical''\n"); 2609 return 1; 2610 } 2611 t = &cx->physical->link.stats.total; 2612 } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0) 2613 t = &arg->bundle->ncp.ipcp.throughput; 2614 else 2615 return -1; 2616 2617 if (arg->argc > arg->argn + 1) { 2618 clear_type = 0; 2619 for (i = arg->argn + 1; i < arg->argc; i++) 2620 if (strcasecmp(arg->argv[i], "overall") == 0) 2621 clear_type |= THROUGHPUT_OVERALL; 2622 else if (strcasecmp(arg->argv[i], "current") == 0) 2623 clear_type |= THROUGHPUT_CURRENT; 2624 else if (strcasecmp(arg->argv[i], "peak") == 0) 2625 clear_type |= THROUGHPUT_PEAK; 2626 else 2627 return -1; 2628 } else 2629 clear_type = THROUGHPUT_ALL; 2630 2631 throughput_clear(t, clear_type, arg->prompt); 2632 return 0; 2633} 2634 2635static int 2636RunListCommand(struct cmdargs const *arg) 2637{ 2638 const char *cmd = arg->argc ? arg->argv[arg->argc - 1] : "???"; 2639 2640#ifndef NONAT 2641 if (arg->cmd->args == NatCommands && 2642 tolower(*arg->argv[arg->argn - 1]) == 'a') { 2643 if (arg->prompt) 2644 prompt_Printf(arg->prompt, "The alias command is deprecated\n"); 2645 else 2646 log_Printf(LogWARN, "The alias command is deprecated\n"); 2647 } 2648#endif 2649 2650 if (arg->argc > arg->argn) 2651 FindExec(arg->bundle, arg->cmd->args, arg->argc, arg->argn, arg->argv, 2652 arg->prompt, arg->cx); 2653 else if (arg->prompt) 2654 prompt_Printf(arg->prompt, "Use `%s help' to get a list or `%s help" 2655 " <option>' for syntax help.\n", cmd, cmd); 2656 else 2657 log_Printf(LogWARN, "%s command must have arguments\n", cmd); 2658 2659 return 0; 2660} 2661 2662static int 2663IfaceAddCommand(struct cmdargs const *arg) 2664{ 2665 int bits, n, how; 2666 struct in_addr ifa, mask, brd; 2667 2668 if (arg->argc == arg->argn + 1) { 2669 if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL)) 2670 return -1; 2671 mask.s_addr = brd.s_addr = INADDR_BROADCAST; 2672 } else { 2673 if (arg->argc == arg->argn + 2) { 2674 if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, &mask, &bits)) 2675 return -1; 2676 n = 1; 2677 } else if (arg->argc == arg->argn + 3) { 2678 if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL)) 2679 return -1; 2680 if (!ParseAddr(NULL, arg->argv[arg->argn + 1], &mask, NULL, NULL)) 2681 return -1; 2682 n = 2; 2683 } else 2684 return -1; 2685 2686 if (!ParseAddr(NULL, arg->argv[arg->argn + n], &brd, NULL, NULL)) 2687 return -1; 2688 } 2689 2690 how = IFACE_ADD_LAST; 2691 if (arg->cmd->args) 2692 how |= IFACE_FORCE_ADD; 2693 2694 return !iface_inAdd(arg->bundle->iface, ifa, mask, brd, how); 2695} 2696 2697static int 2698IfaceDeleteCommand(struct cmdargs const *arg) 2699{ 2700 struct in_addr ifa; 2701 int ok; 2702 2703 if (arg->argc != arg->argn + 1) 2704 return -1; 2705 2706 if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL)) 2707 return -1; 2708 2709 if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED && 2710 arg->bundle->ncp.ipcp.my_ip.s_addr == ifa.s_addr) { 2711 log_Printf(LogWARN, "%s: Cannot remove active interface address\n", 2712 inet_ntoa(ifa)); 2713 return 1; 2714 } 2715 2716 ok = iface_inDelete(arg->bundle->iface, ifa); 2717 if (!ok) { 2718 if (arg->cmd->args) 2719 ok = 1; 2720 else if (arg->prompt) 2721 prompt_Printf(arg->prompt, "%s: No such address\n", inet_ntoa(ifa)); 2722 else 2723 log_Printf(LogWARN, "%s: No such address\n", inet_ntoa(ifa)); 2724 } 2725 2726 return !ok; 2727} 2728 2729static int 2730IfaceClearCommand(struct cmdargs const *arg) 2731{ 2732 int how; 2733 2734 if (arg->argc != arg->argn) 2735 return -1; 2736 2737 how = arg->bundle->ncp.ipcp.fsm.state == ST_OPENED || 2738 arg->bundle->phys_type.all & PHYS_AUTO ? 2739 IFACE_CLEAR_ALIASES : IFACE_CLEAR_ALL; 2740 iface_Clear(arg->bundle->iface, how); 2741 2742 return 0; 2743} 2744 2745static int 2746SetProcTitle(struct cmdargs const *arg) 2747{ 2748 static char title[LINE_LEN]; 2749 char *argv[MAXARGS], *ptr; 2750 int len, remaining, f, argc = arg->argc - arg->argn; 2751 2752 if (arg->argc == arg->argn) { 2753 SetTitle(NULL); 2754 return 0; 2755 } 2756 2757 if (argc >= sizeof argv / sizeof argv[0]) { 2758 argc = sizeof argv / sizeof argv[0] - 1; 2759 log_Printf(LogWARN, "Truncating proc title to %d args\n", argc); 2760 } 2761 command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 1, getpid()); 2762 2763 ptr = title; 2764 remaining = sizeof title - 1; 2765 for (f = 0; f < argc && remaining; f++) { 2766 if (f) { 2767 *ptr++ = ' '; 2768 remaining--; 2769 } 2770 len = strlen(argv[f]); 2771 if (len > remaining) 2772 len = remaining; 2773 memcpy(ptr, argv[f], len); 2774 remaining -= len; 2775 ptr += len; 2776 } 2777 *ptr = '\0'; 2778 2779 SetTitle(title); 2780 2781 return 0; 2782} 2783