command.c revision 71657
16059Samurai/*
26059Samurai *		PPP User command processing module
36059Samurai *
46059Samurai *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
56059Samurai *
66059Samurai *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
76059Samurai *
86059Samurai * Redistribution and use in source and binary forms are permitted
96059Samurai * provided that the above copyright notice and this paragraph are
106059Samurai * duplicated in all such forms and that any documentation,
116059Samurai * advertising materials, and other materials related to such
126059Samurai * distribution and use acknowledge that the software was developed
136059Samurai * by the Internet Initiative Japan, Inc.  The name of the
146059Samurai * IIJ may not be used to endorse or promote products derived
156059Samurai * from this software without specific prior written permission.
166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
198857Srgrimes *
2050479Speter * $FreeBSD: head/usr.sbin/ppp/command.c 71657 2001-01-26 01:41:34Z brian $
218857Srgrimes *
226059Samurai */
2343313Sbrian#include <sys/param.h>
2430715Sbrian#include <netinet/in_systm.h>
2526031Sbrian#include <netinet/in.h>
2630715Sbrian#include <netinet/ip.h>
2726031Sbrian#include <arpa/inet.h>
2830715Sbrian#include <sys/socket.h>
2926031Sbrian#include <net/route.h>
3030715Sbrian#include <netdb.h>
3136285Sbrian#include <sys/un.h>
3230715Sbrian
3338628Sbrian#include <ctype.h>
3430715Sbrian#include <errno.h>
3526516Sbrian#include <fcntl.h>
3630715Sbrian#include <paths.h>
3730715Sbrian#include <stdio.h>
3830715Sbrian#include <stdlib.h>
3930715Sbrian#include <string.h>
4030715Sbrian#include <sys/wait.h>
4130715Sbrian#include <termios.h>
4230715Sbrian#include <unistd.h>
4330715Sbrian
4450059Sbrian#ifndef NONAT
4558037Sbrian#ifdef LOCALNAT
4658037Sbrian#include "alias.h"
4758037Sbrian#else
4846086Sbrian#include <alias.h>
4939395Sbrian#endif
5039395Sbrian#endif
5158037Sbrian
5246686Sbrian#include "layer.h"
5337009Sbrian#include "defs.h"
5431343Sbrian#include "command.h"
5530715Sbrian#include "mbuf.h"
5630715Sbrian#include "log.h"
5730715Sbrian#include "timer.h"
586059Samurai#include "fsm.h"
5931690Sbrian#include "iplist.h"
6036285Sbrian#include "throughput.h"
6136285Sbrian#include "slcompress.h"
6238557Sbrian#include "lqr.h"
6338557Sbrian#include "hdlc.h"
6463484Sbrian#include "lcp.h"
656059Samurai#include "ipcp.h"
6650059Sbrian#ifndef NONAT
6751075Sbrian#include "nat_cmd.h"
6831343Sbrian#endif
6925630Sbrian#include "systems.h"
7036285Sbrian#include "filter.h"
7136285Sbrian#include "descriptor.h"
7230715Sbrian#include "main.h"
7330715Sbrian#include "route.h"
7430715Sbrian#include "ccp.h"
7531080Sbrian#include "auth.h"
7636285Sbrian#include "async.h"
7736285Sbrian#include "link.h"
7836285Sbrian#include "physical.h"
7936285Sbrian#include "mp.h"
8043313Sbrian#ifndef NORADIUS
8143313Sbrian#include "radius.h"
8243313Sbrian#endif
8336285Sbrian#include "bundle.h"
8436285Sbrian#include "server.h"
8536285Sbrian#include "prompt.h"
8636285Sbrian#include "chat.h"
8736285Sbrian#include "chap.h"
8838174Sbrian#include "cbcp.h"
8936285Sbrian#include "datalink.h"
9040561Sbrian#include "iface.h"
9153298Sbrian#include "id.h"
926059Samurai
9336285Sbrian/* ``set'' values */
9436285Sbrian#define	VAR_AUTHKEY	0
9536285Sbrian#define	VAR_DIAL	1
9636285Sbrian#define	VAR_LOGIN	2
9736285Sbrian#define	VAR_AUTHNAME	3
9836285Sbrian#define	VAR_AUTOLOAD	4
9936285Sbrian#define	VAR_WINSIZE	5
10036285Sbrian#define	VAR_DEVICE	6
10136285Sbrian#define	VAR_ACCMAP	7
10236285Sbrian#define	VAR_MRRU	8
10336285Sbrian#define	VAR_MRU		9
10436285Sbrian#define	VAR_MTU		10
10536285Sbrian#define	VAR_OPENMODE	11
10636285Sbrian#define	VAR_PHONE	12
10736285Sbrian#define	VAR_HANGUP	13
10836285Sbrian#define	VAR_IDLETIMEOUT	14
10936285Sbrian#define	VAR_LQRPERIOD	15
11036285Sbrian#define	VAR_LCPRETRY	16
11136285Sbrian#define	VAR_CHAPRETRY	17
11236285Sbrian#define	VAR_PAPRETRY	18
11336285Sbrian#define	VAR_CCPRETRY	19
11436285Sbrian#define	VAR_IPCPRETRY	20
11536285Sbrian#define	VAR_DNS		21
11636285Sbrian#define	VAR_NBNS	22
11736285Sbrian#define	VAR_MODE	23
11838174Sbrian#define	VAR_CALLBACK	24
11938174Sbrian#define	VAR_CBCP	25
12038544Sbrian#define	VAR_CHOKED	26
12140665Sbrian#define	VAR_SENDPIPE	27
12240665Sbrian#define	VAR_RECVPIPE	28
12343313Sbrian#define	VAR_RADIUS	29
12444073Sbrian#define	VAR_CD		30
12546686Sbrian#define	VAR_PARITY	31
12646686Sbrian#define VAR_CRTSCTS	32
12750867Sbrian#define VAR_URGENTPORTS	33
12852488Sbrian#define	VAR_LOGOUT	34
12961534Sbrian#define	VAR_IFQUEUE	35
13067910Sbrian#define	VAR_KEYBITS	36
1316059Samurai
13236285Sbrian/* ``accept|deny|disable|enable'' masks */
13336285Sbrian#define NEG_HISMASK (1)
13436285Sbrian#define NEG_MYMASK (2)
13536285Sbrian
13636285Sbrian/* ``accept|deny|disable|enable'' values */
13736285Sbrian#define NEG_ACFCOMP	40
13844106Sbrian#define NEG_CHAP05	41
13944106Sbrian#define NEG_CHAP80	42
14044106Sbrian#define NEG_CHAP80LM	43
14144106Sbrian#define NEG_DEFLATE	44
14247858Sbrian#define NEG_DNS		45
14347858Sbrian#define NEG_ENDDISC	46
14447858Sbrian#define NEG_LQR		47
14547858Sbrian#define NEG_PAP		48
14647858Sbrian#define NEG_PPPDDEFLATE	49
14747858Sbrian#define NEG_PRED1	50
14847858Sbrian#define NEG_PROTOCOMP	51
14947858Sbrian#define NEG_SHORTSEQ	52
15047858Sbrian#define NEG_VJCOMP	53
15167910Sbrian#define NEG_MPPE	54
15267910Sbrian#define NEG_CHAP81	55
15336285Sbrian
15467915Sbrianconst char Version[] = "2.3";
15536285Sbrian
15636285Sbrianstatic int ShowCommand(struct cmdargs const *);
15736285Sbrianstatic int TerminalCommand(struct cmdargs const *);
15836285Sbrianstatic int QuitCommand(struct cmdargs const *);
15936285Sbrianstatic int OpenCommand(struct cmdargs const *);
16036285Sbrianstatic int CloseCommand(struct cmdargs const *);
16136285Sbrianstatic int DownCommand(struct cmdargs const *);
16236285Sbrianstatic int SetCommand(struct cmdargs const *);
16336285Sbrianstatic int LinkCommand(struct cmdargs const *);
16436285Sbrianstatic int AddCommand(struct cmdargs const *);
16536285Sbrianstatic int DeleteCommand(struct cmdargs const *);
16636285Sbrianstatic int NegotiateCommand(struct cmdargs const *);
16736934Sbrianstatic int ClearCommand(struct cmdargs const *);
16840561Sbrianstatic int RunListCommand(struct cmdargs const *);
16940561Sbrianstatic int IfaceAddCommand(struct cmdargs const *);
17040561Sbrianstatic int IfaceDeleteCommand(struct cmdargs const *);
17140561Sbrianstatic int IfaceClearCommand(struct cmdargs const *);
17240679Sbrianstatic int SetProcTitle(struct cmdargs const *);
17350059Sbrian#ifndef NONAT
17458867Sbrianstatic int NatEnable(struct cmdargs const *);
17558867Sbrianstatic int NatOption(struct cmdargs const *);
17631343Sbrian#endif
1776059Samurai
17836285Sbrianstatic const char *
17936285Sbrianshowcx(struct cmdtab const *cmd)
18036285Sbrian{
18136285Sbrian  if (cmd->lauth & LOCAL_CX)
18236285Sbrian    return "(c)";
18336285Sbrian  else if (cmd->lauth & LOCAL_CX_OPT)
18436285Sbrian    return "(o)";
18536285Sbrian
18636285Sbrian  return "";
18736285Sbrian}
18836285Sbrian
1896059Samuraistatic int
19031343SbrianHelpCommand(struct cmdargs const *arg)
1916059Samurai{
19228679Sbrian  struct cmdtab const *cmd;
19336285Sbrian  int n, cmax, dmax, cols, cxlen;
19436285Sbrian  const char *cx;
1956059Samurai
19636285Sbrian  if (!arg->prompt) {
19736285Sbrian    log_Printf(LogWARN, "help: Cannot help without a prompt\n");
19826516Sbrian    return 0;
19936285Sbrian  }
20026516Sbrian
20136285Sbrian  if (arg->argc > arg->argn) {
20236285Sbrian    for (cmd = arg->cmdtab; cmd->name || cmd->alias; cmd++)
20336285Sbrian      if ((cmd->lauth & arg->prompt->auth) &&
20436285Sbrian          ((cmd->name && !strcasecmp(cmd->name, arg->argv[arg->argn])) ||
20536285Sbrian           (cmd->alias && !strcasecmp(cmd->alias, arg->argv[arg->argn])))) {
20636285Sbrian	prompt_Printf(arg->prompt, "%s %s\n", cmd->syntax, showcx(cmd));
20728679Sbrian	return 0;
2086059Samurai      }
20926516Sbrian    return -1;
2106059Samurai  }
21136285Sbrian
21231372Sbrian  cmax = dmax = 0;
21336285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
21436285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
21536285Sbrian      if ((n = strlen(cmd->name) + strlen(showcx(cmd))) > cmax)
21631372Sbrian        cmax = n;
21731372Sbrian      if ((n = strlen(cmd->helpmes)) > dmax)
21831372Sbrian        dmax = n;
21931372Sbrian    }
22031372Sbrian
22131372Sbrian  cols = 80 / (dmax + cmax + 3);
2226059Samurai  n = 0;
22336285Sbrian  prompt_Printf(arg->prompt, "(o) = Optional context,"
22436285Sbrian                " (c) = Context required\n");
22536285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
22636285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
22736285Sbrian      cx = showcx(cmd);
22836285Sbrian      cxlen = cmax - strlen(cmd->name);
22940482Sbrian      if (n % cols != 0)
23040482Sbrian        prompt_Printf(arg->prompt, " ");
23140482Sbrian      prompt_Printf(arg->prompt, "%s%-*.*s: %-*.*s",
23236285Sbrian              cmd->name, cxlen, cxlen, cx, dmax, dmax, cmd->helpmes);
23331372Sbrian      if (++n % cols == 0)
23436285Sbrian        prompt_Printf(arg->prompt, "\n");
2356059Samurai    }
23631372Sbrian  if (n % cols != 0)
23736285Sbrian    prompt_Printf(arg->prompt, "\n");
23826516Sbrian
23926516Sbrian  return 0;
2406059Samurai}
2416059Samurai
24236285Sbrianstatic int
24363484SbrianIdentCommand(struct cmdargs const *arg)
24463484Sbrian{
24563484Sbrian  int f, pos;
24663484Sbrian
24763484Sbrian  *arg->cx->physical->link.lcp.cfg.ident = '\0';
24863484Sbrian
24963484Sbrian  for (pos = 0, f = arg->argn; f < arg->argc; f++)
25063484Sbrian    pos += snprintf(arg->cx->physical->link.lcp.cfg.ident + pos,
25163484Sbrian                    sizeof arg->cx->physical->link.lcp.cfg.ident - pos, "%s%s",
25263484Sbrian                    f == arg->argn ? "" : " ", arg->argv[f]);
25363484Sbrian
25463484Sbrian  return 0;
25563484Sbrian}
25663484Sbrian
25763484Sbrianstatic int
25863484SbrianSendIdentification(struct cmdargs const *arg)
25963484Sbrian{
26063484Sbrian  if (arg->cx->state < DATALINK_LCP) {
26163484Sbrian    log_Printf(LogWARN, "sendident: link has not reached LCP\n");
26263484Sbrian    return 2;
26363484Sbrian  }
26463484Sbrian  return lcp_SendIdentification(&arg->cx->physical->link.lcp) ? 0 : 1;
26563484Sbrian}
26663484Sbrian
26763484Sbrianstatic int
26836285SbrianCloneCommand(struct cmdargs const *arg)
2696059Samurai{
27036285Sbrian  char namelist[LINE_LEN];
27136285Sbrian  char *name;
27236285Sbrian  int f;
2736059Samurai
27436285Sbrian  if (arg->argc == arg->argn)
27536285Sbrian    return -1;
27636285Sbrian
27736285Sbrian  namelist[sizeof namelist - 1] = '\0';
27836285Sbrian  for (f = arg->argn; f < arg->argc; f++) {
27936285Sbrian    strncpy(namelist, arg->argv[f], sizeof namelist - 1);
28036285Sbrian    for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
28136285Sbrian      bundle_DatalinkClone(arg->bundle, arg->cx, name);
2826059Samurai  }
28336285Sbrian
28436285Sbrian  return 0;
2856059Samurai}
2866059Samurai
2876059Samuraistatic int
28836285SbrianRemoveCommand(struct cmdargs const *arg)
2896059Samurai{
29036285Sbrian  if (arg->argc != arg->argn)
29136285Sbrian    return -1;
29211336Samurai
29336285Sbrian  if (arg->cx->state != DATALINK_CLOSED) {
29436285Sbrian    log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n");
29536285Sbrian    return 2;
2966059Samurai  }
29726516Sbrian
29836285Sbrian  bundle_DatalinkRemove(arg->bundle, arg->cx);
29936285Sbrian  return 0;
30036285Sbrian}
30132711Sbrian
30236285Sbrianstatic int
30336285SbrianRenameCommand(struct cmdargs const *arg)
30436285Sbrian{
30536285Sbrian  if (arg->argc != arg->argn + 1)
30636285Sbrian    return -1;
30731121Sbrian
30836285Sbrian  if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn]))
30936285Sbrian    return 0;
31036285Sbrian
31136285Sbrian  log_Printf(LogWARN, "%s -> %s: target name already exists\n",
31236285Sbrian             arg->cx->name, arg->argv[arg->argn]);
31336285Sbrian  return 1;
31436285Sbrian}
31536285Sbrian
31636285Sbrianint
31736285SbrianLoadCommand(struct cmdargs const *arg)
31836285Sbrian{
31940797Sbrian  const char *err;
32040797Sbrian  int n, mode;
32136285Sbrian
32240797Sbrian  mode = arg->bundle->phys_type.all;
32336285Sbrian
32440797Sbrian  if (arg->argn < arg->argc) {
32540797Sbrian    for (n = arg->argn; n < arg->argc; n++)
32640797Sbrian      if ((err = system_IsValid(arg->argv[n], arg->prompt, mode)) != NULL) {
32740797Sbrian        log_Printf(LogWARN, "%s: %s\n", arg->argv[n], err);
32840797Sbrian        return 1;
32940797Sbrian      }
33040797Sbrian
33140797Sbrian    for (n = arg->argn; n < arg->argc; n++) {
33240797Sbrian      bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
33340797Sbrian      system_Select(arg->bundle, arg->argv[n], CONFFILE, arg->prompt, arg->cx);
33440797Sbrian    }
33540797Sbrian    bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
33640797Sbrian  } else if ((err = system_IsValid("default", arg->prompt, mode)) != NULL) {
33740797Sbrian    log_Printf(LogWARN, "default: %s\n", err);
33836285Sbrian    return 1;
33936285Sbrian  } else {
34040797Sbrian    bundle_SetLabel(arg->bundle, "default");
34140797Sbrian    system_Select(arg->bundle, "default", CONFFILE, arg->prompt, arg->cx);
34240797Sbrian    bundle_SetLabel(arg->bundle, "default");
34336285Sbrian  }
34440797Sbrian
34526516Sbrian  return 0;
3466059Samurai}
3476059Samurai
34836285Sbrianint
34936285SbrianSaveCommand(struct cmdargs const *arg)
35036285Sbrian{
35136285Sbrian  log_Printf(LogWARN, "save command is not implemented (yet).\n");
35236285Sbrian  return 1;
35336285Sbrian}
35436285Sbrian
35510528Samuraistatic int
35636285SbrianDialCommand(struct cmdargs const *arg)
35728536Sbrian{
35836285Sbrian  int res;
35936285Sbrian
36036465Sbrian  if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO)))
36136465Sbrian      || (!arg->cx &&
36236928Sbrian          (arg->bundle->phys_type.all & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) {
36336285Sbrian    log_Printf(LogWARN, "Manual dial is only available for auto and"
36436285Sbrian              " interactive links\n");
36536285Sbrian    return 1;
36634536Sbrian  }
36736285Sbrian
36836285Sbrian  if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0)
36936285Sbrian    return res;
37036285Sbrian
37137993Sbrian  bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
37236285Sbrian
37336285Sbrian  return 0;
37428536Sbrian}
37528536Sbrian
37638628Sbrian#define isinword(ch) (isalnum(ch) || (ch) == '_')
37738628Sbrian
37838628Sbrianstatic char *
37938628Sbrianstrstrword(char *big, const char *little)
38038628Sbrian{
38138628Sbrian  /* Get the first occurance of the word ``little'' in ``big'' */
38238628Sbrian  char *pos;
38338628Sbrian  int len;
38438628Sbrian
38538628Sbrian  pos = big;
38638628Sbrian  len = strlen(little);
38738628Sbrian
38838628Sbrian  while ((pos = strstr(pos, little)) != NULL)
38947865Sbrian    if ((pos != big && isinword(pos[-1])) || isinword(pos[len]))
39047865Sbrian      pos++;
39147865Sbrian    else if (pos != big && pos[-1] == '\\')
39247865Sbrian      memmove(pos - 1, pos, strlen(pos) + 1);
39347865Sbrian    else
39438628Sbrian      break;
39538628Sbrian
39638628Sbrian  return pos;
39738628Sbrian}
39838628Sbrian
39938628Sbrianstatic char *
40038628Sbriansubst(char *tgt, const char *oldstr, const char *newstr)
40138628Sbrian{
40238628Sbrian  /* tgt is a malloc()d area... realloc() as necessary */
40338628Sbrian  char *word, *ntgt;
40438628Sbrian  int ltgt, loldstr, lnewstr, pos;
40538628Sbrian
40638628Sbrian  if ((word = strstrword(tgt, oldstr)) == NULL)
40738628Sbrian    return tgt;
40838628Sbrian
40938628Sbrian  ltgt = strlen(tgt) + 1;
41038628Sbrian  loldstr = strlen(oldstr);
41138628Sbrian  lnewstr = strlen(newstr);
41238628Sbrian  do {
41338628Sbrian    pos = word - tgt;
41438628Sbrian    if (loldstr > lnewstr)
41538628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
41638628Sbrian    if (loldstr != lnewstr) {
41738628Sbrian      ntgt = realloc(tgt, ltgt += lnewstr - loldstr);
41838628Sbrian      if (ntgt == NULL)
41938628Sbrian        break;			/* Oh wonderful ! */
42038628Sbrian      word = ntgt + pos;
42138628Sbrian      tgt = ntgt;
42238628Sbrian    }
42338628Sbrian    if (lnewstr > loldstr)
42438628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
42538628Sbrian    bcopy(newstr, word, lnewstr);
42638628Sbrian  } while ((word = strstrword(word, oldstr)));
42738628Sbrian
42838628Sbrian  return tgt;
42938628Sbrian}
43038628Sbrian
43143888Sbrianvoid
43243888Sbriancommand_Expand(char **nargv, int argc, char const *const *oargv,
43347849Sbrian               struct bundle *bundle, int inc0, pid_t pid)
43438628Sbrian{
43538628Sbrian  int arg;
43647849Sbrian  char pidstr[12];
43738628Sbrian
43841755Sbrian  if (inc0)
43941755Sbrian    arg = 0;		/* Start at arg 0 */
44041755Sbrian  else {
44141755Sbrian    nargv[0] = strdup(oargv[0]);
44241755Sbrian    arg = 1;
44341755Sbrian  }
44447849Sbrian  snprintf(pidstr, sizeof pidstr, "%d", (int)pid);
44541755Sbrian  for (; arg < argc; arg++) {
44638629Sbrian    nargv[arg] = strdup(oargv[arg]);
44738629Sbrian    nargv[arg] = subst(nargv[arg], "HISADDR",
44838628Sbrian                       inet_ntoa(bundle->ncp.ipcp.peer_ip));
44938629Sbrian    nargv[arg] = subst(nargv[arg], "AUTHNAME", bundle->cfg.auth.name);
45040561Sbrian    nargv[arg] = subst(nargv[arg], "INTERFACE", bundle->iface->name);
45138628Sbrian    nargv[arg] = subst(nargv[arg], "MYADDR", inet_ntoa(bundle->ncp.ipcp.my_ip));
45238629Sbrian    nargv[arg] = subst(nargv[arg], "USER", bundle->ncp.mp.peer.authname);
45338629Sbrian    nargv[arg] = subst(nargv[arg], "PEER_ENDDISC",
45438629Sbrian                       mp_Enddisc(bundle->ncp.mp.peer.enddisc.class,
45538629Sbrian                                  bundle->ncp.mp.peer.enddisc.address,
45638629Sbrian                                  bundle->ncp.mp.peer.enddisc.len));
45738629Sbrian    nargv[arg] = subst(nargv[arg], "ENDDISC",
45838629Sbrian                       mp_Enddisc(bundle->ncp.mp.cfg.enddisc.class,
45938629Sbrian                                  bundle->ncp.mp.cfg.enddisc.address,
46038629Sbrian                                  bundle->ncp.mp.cfg.enddisc.len));
46147849Sbrian    nargv[arg] = subst(nargv[arg], "PROCESSID", pidstr);
46238629Sbrian    nargv[arg] = subst(nargv[arg], "LABEL", bundle_GetLabel(bundle));
46358044Sbrian    nargv[arg] = subst(nargv[arg], "DNS0",
46458044Sbrian                       inet_ntoa(bundle->ncp.ipcp.ns.dns[0]));
46558044Sbrian    nargv[arg] = subst(nargv[arg], "DNS1",
46658044Sbrian                       inet_ntoa(bundle->ncp.ipcp.ns.dns[1]));
46763484Sbrian    nargv[arg] = subst(nargv[arg], "VERSION", Version);
46863484Sbrian    nargv[arg] = subst(nargv[arg], "COMPILATIONDATE", __DATE__);
46938628Sbrian  }
47038628Sbrian  nargv[arg] = NULL;
47138628Sbrian}
47238628Sbrian
47328536Sbrianstatic int
47431343SbrianShellCommand(struct cmdargs const *arg, int bg)
47510528Samurai{
47610528Samurai  const char *shell;
47747849Sbrian  pid_t shpid, pid;
47820813Sjkh
47918856Ssos#ifdef SHELL_ONLY_INTERACTIVELY
48026911Sbrian  /* we're only allowed to shell when we run ppp interactively */
48136285Sbrian  if (arg->prompt && arg->prompt->owner) {
48236285Sbrian    log_Printf(LogWARN, "Can't start a shell from a network connection\n");
48326516Sbrian    return 1;
48410528Samurai  }
48526911Sbrian#endif
48628679Sbrian
48736285Sbrian  if (arg->argc == arg->argn) {
48836285Sbrian    if (!arg->prompt) {
48936285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
49036285Sbrian                " a config file\n");
49128381Sbrian      return 1;
49236285Sbrian    } else if (arg->prompt->owner) {
49336285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
49436285Sbrian                " a socket connection\n");
49536285Sbrian      return 1;
49628381Sbrian    } else if (bg) {
49736285Sbrian      log_Printf(LogWARN, "Can only start an interactive shell in"
49828679Sbrian		" the foreground mode\n");
49928381Sbrian      return 1;
50028381Sbrian    }
50134536Sbrian  }
50234536Sbrian
50347849Sbrian  pid = getpid();
50428679Sbrian  if ((shpid = fork()) == 0) {
50536285Sbrian    int i, fd;
50618531Sbde
50736285Sbrian    if ((shell = getenv("SHELL")) == 0)
50836285Sbrian      shell = _PATH_BSHELL;
50932017Sbrian
51036285Sbrian    timer_TermService();
51136285Sbrian
51236285Sbrian    if (arg->prompt)
51336285Sbrian      fd = arg->prompt->fd_out;
51436285Sbrian    else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
51536285Sbrian      log_Printf(LogALERT, "Failed to open %s: %s\n",
51636285Sbrian                _PATH_DEVNULL, strerror(errno));
51728679Sbrian      exit(1);
51828679Sbrian    }
51949976Sbrian    dup2(fd, STDIN_FILENO);
52049976Sbrian    dup2(fd, STDOUT_FILENO);
52149976Sbrian    dup2(fd, STDERR_FILENO);
52249976Sbrian    for (i = getdtablesize(); i > STDERR_FILENO; i--)
52349976Sbrian      fcntl(i, F_SETFD, 1);
52426516Sbrian
52564802Sbrian#ifndef NOSUID
52655252Sbrian    setuid(ID0realuid());
52764802Sbrian#endif
52836285Sbrian    if (arg->argc > arg->argn) {
52928679Sbrian      /* substitute pseudo args */
53038628Sbrian      char *argv[MAXARGS];
53138628Sbrian      int argc = arg->argc - arg->argn;
53238628Sbrian
53338628Sbrian      if (argc >= sizeof argv / sizeof argv[0]) {
53438628Sbrian        argc = sizeof argv / sizeof argv[0] - 1;
53538628Sbrian        log_Printf(LogWARN, "Truncating shell command to %d args\n", argc);
53631343Sbrian      }
53747849Sbrian      command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 0, pid);
53828679Sbrian      if (bg) {
53928679Sbrian	pid_t p;
54010528Samurai
54128679Sbrian	p = getpid();
54228679Sbrian	if (daemon(1, 1) == -1) {
54336832Sbrian	  log_Printf(LogERROR, "%d: daemon: %s\n", (int)p, strerror(errno));
54428679Sbrian	  exit(1);
54528679Sbrian	}
54636285Sbrian      } else if (arg->prompt)
54736285Sbrian        printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]);
54831343Sbrian      execvp(argv[0], argv);
54930316Sbrian    } else {
55036285Sbrian      if (arg->prompt)
55132017Sbrian        printf("ppp: Pausing until %s finishes\n", shell);
55236285Sbrian      prompt_TtyOldMode(arg->prompt);
55331343Sbrian      execl(shell, shell, NULL);
55430316Sbrian    }
55520813Sjkh
55640665Sbrian    log_Printf(LogWARN, "exec() of %s failed: %s\n",
55740665Sbrian              arg->argc > arg->argn ? arg->argv[arg->argn] : shell,
55840665Sbrian              strerror(errno));
55949976Sbrian    _exit(255);
56010528Samurai  }
56136285Sbrian
56236285Sbrian  if (shpid == (pid_t) - 1)
56336285Sbrian    log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno));
56436285Sbrian  else {
56510528Samurai    int status;
56631343Sbrian    waitpid(shpid, &status, 0);
56710528Samurai  }
56820813Sjkh
56936285Sbrian  if (arg->prompt && !arg->prompt->owner)
57036285Sbrian    prompt_TtyCommandMode(arg->prompt);
57120813Sjkh
57236285Sbrian  return 0;
57310528Samurai}
57410528Samurai
57531343Sbrianstatic int
57631343SbrianBgShellCommand(struct cmdargs const *arg)
57731343Sbrian{
57836285Sbrian  if (arg->argc == arg->argn)
57931343Sbrian    return -1;
58031343Sbrian  return ShellCommand(arg, 1);
58131343Sbrian}
58231343Sbrian
58331343Sbrianstatic int
58431343SbrianFgShellCommand(struct cmdargs const *arg)
58531343Sbrian{
58631343Sbrian  return ShellCommand(arg, 0);
58731343Sbrian}
58831343Sbrian
58958044Sbrianstatic int
59058044SbrianResolvCommand(struct cmdargs const *arg)
59158044Sbrian{
59258044Sbrian  if (arg->argc == arg->argn + 1) {
59358044Sbrian    if (!strcasecmp(arg->argv[arg->argn], "reload"))
59458044Sbrian      ipcp_LoadDNS(&arg->bundle->ncp.ipcp);
59558044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "restore"))
59658044Sbrian      ipcp_RestoreDNS(&arg->bundle->ncp.ipcp);
59758044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "rewrite"))
59858044Sbrian      ipcp_WriteDNS(&arg->bundle->ncp.ipcp);
59958044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "readonly"))
60058044Sbrian      arg->bundle->ncp.ipcp.ns.writable = 0;
60158044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "writable"))
60258044Sbrian      arg->bundle->ncp.ipcp.ns.writable = 1;
60358044Sbrian    else
60458044Sbrian      return -1;
60558044Sbrian
60658044Sbrian    return 0;
60758044Sbrian  }
60858044Sbrian
60958044Sbrian  return -1;
61058044Sbrian}
61158044Sbrian
61250059Sbrian#ifndef NONAT
61358867Sbrianstatic struct cmdtab const NatCommands[] =
61440561Sbrian{
61550059Sbrian  {"addr", NULL, nat_RedirectAddr, LOCAL_AUTH,
61650059Sbrian   "static address translation", "nat addr [addr_local addr_alias]"},
61758867Sbrian  {"deny_incoming", NULL, NatOption, LOCAL_AUTH,
61850059Sbrian   "stop incoming connections", "nat deny_incoming yes|no",
61940561Sbrian   (const void *) PKT_ALIAS_DENY_INCOMING},
62058867Sbrian  {"enable", NULL, NatEnable, LOCAL_AUTH,
62150059Sbrian   "enable NAT", "nat enable yes|no"},
62258867Sbrian  {"log", NULL, NatOption, LOCAL_AUTH,
62350059Sbrian   "log NAT link creation", "nat log yes|no",
62440561Sbrian   (const void *) PKT_ALIAS_LOG},
62550059Sbrian  {"port", NULL, nat_RedirectPort, LOCAL_AUTH, "port redirection",
62650059Sbrian   "nat port proto localaddr:port[-port] aliasport[-aliasport]"},
62750059Sbrian  {"proxy", NULL, nat_ProxyRule, LOCAL_AUTH,
62850059Sbrian   "proxy control", "nat proxy server host[:port] ..."},
62958867Sbrian  {"same_ports", NULL, NatOption, LOCAL_AUTH,
63050059Sbrian   "try to leave port numbers unchanged", "nat same_ports yes|no",
63140561Sbrian   (const void *) PKT_ALIAS_SAME_PORTS},
63258867Sbrian  {"target", NULL, nat_SetTarget, LOCAL_AUTH,
63358867Sbrian   "Default address for incoming connections", "nat target addr" },
63458867Sbrian  {"unregistered_only", NULL, NatOption, LOCAL_AUTH,
63550059Sbrian   "translate unregistered (private) IP address space only",
63650059Sbrian   "nat unregistered_only yes|no",
63740561Sbrian   (const void *) PKT_ALIAS_UNREGISTERED_ONLY},
63858867Sbrian  {"use_sockets", NULL, NatOption, LOCAL_AUTH,
63950059Sbrian   "allocate host sockets", "nat use_sockets yes|no",
64040561Sbrian   (const void *) PKT_ALIAS_USE_SOCKETS},
64140561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
64258867Sbrian   "Display this message", "nat help|? [command]", NatCommands},
64340561Sbrian  {NULL, NULL, NULL},
64440561Sbrian};
64540561Sbrian#endif
64640561Sbrian
64740561Sbrianstatic struct cmdtab const AllowCommands[] = {
64840561Sbrian  {"modes", "mode", AllowModes, LOCAL_AUTH,
64940561Sbrian  "Only allow certain ppp modes", "allow modes mode..."},
65040561Sbrian  {"users", "user", AllowUsers, LOCAL_AUTH,
65140561Sbrian  "Only allow ppp access to certain users", "allow users logname..."},
65240561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
65340561Sbrian  "Display this message", "allow help|? [command]", AllowCommands},
65440561Sbrian  {NULL, NULL, NULL},
65540561Sbrian};
65640561Sbrian
65740561Sbrianstatic struct cmdtab const IfaceCommands[] =
65840561Sbrian{
65940561Sbrian  {"add", NULL, IfaceAddCommand, LOCAL_AUTH,
66040561Sbrian   "Add iface address", "iface add addr[/bits| mask] peer", NULL},
66140561Sbrian  {NULL, "add!", IfaceAddCommand, LOCAL_AUTH,
66240561Sbrian   "Add or change an iface address", "iface add! addr[/bits| mask] peer",
66340561Sbrian   (void *)1},
66440561Sbrian  {"clear", NULL, IfaceClearCommand, LOCAL_AUTH,
66540561Sbrian   "Clear iface address(es)", "iface clear"},
66640561Sbrian  {"delete", "rm", IfaceDeleteCommand, LOCAL_AUTH,
66740561Sbrian   "Delete iface address", "iface delete addr", NULL},
66840561Sbrian  {NULL, "rm!", IfaceDeleteCommand, LOCAL_AUTH,
66940561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
67040561Sbrian  {NULL, "delete!", IfaceDeleteCommand, LOCAL_AUTH,
67140561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
67240561Sbrian  {"show", NULL, iface_Show, LOCAL_AUTH,
67340561Sbrian   "Show iface address(es)", "iface show"},
67440561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
67550059Sbrian   "Display this message", "nat help|? [command]", IfaceCommands},
67640561Sbrian  {NULL, NULL, NULL},
67740561Sbrian};
67840561Sbrian
67930715Sbrianstatic struct cmdtab const Commands[] = {
68036285Sbrian  {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
68128679Sbrian  "accept option request", "accept option .."},
68228679Sbrian  {"add", NULL, AddCommand, LOCAL_AUTH,
68332109Sbrian  "add route", "add dest mask gateway", NULL},
68436285Sbrian  {NULL, "add!", AddCommand, LOCAL_AUTH,
68532109Sbrian  "add or change route", "add! dest mask gateway", (void *)1},
68640561Sbrian  {"allow", "auth", RunListCommand, LOCAL_AUTH,
68740561Sbrian  "Allow ppp access", "allow users|modes ....", AllowCommands},
68828679Sbrian  {"bg", "!bg", BgShellCommand, LOCAL_AUTH,
68931372Sbrian  "Run a background command", "[!]bg command"},
69036934Sbrian  {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT,
69146686Sbrian  "Clear throughput statistics",
69246686Sbrian  "clear ipcp|physical [current|overall|peak]..."},
69336285Sbrian  {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX,
69436285Sbrian  "Clone a link", "clone newname..."},
69536285Sbrian  {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT,
69636285Sbrian  "Close an FSM", "close [lcp|ccp]"},
69728679Sbrian  {"delete", NULL, DeleteCommand, LOCAL_AUTH,
69832109Sbrian  "delete route", "delete dest", NULL},
69936285Sbrian  {NULL, "delete!", DeleteCommand, LOCAL_AUTH,
70032109Sbrian  "delete a route if it exists", "delete! dest", (void *)1},
70136285Sbrian  {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
70228679Sbrian  "Deny option request", "deny option .."},
70336285Sbrian  {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT,
70440797Sbrian  "Dial and login", "dial|call [system ...]", NULL},
70536285Sbrian  {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
70628679Sbrian  "Disable option", "disable option .."},
70736285Sbrian  {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT,
70846686Sbrian  "Generate a down event", "down [ccp|lcp]"},
70936285Sbrian  {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
71028679Sbrian  "Enable option", "enable option .."},
71163484Sbrian  {"ident", NULL, IdentCommand, LOCAL_AUTH | LOCAL_CX,
71263484Sbrian  "Set the link identity", "ident text..."},
71340561Sbrian  {"iface", "interface", RunListCommand, LOCAL_AUTH,
71440561Sbrian  "interface control", "iface option ...", IfaceCommands},
71536285Sbrian  {"link", "datalink", LinkCommand, LOCAL_AUTH,
71636285Sbrian  "Link specific commands", "link name command ..."},
71737008Sbrian  {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT,
71840797Sbrian  "Load settings", "load [system ...]"},
71950059Sbrian#ifndef NONAT
72050059Sbrian  {"nat", "alias", RunListCommand, LOCAL_AUTH,
72158867Sbrian  "NAT control", "nat option yes|no", NatCommands},
72250059Sbrian#endif
72336285Sbrian  {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT,
72437955Sbrian  "Open an FSM", "open! [lcp|ccp|ipcp]", (void *)1},
72536285Sbrian  {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH,
72636285Sbrian  "Password for manipulation", "passwd LocalPassword"},
72736285Sbrian  {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
72836285Sbrian  "Quit PPP program", "quit|bye [all]"},
72936285Sbrian  {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX,
73036285Sbrian  "Remove a link", "remove"},
73136285Sbrian  {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX,
73236285Sbrian  "Rename a link", "rename name"},
73358044Sbrian  {"resolv", NULL, ResolvCommand, LOCAL_AUTH,
73458044Sbrian  "Manipulate resolv.conf", "resolv readonly|reload|restore|rewrite|writable"},
73528679Sbrian  {"save", NULL, SaveCommand, LOCAL_AUTH,
73628679Sbrian  "Save settings", "save"},
73763484Sbrian  {"sendident", NULL, SendIdentification, LOCAL_AUTH | LOCAL_CX,
73863484Sbrian  "Transmit the link identity", "sendident"},
73936285Sbrian  {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT,
74028679Sbrian  "Set parameters", "set[up] var value"},
74128679Sbrian  {"shell", "!", FgShellCommand, LOCAL_AUTH,
74228679Sbrian  "Run a subshell", "shell|! [sh command]"},
74336285Sbrian  {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT,
74431372Sbrian  "Show status and stats", "show var"},
74536285Sbrian  {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX,
74631372Sbrian  "Enter terminal mode", "term"},
74728679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
74831343Sbrian  "Display this message", "help|? [command]", Commands},
74928679Sbrian  {NULL, NULL, NULL},
7506059Samurai};
7516059Samurai
75228536Sbrianstatic int
75331343SbrianShowEscape(struct cmdargs const *arg)
7546059Samurai{
75536285Sbrian  if (arg->cx->physical->async.cfg.EscMap[32]) {
75636285Sbrian    int code, bit;
75736285Sbrian    const char *sep = "";
7586059Samurai
75926516Sbrian    for (code = 0; code < 32; code++)
76036285Sbrian      if (arg->cx->physical->async.cfg.EscMap[code])
76128679Sbrian	for (bit = 0; bit < 8; bit++)
76236285Sbrian	  if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) {
76336285Sbrian	    prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit);
76436285Sbrian            sep = ", ";
76536285Sbrian          }
76636285Sbrian    prompt_Printf(arg->prompt, "\n");
7676059Samurai  }
76831077Sbrian  return 0;
7696059Samurai}
7706059Samurai
77128679Sbrianstatic int
77236285SbrianShowTimerList(struct cmdargs const *arg)
7736059Samurai{
77436285Sbrian  timer_Show(0, arg->prompt);
77531077Sbrian  return 0;
7766059Samurai}
7776059Samurai
77828679Sbrianstatic int
77931343SbrianShowStopped(struct cmdargs const *arg)
78028327Sbrian{
78136285Sbrian  prompt_Printf(arg->prompt, " Stopped Timer:  LCP: ");
78236285Sbrian  if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load)
78336285Sbrian    prompt_Printf(arg->prompt, "Disabled");
78428327Sbrian  else
78536285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
78636285Sbrian                  arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS);
78728461Sbrian
78836285Sbrian  prompt_Printf(arg->prompt, ", CCP: ");
78936285Sbrian  if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load)
79036285Sbrian    prompt_Printf(arg->prompt, "Disabled");
79128461Sbrian  else
79236285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
79336285Sbrian                  arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS);
79428461Sbrian
79536285Sbrian  prompt_Printf(arg->prompt, "\n");
79628461Sbrian
79731077Sbrian  return 0;
79828327Sbrian}
79928327Sbrian
80028679Sbrianstatic int
80131343SbrianShowVersion(struct cmdargs const *arg)
8026059Samurai{
80351026Sbrian  prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, __DATE__);
80431077Sbrian  return 0;
8056059Samurai}
8066059Samurai
80728679Sbrianstatic int
80836285SbrianShowProtocolStats(struct cmdargs const *arg)
80926326Sbrian{
81036285Sbrian  struct link *l = command_ChooseLink(arg);
81126326Sbrian
81236285Sbrian  prompt_Printf(arg->prompt, "%s:\n", l->name);
81336285Sbrian  link_ReportProtocolStatus(l, arg->prompt);
81431077Sbrian  return 0;
81526326Sbrian}
81626326Sbrian
81730715Sbrianstatic struct cmdtab const ShowCommands[] = {
81836285Sbrian  {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH,
81936285Sbrian  "bundle details", "show bundle"},
82036285Sbrian  {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT,
82136285Sbrian  "CCP status", "show cpp"},
82236285Sbrian  {"compress", NULL, sl_Show, LOCAL_AUTH,
82336285Sbrian  "VJ compression stats", "show compress"},
82436285Sbrian  {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX,
82536285Sbrian  "escape characters", "show escape"},
82636285Sbrian  {"filter", NULL, filter_Show, LOCAL_AUTH,
82736285Sbrian  "packet filters", "show filter [in|out|dial|alive]"},
82836285Sbrian  {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX,
82936285Sbrian  "HDLC errors", "show hdlc"},
83040561Sbrian  {"iface", "interface", iface_Show, LOCAL_AUTH,
83140561Sbrian  "Interface status", "show iface"},
83236285Sbrian  {"ipcp", NULL, ipcp_Show, LOCAL_AUTH,
83336285Sbrian  "IPCP status", "show ipcp"},
83447211Sbrian  {"layers", NULL, link_ShowLayers, LOCAL_AUTH | LOCAL_CX_OPT,
83547211Sbrian  "Protocol layers", "show layers"},
83636285Sbrian  {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX,
83736285Sbrian  "LCP status", "show lcp"},
83836285Sbrian  {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX,
83936285Sbrian  "(high-level) link info", "show link"},
84036285Sbrian  {"links", NULL, bundle_ShowLinks, LOCAL_AUTH,
84136285Sbrian  "available link names", "show links"},
84236285Sbrian  {"log", NULL, log_ShowLevel, LOCAL_AUTH,
84336285Sbrian  "log levels", "show log"},
84436285Sbrian  {"mem", NULL, mbuf_Show, LOCAL_AUTH,
84536285Sbrian  "mbuf allocations", "show mem"},
84646686Sbrian  {"physical", NULL, physical_ShowStatus, LOCAL_AUTH | LOCAL_CX,
84746686Sbrian  "(low-level) link info", "show physical"},
84836285Sbrian  {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH,
84936285Sbrian  "multilink setup", "show mp"},
85036285Sbrian  {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT,
85136285Sbrian  "protocol summary", "show proto"},
85236285Sbrian  {"route", NULL, route_Show, LOCAL_AUTH,
85336285Sbrian  "routing table", "show route"},
85436285Sbrian  {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX,
85536285Sbrian  "STOPPED timeout", "show stopped"},
85636285Sbrian  {"timers", NULL, ShowTimerList, LOCAL_AUTH,
85736285Sbrian  "alarm timers", "show timers"},
85828679Sbrian  {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH,
85936285Sbrian  "version string", "show version"},
86036285Sbrian  {"who", NULL, log_ShowWho, LOCAL_AUTH,
86136285Sbrian  "client list", "show who"},
86228679Sbrian  {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH,
86331343Sbrian  "Display this message", "show help|? [command]", ShowCommands},
86428679Sbrian  {NULL, NULL, NULL},
8656059Samurai};
8666059Samurai
86730715Sbrianstatic struct cmdtab const *
86831343SbrianFindCommand(struct cmdtab const *cmds, const char *str, int *pmatch)
8696059Samurai{
87026516Sbrian  int nmatch;
87126516Sbrian  int len;
87228679Sbrian  struct cmdtab const *found;
8736059Samurai
87426516Sbrian  found = NULL;
87526516Sbrian  len = strlen(str);
87626516Sbrian  nmatch = 0;
8776059Samurai  while (cmds->func) {
87825566Sbrian    if (cmds->name && strncasecmp(str, cmds->name, len) == 0) {
87926516Sbrian      if (cmds->name[len] == '\0') {
88028679Sbrian	*pmatch = 1;
88128679Sbrian	return cmds;
88226516Sbrian      }
8836059Samurai      nmatch++;
8846059Samurai      found = cmds;
88528679Sbrian    } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) {
88626516Sbrian      if (cmds->alias[len] == '\0') {
88728679Sbrian	*pmatch = 1;
88828679Sbrian	return cmds;
88926516Sbrian      }
8906059Samurai      nmatch++;
8916059Samurai      found = cmds;
8926059Samurai    }
8936059Samurai    cmds++;
8946059Samurai  }
8956059Samurai  *pmatch = nmatch;
89626516Sbrian  return found;
8976059Samurai}
8986059Samurai
89936285Sbrianstatic const char *
90036285SbrianmkPrefix(int argc, char const *const *argv, char *tgt, int sz)
90136285Sbrian{
90236285Sbrian  int f, tlen, len;
90336285Sbrian
90436285Sbrian  tlen = 0;
90536285Sbrian  for (f = 0; f < argc && tlen < sz - 2; f++) {
90636285Sbrian    if (f)
90736285Sbrian      tgt[tlen++] = ' ';
90836285Sbrian    len = strlen(argv[f]);
90936285Sbrian    if (len > sz - tlen - 1)
91036285Sbrian      len = sz - tlen - 1;
91136285Sbrian    strncpy(tgt+tlen, argv[f], len);
91236285Sbrian    tlen += len;
91336285Sbrian  }
91436285Sbrian  tgt[tlen] = '\0';
91536285Sbrian  return tgt;
91636285Sbrian}
91736285Sbrian
91830715Sbrianstatic int
91936285SbrianFindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn,
92036285Sbrian         char const *const *argv, struct prompt *prompt, struct datalink *cx)
9216059Samurai{
92228679Sbrian  struct cmdtab const *cmd;
9236059Samurai  int val = 1;
9246059Samurai  int nmatch;
92531343Sbrian  struct cmdargs arg;
92636285Sbrian  char prefix[100];
9276059Samurai
92836285Sbrian  cmd = FindCommand(cmds, argv[argn], &nmatch);
9296059Samurai  if (nmatch > 1)
93036285Sbrian    log_Printf(LogWARN, "%s: Ambiguous command\n",
93136285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
93236285Sbrian  else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) {
93336285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
93436285Sbrian      /* We've got no context, but we require it */
93536285Sbrian      cx = bundle2datalink(bundle, NULL);
93636285Sbrian
93736285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
93836285Sbrian      log_Printf(LogWARN, "%s: No context (use the `link' command)\n",
93936285Sbrian                mkPrefix(argn+1, argv, prefix, sizeof prefix));
94036285Sbrian    else {
94136285Sbrian      if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
94236285Sbrian        log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n",
94336285Sbrian                  mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name);
94436285Sbrian        cx = NULL;
94536285Sbrian      }
94636285Sbrian      arg.cmdtab = cmds;
94736285Sbrian      arg.cmd = cmd;
94836285Sbrian      arg.argc = argc;
94936285Sbrian      arg.argn = argn+1;
95036285Sbrian      arg.argv = argv;
95136285Sbrian      arg.bundle = bundle;
95236285Sbrian      arg.cx = cx;
95336285Sbrian      arg.prompt = prompt;
95436285Sbrian      val = (*cmd->func) (&arg);
95536285Sbrian    }
95631343Sbrian  } else
95736285Sbrian    log_Printf(LogWARN, "%s: Invalid command\n",
95836285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
95926516Sbrian
96026516Sbrian  if (val == -1)
96136285Sbrian    log_Printf(LogWARN, "Usage: %s\n", cmd->syntax);
96228679Sbrian  else if (val)
96336285Sbrian    log_Printf(LogWARN, "%s: Failed %d\n",
96436285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix), val);
96526516Sbrian
96626516Sbrian  return val;
9676059Samurai}
9686059Samurai
96937009Sbrianint
97058045Sbriancommand_Expand_Interpret(char *buff, int nb, char *argv[MAXARGS], int offset)
97158045Sbrian{
97258045Sbrian  char buff2[LINE_LEN-offset];
97358045Sbrian
97458045Sbrian  InterpretArg(buff, buff2);
97558045Sbrian  strncpy(buff, buff2, LINE_LEN - offset - 1);
97658045Sbrian  buff[LINE_LEN - offset - 1] = '\0';
97758045Sbrian
97858045Sbrian  return command_Interpret(buff, nb, argv);
97958045Sbrian}
98058045Sbrian
98158045Sbrianint
98237009Sbriancommand_Interpret(char *buff, int nb, char *argv[MAXARGS])
9836059Samurai{
9846059Samurai  char *cp;
9856059Samurai
9866059Samurai  if (nb > 0) {
9876059Samurai    cp = buff + strcspn(buff, "\r\n");
9886059Samurai    if (cp)
9896059Samurai      *cp = '\0';
99055145Sbrian    return MakeArgs(buff, argv, MAXARGS, PARSE_REDUCE);
99137009Sbrian  }
99237009Sbrian  return 0;
99331121Sbrian}
9946059Samurai
99531822Sbrianstatic int
99631822Sbrianarghidden(int argc, char const *const *argv, int n)
99731822Sbrian{
99831822Sbrian  /* Is arg n of the given command to be hidden from the log ? */
99931828Sbrian
100031828Sbrian  /* set authkey xxxxx */
100131828Sbrian  /* set key xxxxx */
100231822Sbrian  if (n == 2 && !strncasecmp(argv[0], "se", 2) &&
100331822Sbrian      (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2)))
100431822Sbrian    return 1;
100531822Sbrian
100631828Sbrian  /* passwd xxxxx */
100731828Sbrian  if (n == 1 && !strncasecmp(argv[0], "p", 1))
100831828Sbrian    return 1;
100931828Sbrian
101036285Sbrian  /* set server port xxxxx .... */
101136285Sbrian  if (n == 3 && !strncasecmp(argv[0], "se", 2) &&
101236285Sbrian      !strncasecmp(argv[1], "se", 2))
101336285Sbrian    return 1;
101436285Sbrian
101531822Sbrian  return 0;
101631822Sbrian}
101731822Sbrian
101831121Sbrianvoid
101936285Sbriancommand_Run(struct bundle *bundle, int argc, char const *const *argv,
102037008Sbrian           struct prompt *prompt, const char *label, struct datalink *cx)
102131121Sbrian{
102231156Sbrian  if (argc > 0) {
102336285Sbrian    if (log_IsKept(LogCOMMAND)) {
102447844Sbrian      char buf[LINE_LEN];
102531156Sbrian      int f, n;
102631156Sbrian
102731156Sbrian      if (label) {
102831962Sbrian        strncpy(buf, label, sizeof buf - 3);
102931962Sbrian        buf[sizeof buf - 3] = '\0';
103031156Sbrian        strcat(buf, ": ");
103147844Sbrian        n = strlen(buf);
103247844Sbrian      } else {
103347844Sbrian        *buf = '\0';
103447844Sbrian        n = 0;
103531156Sbrian      }
103647844Sbrian      buf[sizeof buf - 1] = '\0';	/* In case we run out of room in buf */
103747844Sbrian
103831156Sbrian      for (f = 0; f < argc; f++) {
103931962Sbrian        if (n < sizeof buf - 1 && f)
104031156Sbrian          buf[n++] = ' ';
104131822Sbrian        if (arghidden(argc, argv, f))
104236285Sbrian          strncpy(buf+n, "********", sizeof buf - n - 1);
104331822Sbrian        else
104431962Sbrian          strncpy(buf+n, argv[f], sizeof buf - n - 1);
104531156Sbrian        n += strlen(buf+n);
104631156Sbrian      }
104736285Sbrian      log_Printf(LogCOMMAND, "%s\n", buf);
104831156Sbrian    }
104937008Sbrian    FindExec(bundle, Commands, argc, 0, argv, prompt, cx);
105031156Sbrian  }
10516059Samurai}
10526059Samurai
105354914Sbrianint
105436285Sbriancommand_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt,
105536285Sbrian              const char *label)
105631121Sbrian{
105731121Sbrian  int argc;
105837009Sbrian  char *argv[MAXARGS];
105931121Sbrian
106058045Sbrian  if ((argc = command_Expand_Interpret(buff, nb, argv, 0)) < 0)
106154914Sbrian    return 0;
106254914Sbrian
106337008Sbrian  command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL);
106454914Sbrian  return 1;
106531121Sbrian}
106631121Sbrian
10676059Samuraistatic int
106831343SbrianShowCommand(struct cmdargs const *arg)
10696059Samurai{
107036285Sbrian  if (!arg->prompt)
107136285Sbrian    log_Printf(LogWARN, "show: Cannot show without a prompt\n");
107236285Sbrian  else if (arg->argc > arg->argn)
107336285Sbrian    FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv,
107436285Sbrian             arg->prompt, arg->cx);
10756059Samurai  else
107636285Sbrian    prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n");
107726516Sbrian
107826516Sbrian  return 0;
10796059Samurai}
10806059Samurai
10816059Samuraistatic int
108231343SbrianTerminalCommand(struct cmdargs const *arg)
10836059Samurai{
108436285Sbrian  if (!arg->prompt) {
108536285Sbrian    log_Printf(LogWARN, "term: Need a prompt\n");
108626516Sbrian    return 1;
10876059Samurai  }
108836285Sbrian
108936285Sbrian  if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) {
109036285Sbrian    prompt_Printf(arg->prompt, "LCP state is [%s]\n",
109136285Sbrian                  State2Nam(arg->cx->physical->link.lcp.fsm.state));
109236285Sbrian    return 1;
10936059Samurai  }
109436285Sbrian
109536285Sbrian  datalink_Up(arg->cx, 0, 0);
109636285Sbrian  prompt_TtyTermMode(arg->prompt, arg->cx);
109736285Sbrian  return 0;
10986059Samurai}
10996059Samurai
11006059Samuraistatic int
110131343SbrianQuitCommand(struct cmdargs const *arg)
11026059Samurai{
110336285Sbrian  if (!arg->prompt || prompt_IsController(arg->prompt) ||
110436285Sbrian      (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") &&
110536285Sbrian       (arg->prompt->auth & LOCAL_AUTH)))
110636285Sbrian    Cleanup(EX_NORMAL);
110736285Sbrian  if (arg->prompt)
110836285Sbrian    prompt_Destroy(arg->prompt, 1);
110926516Sbrian
111026516Sbrian  return 0;
11116059Samurai}
11126059Samurai
11136059Samuraistatic int
111436285SbrianOpenCommand(struct cmdargs const *arg)
11156059Samurai{
111637160Sbrian  if (arg->argc == arg->argn)
111737993Sbrian    bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
111837160Sbrian  else if (arg->argc == arg->argn + 1) {
111937160Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
112037385Sbrian      struct datalink *cx = arg->cx ?
112137385Sbrian        arg->cx : bundle2datalink(arg->bundle, NULL);
112237385Sbrian      if (cx) {
112337385Sbrian        if (cx->physical->link.lcp.fsm.state == ST_OPENED)
112437385Sbrian          fsm_Reopen(&cx->physical->link.lcp.fsm);
112537160Sbrian        else
112637993Sbrian          bundle_Open(arg->bundle, cx->name, PHYS_ALL, 1);
112737160Sbrian      } else
112837160Sbrian        log_Printf(LogWARN, "open lcp: You must specify a link\n");
112937160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
113037160Sbrian      struct fsm *fp;
11316059Samurai
113237210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
113337160Sbrian      if (fp->link->lcp.fsm.state != ST_OPENED)
113437160Sbrian        log_Printf(LogWARN, "open: LCP must be open before opening CCP\n");
113537160Sbrian      else if (fp->state == ST_OPENED)
113637160Sbrian        fsm_Reopen(fp);
113737160Sbrian      else {
113837160Sbrian        fp->open_mode = 0;	/* Not passive any more */
113937160Sbrian        if (fp->state == ST_STOPPED) {
114037160Sbrian          fsm_Down(fp);
114137160Sbrian          fsm_Up(fp);
114237160Sbrian        } else {
114337160Sbrian          fsm_Up(fp);
114437160Sbrian          fsm_Open(fp);
114537160Sbrian        }
114636285Sbrian      }
114737160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) {
114837160Sbrian      if (arg->cx)
114937160Sbrian        log_Printf(LogWARN, "open ipcp: You need not specify a link\n");
115037160Sbrian      if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
115137160Sbrian        fsm_Reopen(&arg->bundle->ncp.ipcp.fsm);
115237160Sbrian      else
115337993Sbrian        bundle_Open(arg->bundle, NULL, PHYS_ALL, 1);
115437160Sbrian    } else
115537160Sbrian      return -1;
115636285Sbrian  } else
115736285Sbrian    return -1;
115836285Sbrian
115926516Sbrian  return 0;
11606059Samurai}
11616059Samurai
116225067Sbrianstatic int
116336285SbrianCloseCommand(struct cmdargs const *arg)
11646059Samurai{
116537007Sbrian  if (arg->argc == arg->argn)
116637007Sbrian    bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN);
116737007Sbrian  else if (arg->argc == arg->argn + 1) {
116837007Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp"))
116937007Sbrian      bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP);
117037007Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "ccp") ||
117137007Sbrian             !strcasecmp(arg->argv[arg->argn], "ccp!")) {
117237007Sbrian      struct fsm *fp;
11736059Samurai
117437210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
117537007Sbrian      if (fp->state == ST_OPENED) {
117637007Sbrian        fsm_Close(fp);
117737007Sbrian        if (arg->argv[arg->argn][3] == '!')
117837007Sbrian          fp->open_mode = 0;		/* Stay ST_CLOSED */
117937007Sbrian        else
118037007Sbrian          fp->open_mode = OPEN_PASSIVE;	/* Wait for the peer to start */
118137007Sbrian      }
118237007Sbrian    } else
118336285Sbrian      return -1;
118436285Sbrian  } else
118536285Sbrian    return -1;
118636285Sbrian
118736285Sbrian  return 0;
11886059Samurai}
11896059Samurai
119025067Sbrianstatic int
119136285SbrianDownCommand(struct cmdargs const *arg)
119211336Samurai{
119337018Sbrian  if (arg->argc == arg->argn) {
119437018Sbrian      if (arg->cx)
119537018Sbrian        datalink_Down(arg->cx, CLOSE_STAYDOWN);
119637018Sbrian      else
119737018Sbrian        bundle_Down(arg->bundle, CLOSE_STAYDOWN);
119837018Sbrian  } else if (arg->argc == arg->argn + 1) {
119937018Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
120037018Sbrian      if (arg->cx)
120137018Sbrian        datalink_Down(arg->cx, CLOSE_LCP);
120237018Sbrian      else
120337018Sbrian        bundle_Down(arg->bundle, CLOSE_LCP);
120437018Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
120537018Sbrian      struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm :
120637018Sbrian                                 &arg->bundle->ncp.mp.link.ccp.fsm;
120737060Sbrian      fsm2initial(fp);
120837018Sbrian    } else
120937018Sbrian      return -1;
121036285Sbrian  } else
121136285Sbrian    return -1;
121236285Sbrian
121336285Sbrian  return 0;
121425067Sbrian}
121525067Sbrian
121625067Sbrianstatic int
121736285SbrianSetModemSpeed(struct cmdargs const *arg)
121825067Sbrian{
121936285Sbrian  long speed;
122036285Sbrian  char *end;
122111336Samurai
122236285Sbrian  if (arg->argc > arg->argn && *arg->argv[arg->argn]) {
122336285Sbrian    if (arg->argc > arg->argn+1) {
122454917Sbrian      log_Printf(LogWARN, "SetModemSpeed: Too many arguments\n");
122536285Sbrian      return -1;
122611336Samurai    }
122736285Sbrian    if (strcasecmp(arg->argv[arg->argn], "sync") == 0) {
122836285Sbrian      physical_SetSync(arg->cx->physical);
122936285Sbrian      return 0;
123036285Sbrian    }
123136285Sbrian    end = NULL;
123236285Sbrian    speed = strtol(arg->argv[arg->argn], &end, 10);
123336285Sbrian    if (*end) {
123436285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"",
123536285Sbrian                arg->argv[arg->argn]);
123636285Sbrian      return -1;
123736285Sbrian    }
123836285Sbrian    if (physical_SetSpeed(arg->cx->physical, speed))
123936285Sbrian      return 0;
124036285Sbrian    log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]);
124136285Sbrian  } else
124236285Sbrian    log_Printf(LogWARN, "SetModemSpeed: No speed specified\n");
124324939Sbrian
124426516Sbrian  return -1;
124511336Samurai}
124611336Samurai
124725067Sbrianstatic int
124831343SbrianSetStoppedTimeout(struct cmdargs const *arg)
124928327Sbrian{
125036285Sbrian  struct link *l = &arg->cx->physical->link;
125136285Sbrian
125236285Sbrian  l->lcp.fsm.StoppedTimer.load = 0;
125336285Sbrian  l->ccp.fsm.StoppedTimer.load = 0;
125436285Sbrian  if (arg->argc <= arg->argn+2) {
125536285Sbrian    if (arg->argc > arg->argn) {
125636285Sbrian      l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS;
125736285Sbrian      if (arg->argc > arg->argn+1)
125836285Sbrian        l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS;
125928461Sbrian    }
126028327Sbrian    return 0;
126128327Sbrian  }
126228327Sbrian  return -1;
126328327Sbrian}
126428327Sbrian
126528327Sbrianstatic int
126631343SbrianSetServer(struct cmdargs const *arg)
126726940Sbrian{
126826940Sbrian  int res = -1;
126926940Sbrian
127036285Sbrian  if (arg->argc > arg->argn && arg->argc < arg->argn+4) {
127131081Sbrian    const char *port, *passwd, *mask;
127253125Sbrian    int mlen;
127331081Sbrian
127431081Sbrian    /* What's what ? */
127536285Sbrian    port = arg->argv[arg->argn];
127636285Sbrian    if (arg->argc == arg->argn + 2) {
127736285Sbrian      passwd = arg->argv[arg->argn+1];
127836285Sbrian      mask = NULL;
127936285Sbrian    } else if (arg->argc == arg->argn + 3) {
128036285Sbrian      passwd = arg->argv[arg->argn+1];
128136285Sbrian      mask = arg->argv[arg->argn+2];
128253125Sbrian      mlen = strlen(mask);
128353125Sbrian      if (mlen == 0 || mlen > 4 || strspn(mask, "01234567") != mlen ||
128453125Sbrian          (mlen == 4 && *mask != '0')) {
128553125Sbrian        log_Printf(LogWARN, "%s %s: %s: Invalid mask\n",
128653125Sbrian                   arg->argv[arg->argn - 2], arg->argv[arg->argn - 1], mask);
128731081Sbrian        return -1;
128853125Sbrian      }
128936285Sbrian    } else if (strcasecmp(port, "none") == 0) {
129071657Sbrian      if (server_Clear(arg->bundle))
129171657Sbrian        log_Printf(LogPHASE, "Disabled server socket\n");
129271657Sbrian      return 0;
129371657Sbrian    } else if (strcasecmp(port, "open") == 0) {
129471657Sbrian      switch (server_Reopen(arg->bundle)) {
129571657Sbrian        case SERVER_OK:
129671657Sbrian          return 0;
129771657Sbrian        case SERVER_FAILED:
129871657Sbrian          log_Printf(LogPHASE, "Failed to reopen server port\n");
129971657Sbrian          return 1;
130071657Sbrian        case SERVER_UNSET:
130171657Sbrian          log_Printf(LogPHASE, "Cannot reopen unset server socket\n");
130271657Sbrian          return 1;
130371657Sbrian        default:
130471657Sbrian          break;
130571657Sbrian      }
130671657Sbrian      return -1;
130771657Sbrian    } else if (strcasecmp(port, "closed") == 0) {
130836285Sbrian      if (server_Close(arg->bundle))
130971657Sbrian        log_Printf(LogPHASE, "Closed server socket\n");
131071657Sbrian      else
131171657Sbrian        log_Printf(LogWARN, "Server socket not open\n");
131271657Sbrian
131336285Sbrian      return 0;
131431081Sbrian    } else
131536285Sbrian      return -1;
131631081Sbrian
131771657Sbrian    strncpy(server.cfg.passwd, passwd, sizeof server.cfg.passwd - 1);
131871657Sbrian    server.cfg.passwd[sizeof server.cfg.passwd - 1] = '\0';
131931081Sbrian
132036285Sbrian    if (*port == '/') {
132131081Sbrian      mode_t imask;
132236285Sbrian      char *ptr, name[LINE_LEN + 12];
132328679Sbrian
132453125Sbrian      if (mask == NULL)
132531081Sbrian        imask = (mode_t)-1;
132653125Sbrian      else for (imask = mlen = 0; mask[mlen]; mlen++)
132753125Sbrian        imask = (imask * 8) + mask[mlen] - '0';
132836285Sbrian
132936285Sbrian      ptr = strstr(port, "%d");
133036285Sbrian      if (ptr) {
133136285Sbrian        snprintf(name, sizeof name, "%.*s%d%s",
133237210Sbrian                 (int)(ptr - port), port, arg->bundle->unit, ptr + 2);
133336285Sbrian        port = name;
133436285Sbrian      }
133536285Sbrian      res = server_LocalOpen(arg->bundle, port, imask);
133627346Sbrian    } else {
133736285Sbrian      int iport, add = 0;
133828679Sbrian
133931081Sbrian      if (mask != NULL)
134031081Sbrian        return -1;
134128679Sbrian
134236285Sbrian      if (*port == '+') {
134336285Sbrian        port++;
134436285Sbrian        add = 1;
134536285Sbrian      }
134631081Sbrian      if (strspn(port, "0123456789") != strlen(port)) {
134731081Sbrian        struct servent *s;
134831081Sbrian
134931081Sbrian        if ((s = getservbyname(port, "tcp")) == NULL) {
135031081Sbrian	  iport = 0;
135136285Sbrian	  log_Printf(LogWARN, "%s: Invalid port or service\n", port);
135228679Sbrian	} else
135331081Sbrian	  iport = ntohs(s->s_port);
135427346Sbrian      } else
135531081Sbrian        iport = atoi(port);
135636285Sbrian
135736285Sbrian      if (iport) {
135836285Sbrian        if (add)
135936285Sbrian          iport += arg->bundle->unit;
136036285Sbrian        res = server_TcpOpen(arg->bundle, iport);
136136285Sbrian      } else
136236285Sbrian        res = -1;
136327346Sbrian    }
136431081Sbrian  }
136526940Sbrian
136626940Sbrian  return res;
136726940Sbrian}
136826940Sbrian
136926940Sbrianstatic int
137031343SbrianSetEscape(struct cmdargs const *arg)
13716059Samurai{
13726059Samurai  int code;
137336285Sbrian  int argc = arg->argc - arg->argn;
137436285Sbrian  char const *const *argv = arg->argv + arg->argn;
13756059Samurai
13766059Samurai  for (code = 0; code < 33; code++)
137736285Sbrian    arg->cx->physical->async.cfg.EscMap[code] = 0;
137831343Sbrian
13796059Samurai  while (argc-- > 0) {
13806059Samurai    sscanf(*argv++, "%x", &code);
13816059Samurai    code &= 0xff;
138236285Sbrian    arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7));
138336285Sbrian    arg->cx->physical->async.cfg.EscMap[32] = 1;
13846059Samurai  }
138526516Sbrian  return 0;
13866059Samurai}
13876059Samurai
13886059Samuraistatic int
138931343SbrianSetInterfaceAddr(struct cmdargs const *arg)
13906059Samurai{
139136285Sbrian  struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
139232267Sbrian  const char *hisaddr;
139332267Sbrian
139440561Sbrian  if (arg->argc > arg->argn + 4)
139540561Sbrian    return -1;
139640561Sbrian
139732267Sbrian  hisaddr = NULL;
139844874Sbrian  memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range);
139944874Sbrian  memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
140036285Sbrian  ipcp->cfg.HaveTriggerAddress = 0;
140136285Sbrian  ipcp->cfg.netmask.s_addr = INADDR_ANY;
140236285Sbrian  iplist_reset(&ipcp->cfg.peer_list);
140328394Sbrian
140436285Sbrian  if (arg->argc > arg->argn) {
140543313Sbrian    if (!ParseAddr(ipcp, arg->argv[arg->argn],
140636285Sbrian                   &ipcp->cfg.my_range.ipaddr, &ipcp->cfg.my_range.mask,
140736285Sbrian                   &ipcp->cfg.my_range.width))
140828679Sbrian      return 1;
140936285Sbrian    if (arg->argc > arg->argn+1) {
141036285Sbrian      hisaddr = arg->argv[arg->argn+1];
141136285Sbrian      if (arg->argc > arg->argn+2) {
141244455Sbrian        ipcp->ifmask = ipcp->cfg.netmask = GetIpAddr(arg->argv[arg->argn+2]);
141336285Sbrian	if (arg->argc > arg->argn+3) {
141436285Sbrian	  ipcp->cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]);
141536285Sbrian	  ipcp->cfg.HaveTriggerAddress = 1;
14169440Samurai	}
14176059Samurai      }
14186059Samurai    }
14196059Samurai  }
142028394Sbrian
142140561Sbrian  /* 0.0.0.0 means any address (0 bits) */
142236285Sbrian  if (ipcp->cfg.my_range.ipaddr.s_addr == INADDR_ANY) {
142336285Sbrian    ipcp->cfg.my_range.mask.s_addr = INADDR_ANY;
142436285Sbrian    ipcp->cfg.my_range.width = 0;
14256059Samurai  }
142636285Sbrian  ipcp->my_ip.s_addr = ipcp->cfg.my_range.ipaddr.s_addr;
142747648Sbrian  bundle_AdjustFilters(arg->bundle, &ipcp->my_ip, NULL);
142836285Sbrian
142936285Sbrian  if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr,
143036928Sbrian                                  arg->bundle->phys_type.all & PHYS_AUTO))
143132267Sbrian    return 4;
143231121Sbrian
143326516Sbrian  return 0;
14346059Samurai}
14356059Samurai
143618752Sjkhstatic int
143744305SbrianSetRetry(int argc, char const *const *argv, u_int *timeout, u_int *maxreq,
143844305Sbrian          u_int *maxtrm, int def)
143944305Sbrian{
144044305Sbrian  if (argc == 0) {
144144305Sbrian    *timeout = DEF_FSMRETRY;
144244305Sbrian    *maxreq = def;
144344305Sbrian    if (maxtrm != NULL)
144444305Sbrian      *maxtrm = def;
144544305Sbrian  } else {
144644305Sbrian    long l = atol(argv[0]);
144744305Sbrian
144844305Sbrian    if (l < MIN_FSMRETRY) {
144944305Sbrian      log_Printf(LogWARN, "%ld: Invalid FSM retry period - min %d\n",
145044305Sbrian                 l, MIN_FSMRETRY);
145144305Sbrian      return 1;
145244305Sbrian    } else
145344305Sbrian      *timeout = l;
145444305Sbrian
145544305Sbrian    if (argc > 1) {
145644305Sbrian      l = atol(argv[1]);
145744305Sbrian      if (l < 1) {
145844305Sbrian        log_Printf(LogWARN, "%ld: Invalid FSM REQ tries - changed to 1\n", l);
145944305Sbrian        l = 1;
146044305Sbrian      }
146144305Sbrian      *maxreq = l;
146244305Sbrian
146344305Sbrian      if (argc > 2 && maxtrm != NULL) {
146444305Sbrian        l = atol(argv[2]);
146544305Sbrian        if (l < 1) {
146644305Sbrian          log_Printf(LogWARN, "%ld: Invalid FSM TRM tries - changed to 1\n", l);
146744305Sbrian          l = 1;
146844305Sbrian        }
146944305Sbrian        *maxtrm = l;
147044305Sbrian      }
147144305Sbrian    }
147244305Sbrian  }
147344305Sbrian
147444305Sbrian  return 0;
147544305Sbrian}
147644305Sbrian
147744305Sbrianstatic int
147831343SbrianSetVariable(struct cmdargs const *arg)
14796059Samurai{
148037210Sbrian  long long_val, param = (long)arg->cmd->args;
148151048Sbrian  int mode, dummyint, f, first;
148231343Sbrian  const char *argp;
148336285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
148436285Sbrian  const char *err = NULL;
148536285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
148636285Sbrian  struct in_addr dummyaddr, *addr;
14876059Samurai
148836285Sbrian  if (arg->argc > arg->argn)
148936285Sbrian    argp = arg->argv[arg->argn];
149026551Sbrian  else
149131343Sbrian    argp = "";
149226551Sbrian
149336285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
149436285Sbrian    log_Printf(LogWARN, "set %s: No context (use the `link' command)\n",
149536285Sbrian              arg->cmd->name);
149636285Sbrian    return 1;
149736285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
149836285Sbrian    log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n",
149936285Sbrian              arg->cmd->name, cx->name);
150036285Sbrian    cx = NULL;
150136285Sbrian  }
150236285Sbrian
150326551Sbrian  switch (param) {
150428679Sbrian  case VAR_AUTHKEY:
150550139Sbrian    strncpy(arg->bundle->cfg.auth.key, argp,
150650139Sbrian            sizeof arg->bundle->cfg.auth.key - 1);
150750139Sbrian    arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0';
150828679Sbrian    break;
150937210Sbrian
151028679Sbrian  case VAR_AUTHNAME:
151140622Sbrian    switch (bundle_Phase(arg->bundle)) {
151258880Sbrian      default:
151358880Sbrian        log_Printf(LogWARN, "Altering authname while at phase %s\n",
151458880Sbrian                   bundle_PhaseName(arg->bundle));
151558880Sbrian        /* drop through */
151640622Sbrian      case PHASE_DEAD:
151740622Sbrian      case PHASE_ESTABLISH:
151840622Sbrian        strncpy(arg->bundle->cfg.auth.name, argp,
151940622Sbrian                sizeof arg->bundle->cfg.auth.name - 1);
152040622Sbrian        arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name-1] = '\0';
152140622Sbrian        break;
152236285Sbrian    }
152328679Sbrian    break;
152437210Sbrian
152536285Sbrian  case VAR_AUTOLOAD:
152649434Sbrian    if (arg->argc == arg->argn + 3) {
152749434Sbrian      int v1, v2, v3;
152849434Sbrian      char *end;
152949434Sbrian
153049434Sbrian      v1 = strtol(arg->argv[arg->argn], &end, 0);
153149434Sbrian      if (v1 < 0 || *end) {
153249434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid min percentage\n",
153349434Sbrian                   arg->argv[arg->argn]);
153449434Sbrian        return 1;
153536285Sbrian      }
153649434Sbrian
153749434Sbrian      v2 = strtol(arg->argv[arg->argn + 1], &end, 0);
153849434Sbrian      if (v2 < 0 || *end) {
153949434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid max percentage\n",
154049434Sbrian                   arg->argv[arg->argn + 1]);
154149434Sbrian        return 1;
154249434Sbrian      }
154349434Sbrian      if (v2 < v1) {
154449434Sbrian        v3 = v1;
154549434Sbrian        v1 = v2;
154649434Sbrian        v2 = v3;
154749434Sbrian      }
154849434Sbrian
154949434Sbrian      v3 = strtol(arg->argv[arg->argn + 2], &end, 0);
155049434Sbrian      if (v3 <= 0 || *end) {
155149434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid throughput period\n",
155249434Sbrian                   arg->argv[arg->argn + 2]);
155349434Sbrian        return 1;
155449434Sbrian      }
155549434Sbrian
155649434Sbrian      arg->bundle->ncp.mp.cfg.autoload.min = v1;
155749434Sbrian      arg->bundle->ncp.mp.cfg.autoload.max = v2;
155849434Sbrian      arg->bundle->ncp.mp.cfg.autoload.period = v3;
155949434Sbrian      mp_RestartAutoloadTimer(&arg->bundle->ncp.mp);
156036285Sbrian    } else {
156149434Sbrian      err = "Set autoload requires three arguments\n";
156236285Sbrian      log_Printf(LogWARN, err);
156336285Sbrian    }
156436285Sbrian    break;
156537210Sbrian
156628679Sbrian  case VAR_DIAL:
156736285Sbrian    strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1);
156836285Sbrian    cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0';
156928679Sbrian    break;
157037210Sbrian
157128679Sbrian  case VAR_LOGIN:
157236285Sbrian    strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1);
157336285Sbrian    cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0';
157428679Sbrian    break;
157537210Sbrian
157636285Sbrian  case VAR_WINSIZE:
157736285Sbrian    if (arg->argc > arg->argn) {
157836285Sbrian      l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]);
157936285Sbrian      if (l->ccp.cfg.deflate.out.winsize < 8 ||
158036285Sbrian          l->ccp.cfg.deflate.out.winsize > 15) {
158136285Sbrian          log_Printf(LogWARN, "%d: Invalid outgoing window size\n",
158236285Sbrian                    l->ccp.cfg.deflate.out.winsize);
158336285Sbrian          l->ccp.cfg.deflate.out.winsize = 15;
158436285Sbrian      }
158536285Sbrian      if (arg->argc > arg->argn+1) {
158636285Sbrian        l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]);
158736285Sbrian        if (l->ccp.cfg.deflate.in.winsize < 8 ||
158836285Sbrian            l->ccp.cfg.deflate.in.winsize > 15) {
158936285Sbrian            log_Printf(LogWARN, "%d: Invalid incoming window size\n",
159036285Sbrian                      l->ccp.cfg.deflate.in.winsize);
159136285Sbrian            l->ccp.cfg.deflate.in.winsize = 15;
159236285Sbrian        }
159336285Sbrian      } else
159436285Sbrian        l->ccp.cfg.deflate.in.winsize = 0;
159536285Sbrian    } else {
159636285Sbrian      err = "No window size specified\n";
159736285Sbrian      log_Printf(LogWARN, err);
159836285Sbrian    }
159936285Sbrian    break;
160037210Sbrian
160167910Sbrian#ifdef HAVE_DES
160267910Sbrian  case VAR_KEYBITS:
160367910Sbrian    if (arg->argc > arg->argn) {
160467910Sbrian      l->ccp.cfg.mppe.keybits = atoi(arg->argv[arg->argn]);
160567910Sbrian      if (l->ccp.cfg.mppe.keybits != 40 &&
160667910Sbrian          l->ccp.cfg.mppe.keybits != 56 &&
160767910Sbrian          l->ccp.cfg.mppe.keybits != 128 ) {
160867910Sbrian        log_Printf(LogWARN, "%d: Invalid bits number\n",
160967910Sbrian                  l->ccp.cfg.mppe.keybits);
161067910Sbrian        l->ccp.cfg.mppe.keybits = 40;
161167910Sbrian      }
161267910Sbrian    } else {
161367910Sbrian      err = "No bits number pecified\n";
161467910Sbrian      log_Printf(LogWARN, err);
161567910Sbrian    }
161667910Sbrian    break;
161767910Sbrian#endif
161867910Sbrian
161928679Sbrian  case VAR_DEVICE:
162036285Sbrian    physical_SetDeviceList(cx->physical, arg->argc - arg->argn,
162136285Sbrian                           arg->argv + arg->argn);
162236285Sbrian    break;
162337210Sbrian
162436285Sbrian  case VAR_ACCMAP:
162536285Sbrian    if (arg->argc > arg->argn) {
162637210Sbrian      u_long ulong_val;
162736285Sbrian      sscanf(argp, "%lx", &ulong_val);
162837210Sbrian      cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val;
162936285Sbrian    } else {
163036285Sbrian      err = "No accmap specified\n";
163136285Sbrian      log_Printf(LogWARN, err);
163236285Sbrian    }
163336285Sbrian    break;
163437210Sbrian
163536285Sbrian  case VAR_MODE:
163636285Sbrian    mode = Nam2mode(argp);
163736285Sbrian    if (mode == PHYS_NONE || mode == PHYS_ALL) {
163836285Sbrian      log_Printf(LogWARN, "%s: Invalid mode\n", argp);
163936285Sbrian      return -1;
164036285Sbrian    }
164136285Sbrian    bundle_SetMode(arg->bundle, cx, mode);
164236285Sbrian    break;
164337210Sbrian
164436285Sbrian  case VAR_MRRU:
164540622Sbrian    switch (bundle_Phase(arg->bundle)) {
164640622Sbrian      case PHASE_DEAD:
164740622Sbrian        break;
164840622Sbrian      case PHASE_ESTABLISH:
164940622Sbrian        /* Make sure none of our links are DATALINK_LCP or greater */
165040622Sbrian        if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
165140622Sbrian          log_Printf(LogWARN, "mrru: Only changable before LCP negotiations\n");
165240622Sbrian          return 1;
165340622Sbrian        }
165440622Sbrian        break;
165540622Sbrian      default:
165640622Sbrian        log_Printf(LogWARN, "mrru: Only changable at phase DEAD/ESTABLISH\n");
165740622Sbrian        return 1;
165829696Sbrian    }
165937210Sbrian    long_val = atol(argp);
166037210Sbrian    if (long_val && long_val < MIN_MRU) {
166137210Sbrian      log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU);
166237210Sbrian      return 1;
166337210Sbrian    } else if (long_val > MAX_MRU) {
166437210Sbrian      log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU);
166537210Sbrian      return 1;
166637210Sbrian    } else
166737210Sbrian      arg->bundle->ncp.mp.cfg.mrru = long_val;
166828679Sbrian    break;
166937210Sbrian
167036285Sbrian  case VAR_MRU:
167137210Sbrian    long_val = atol(argp);
167237210Sbrian    if (long_val == 0)
167337210Sbrian      l->lcp.cfg.mru = DEF_MRU;
167437210Sbrian    else if (long_val < MIN_MRU) {
167537210Sbrian      log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU);
167637210Sbrian      return 1;
167737210Sbrian    } else if (long_val > MAX_MRU) {
167837210Sbrian      log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU);
167937210Sbrian      return 1;
168037210Sbrian    } else
168137210Sbrian      l->lcp.cfg.mru = long_val;
168228679Sbrian    break;
168337210Sbrian
168436285Sbrian  case VAR_MTU:
168537210Sbrian    long_val = atol(argp);
168637210Sbrian    if (long_val && long_val < MIN_MTU) {
168737210Sbrian      log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU);
168837210Sbrian      return 1;
168937210Sbrian    } else if (long_val > MAX_MTU) {
169037210Sbrian      log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU);
169137210Sbrian      return 1;
169237210Sbrian    } else
169337210Sbrian      arg->bundle->cfg.mtu = long_val;
169436285Sbrian    break;
169537210Sbrian
169636285Sbrian  case VAR_OPENMODE:
169736285Sbrian    if (strcasecmp(argp, "active") == 0)
169836285Sbrian      cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ?
169936285Sbrian        atoi(arg->argv[arg->argn+1]) : 1;
170036285Sbrian    else if (strcasecmp(argp, "passive") == 0)
170136285Sbrian      cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE;
170236285Sbrian    else {
170336285Sbrian      err = "%s: Invalid openmode\n";
170436285Sbrian      log_Printf(LogWARN, err, argp);
170536285Sbrian    }
170636285Sbrian    break;
170737210Sbrian
170828679Sbrian  case VAR_PHONE:
170936285Sbrian    strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1);
171036285Sbrian    cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0';
171138174Sbrian    cx->phone.alt = cx->phone.next = NULL;
171228679Sbrian    break;
171337210Sbrian
171428679Sbrian  case VAR_HANGUP:
171536285Sbrian    strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1);
171636285Sbrian    cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0';
171728679Sbrian    break;
171837210Sbrian
171961534Sbrian  case VAR_IFQUEUE:
172061534Sbrian    long_val = atol(argp);
172161534Sbrian    arg->bundle->cfg.ifqueue = long_val < 0 ? 0 : long_val;
172261534Sbrian    break;
172361534Sbrian
172452488Sbrian  case VAR_LOGOUT:
172552488Sbrian    strncpy(cx->cfg.script.logout, argp, sizeof cx->cfg.script.logout - 1);
172652488Sbrian    cx->cfg.script.logout[sizeof cx->cfg.script.logout - 1] = '\0';
172752488Sbrian    break;
172852488Sbrian
172936285Sbrian  case VAR_IDLETIMEOUT:
173049978Sbrian    if (arg->argc > arg->argn+2)
173136285Sbrian      err = "Too many idle timeout values\n";
173249978Sbrian    else if (arg->argc == arg->argn)
173349978Sbrian      err = "Too few idle timeout values\n";
173449978Sbrian    else {
173549978Sbrian      int timeout, min;
173649978Sbrian
173749978Sbrian      timeout = atoi(argp);
173849978Sbrian      min = arg->argc == arg->argn + 2 ? atoi(arg->argv[arg->argn + 1]) : -1;
173949978Sbrian      bundle_SetIdleTimer(arg->bundle, timeout, min);
174049978Sbrian    }
174136285Sbrian    if (err)
174236285Sbrian      log_Printf(LogWARN, err);
174329549Sbrian    break;
174437210Sbrian
174536285Sbrian  case VAR_LQRPERIOD:
174637210Sbrian    long_val = atol(argp);
174737210Sbrian    if (long_val < MIN_LQRPERIOD) {
174837210Sbrian      log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n",
174937210Sbrian                 long_val, MIN_LQRPERIOD);
175037210Sbrian      return 1;
175136285Sbrian    } else
175237210Sbrian      l->lcp.cfg.lqrperiod = long_val;
175336285Sbrian    break;
175437210Sbrian
175536285Sbrian  case VAR_LCPRETRY:
175644305Sbrian    return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
175744305Sbrian                    &cx->physical->link.lcp.cfg.fsm.timeout,
175844305Sbrian                    &cx->physical->link.lcp.cfg.fsm.maxreq,
175944305Sbrian                    &cx->physical->link.lcp.cfg.fsm.maxtrm, DEF_FSMTRIES);
176036285Sbrian    break;
176137210Sbrian
176236285Sbrian  case VAR_CHAPRETRY:
176344305Sbrian    return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
176444305Sbrian                    &cx->chap.auth.cfg.fsm.timeout,
176544305Sbrian                    &cx->chap.auth.cfg.fsm.maxreq, NULL, DEF_FSMAUTHTRIES);
176636285Sbrian    break;
176737210Sbrian
176836285Sbrian  case VAR_PAPRETRY:
176944305Sbrian    return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
177044305Sbrian                    &cx->pap.cfg.fsm.timeout, &cx->pap.cfg.fsm.maxreq,
177144305Sbrian                    NULL, DEF_FSMAUTHTRIES);
177236285Sbrian    break;
177337210Sbrian
177436285Sbrian  case VAR_CCPRETRY:
177544305Sbrian    return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
177644305Sbrian                    &l->ccp.cfg.fsm.timeout, &l->ccp.cfg.fsm.maxreq,
177744305Sbrian                    &l->ccp.cfg.fsm.maxtrm, DEF_FSMTRIES);
177836285Sbrian    break;
177937210Sbrian
178036285Sbrian  case VAR_IPCPRETRY:
178144305Sbrian    return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
178244305Sbrian                    &arg->bundle->ncp.ipcp.cfg.fsm.timeout,
178344305Sbrian                    &arg->bundle->ncp.ipcp.cfg.fsm.maxreq,
178444305Sbrian                    &arg->bundle->ncp.ipcp.cfg.fsm.maxtrm, DEF_FSMTRIES);
178536285Sbrian    break;
178637210Sbrian
178736285Sbrian  case VAR_NBNS:
178836285Sbrian  case VAR_DNS:
178958044Sbrian    if (param == VAR_DNS) {
179036285Sbrian      addr = arg->bundle->ncp.ipcp.cfg.ns.dns;
179158044Sbrian      addr[0].s_addr = addr[1].s_addr = INADDR_NONE;
179258044Sbrian    } else {
179336285Sbrian      addr = arg->bundle->ncp.ipcp.cfg.ns.nbns;
179458044Sbrian      addr[0].s_addr = addr[1].s_addr = INADDR_ANY;
179558044Sbrian    }
179636285Sbrian
179736285Sbrian    if (arg->argc > arg->argn) {
179843313Sbrian      ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn],
179936285Sbrian                addr, &dummyaddr, &dummyint);
180036285Sbrian      if (arg->argc > arg->argn+1)
180143313Sbrian        ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn + 1],
180236285Sbrian                  addr + 1, &dummyaddr, &dummyint);
180336285Sbrian
180458044Sbrian      if (addr[0].s_addr == INADDR_ANY) {
180536285Sbrian        addr[0].s_addr = addr[1].s_addr;
180658044Sbrian        addr[1].s_addr = INADDR_ANY;
180758044Sbrian      }
180858044Sbrian      if (addr[0].s_addr == INADDR_NONE) {
180958044Sbrian        addr[0].s_addr = addr[1].s_addr;
181058044Sbrian        addr[1].s_addr = INADDR_NONE;
181158044Sbrian      }
181236285Sbrian    }
181336285Sbrian    break;
181438174Sbrian
181538174Sbrian  case VAR_CALLBACK:
181638174Sbrian    cx->cfg.callback.opmask = 0;
181738174Sbrian    for (dummyint = arg->argn; dummyint < arg->argc; dummyint++) {
181838174Sbrian      if (!strcasecmp(arg->argv[dummyint], "auth"))
181938174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_AUTH);
182038174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "cbcp"))
182138174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_CBCP);
182238174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "e.164")) {
182338174Sbrian        if (dummyint == arg->argc - 1)
182438174Sbrian          log_Printf(LogWARN, "No E.164 arg (E.164 ignored) !\n");
182538174Sbrian        else {
182638174Sbrian          cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_E164);
182738174Sbrian          strncpy(cx->cfg.callback.msg, arg->argv[++dummyint],
182838174Sbrian                  sizeof cx->cfg.callback.msg - 1);
182938174Sbrian          cx->cfg.callback.msg[sizeof cx->cfg.callback.msg - 1] = '\0';
183038174Sbrian        }
183138174Sbrian      } else if (!strcasecmp(arg->argv[dummyint], "none"))
183238174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_NONE);
183338174Sbrian      else
183438174Sbrian        return -1;
183538174Sbrian    }
183638174Sbrian    if (cx->cfg.callback.opmask == CALLBACK_BIT(CALLBACK_NONE))
183738174Sbrian      cx->cfg.callback.opmask = 0;
183838174Sbrian    break;
183938174Sbrian
184038174Sbrian  case VAR_CBCP:
184138174Sbrian    cx->cfg.cbcp.delay = 0;
184238174Sbrian    *cx->cfg.cbcp.phone = '\0';
184338174Sbrian    cx->cfg.cbcp.fsmretry = DEF_FSMRETRY;
184438174Sbrian    if (arg->argc > arg->argn) {
184538174Sbrian      strncpy(cx->cfg.cbcp.phone, arg->argv[arg->argn],
184638174Sbrian              sizeof cx->cfg.cbcp.phone - 1);
184738174Sbrian      cx->cfg.cbcp.phone[sizeof cx->cfg.cbcp.phone - 1] = '\0';
184838174Sbrian      if (arg->argc > arg->argn + 1) {
184938174Sbrian        cx->cfg.cbcp.delay = atoi(arg->argv[arg->argn + 1]);
185038174Sbrian        if (arg->argc > arg->argn + 2) {
185138174Sbrian          long_val = atol(arg->argv[arg->argn + 2]);
185238174Sbrian          if (long_val < MIN_FSMRETRY)
185338174Sbrian            log_Printf(LogWARN, "%ld: Invalid CBCP FSM retry period - min %d\n",
185438174Sbrian                       long_val, MIN_FSMRETRY);
185538174Sbrian          else
185638174Sbrian            cx->cfg.cbcp.fsmretry = long_val;
185738174Sbrian        }
185838174Sbrian      }
185938174Sbrian    }
186038174Sbrian    break;
186138544Sbrian
186238544Sbrian  case VAR_CHOKED:
186338544Sbrian    arg->bundle->cfg.choked.timeout = atoi(argp);
186438544Sbrian    if (arg->bundle->cfg.choked.timeout <= 0)
186538544Sbrian      arg->bundle->cfg.choked.timeout = CHOKED_TIMEOUT;
186638544Sbrian    break;
186740665Sbrian
186840665Sbrian  case VAR_SENDPIPE:
186940665Sbrian    long_val = atol(argp);
187040665Sbrian    arg->bundle->ncp.ipcp.cfg.sendpipe = long_val;
187140665Sbrian    break;
187240665Sbrian
187340665Sbrian  case VAR_RECVPIPE:
187440665Sbrian    long_val = atol(argp);
187540665Sbrian    arg->bundle->ncp.ipcp.cfg.recvpipe = long_val;
187640665Sbrian    break;
187743313Sbrian
187843313Sbrian#ifndef NORADIUS
187943313Sbrian  case VAR_RADIUS:
188043313Sbrian    if (!*argp)
188143313Sbrian      *arg->bundle->radius.cfg.file = '\0';
188243313Sbrian    else if (access(argp, R_OK)) {
188343313Sbrian      log_Printf(LogWARN, "%s: %s\n", argp, strerror(errno));
188443313Sbrian      return 1;
188543313Sbrian    } else {
188643313Sbrian      strncpy(arg->bundle->radius.cfg.file, argp,
188743313Sbrian              sizeof arg->bundle->radius.cfg.file - 1);
188843313Sbrian      arg->bundle->radius.cfg.file
188943313Sbrian        [sizeof arg->bundle->radius.cfg.file - 1] = '\0';
189043313Sbrian    }
189143313Sbrian    break;
189243313Sbrian#endif
189344073Sbrian
189444073Sbrian  case VAR_CD:
189544073Sbrian    if (*argp) {
189651699Sbrian      if (strcasecmp(argp, "off")) {
189751699Sbrian        long_val = atol(argp);
189851699Sbrian        if (long_val < 0)
189951699Sbrian          long_val = 0;
190051699Sbrian        cx->physical->cfg.cd.delay = long_val;
190151699Sbrian        cx->physical->cfg.cd.necessity = argp[strlen(argp)-1] == '!' ?
190251699Sbrian          CD_REQUIRED : CD_VARIABLE;
190351699Sbrian      } else
190451699Sbrian        cx->physical->cfg.cd.necessity = CD_NOTREQUIRED;
190544073Sbrian    } else {
190653733Sbrian      cx->physical->cfg.cd.delay = 0;
190753733Sbrian      cx->physical->cfg.cd.necessity = CD_DEFAULT;
190844073Sbrian    }
190944073Sbrian    break;
191036285Sbrian
191146686Sbrian  case VAR_PARITY:
191246686Sbrian    if (arg->argc == arg->argn + 1)
191346686Sbrian      return physical_SetParity(arg->cx->physical, argp);
191446686Sbrian    else {
191546686Sbrian      err = "Parity value must be odd, even or none\n";
191646686Sbrian      log_Printf(LogWARN, err);
191746686Sbrian    }
191846686Sbrian    break;
19196059Samurai
192046686Sbrian  case VAR_CRTSCTS:
192146686Sbrian    if (strcasecmp(argp, "on") == 0)
192236285Sbrian      physical_SetRtsCts(arg->cx->physical, 1);
192346686Sbrian    else if (strcasecmp(argp, "off") == 0)
192436285Sbrian      physical_SetRtsCts(arg->cx->physical, 0);
192546686Sbrian    else {
192646686Sbrian      err = "RTS/CTS value must be on or off\n";
192746686Sbrian      log_Printf(LogWARN, err);
192846686Sbrian    }
192946686Sbrian    break;
193050867Sbrian
193150867Sbrian  case VAR_URGENTPORTS:
193251048Sbrian    if (arg->argn == arg->argc) {
193361430Sbrian      ipcp_SetUrgentTOS(&arg->bundle->ncp.ipcp);
193451048Sbrian      ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp);
193551048Sbrian      ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp);
193651048Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "udp")) {
193761430Sbrian      ipcp_SetUrgentTOS(&arg->bundle->ncp.ipcp);
193851048Sbrian      if (arg->argn == arg->argc - 1)
193951048Sbrian        ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp);
194051048Sbrian      else for (f = arg->argn + 1; f < arg->argc; f++)
194151048Sbrian        if (*arg->argv[f] == '+')
194251048Sbrian          ipcp_AddUrgentUdpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f] + 1));
194351048Sbrian        else if (*arg->argv[f] == '-')
194451048Sbrian          ipcp_RemoveUrgentUdpPort(&arg->bundle->ncp.ipcp,
194551048Sbrian                                   atoi(arg->argv[f] + 1));
194651048Sbrian        else {
194751048Sbrian          if (f == arg->argn)
194851048Sbrian            ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp);
194951048Sbrian          ipcp_AddUrgentUdpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f]));
195051048Sbrian        }
195161430Sbrian    } else if (arg->argn == arg->argc - 1 &&
195261430Sbrian               !strcasecmp(arg->argv[arg->argn], "none")) {
195361430Sbrian      ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp);
195461430Sbrian      ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp);
195561430Sbrian      ipcp_ClearUrgentTOS(&arg->bundle->ncp.ipcp);
195651048Sbrian    } else {
195761430Sbrian      ipcp_SetUrgentTOS(&arg->bundle->ncp.ipcp);
195851048Sbrian      first = arg->argn;
195951048Sbrian      if (!strcasecmp(arg->argv[first], "tcp") && ++first == arg->argc)
196051048Sbrian        ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp);
196151048Sbrian
196251048Sbrian      for (f = first; f < arg->argc; f++)
196351048Sbrian        if (*arg->argv[f] == '+')
196451048Sbrian          ipcp_AddUrgentTcpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f] + 1));
196551048Sbrian        else if (*arg->argv[f] == '-')
196651048Sbrian          ipcp_RemoveUrgentTcpPort(&arg->bundle->ncp.ipcp,
196751048Sbrian                                   atoi(arg->argv[f] + 1));
196851048Sbrian        else {
196951048Sbrian          if (f == first)
197051048Sbrian            ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp);
197151048Sbrian          ipcp_AddUrgentTcpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f]));
197251048Sbrian        }
197351048Sbrian    }
197450867Sbrian    break;
197520812Sjkh  }
197646686Sbrian
197746686Sbrian  return err ? 1 : 0;
197820812Sjkh}
197920812Sjkh
198030715Sbrianstatic struct cmdtab const SetCommands[] = {
198136285Sbrian  {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
198236285Sbrian  "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP},
198328679Sbrian  {"authkey", "key", SetVariable, LOCAL_AUTH,
198436285Sbrian  "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY},
198528679Sbrian  {"authname", NULL, SetVariable, LOCAL_AUTH,
198636285Sbrian  "authentication name", "set authname name", (const void *)VAR_AUTHNAME},
198736285Sbrian  {"autoload", NULL, SetVariable, LOCAL_AUTH,
198836285Sbrian  "auto link [de]activation", "set autoload maxtime maxload mintime minload",
198936285Sbrian  (const void *)VAR_AUTOLOAD},
199050867Sbrian  {"bandwidth", NULL, mp_SetDatalinkBandwidth, LOCAL_AUTH | LOCAL_CX,
199150867Sbrian  "datalink bandwidth", "set bandwidth value"},
199238174Sbrian  {"callback", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
199338174Sbrian  "callback control", "set callback [none|auth|cbcp|"
199438174Sbrian  "E.164 *|number[,number]...]...", (const void *)VAR_CALLBACK},
199538174Sbrian  {"cbcp", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
199638174Sbrian  "CBCP control", "set cbcp [*|phone[,phone...] [delay [timeout]]]",
199738174Sbrian  (const void *)VAR_CBCP},
199844305Sbrian  {"ccpretry", "ccpretries", SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
199944305Sbrian   "CCP retries", "set ccpretry value [attempts]", (const void *)VAR_CCPRETRY},
200044073Sbrian  {"cd", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "Carrier delay requirement",
200144073Sbrian   "set cd value[!]", (const void *)VAR_CD},
200244305Sbrian  {"chapretry", "chapretries", SetVariable, LOCAL_AUTH | LOCAL_CX,
200344305Sbrian   "CHAP retries", "set chapretry value [attempts]",
200444305Sbrian   (const void *)VAR_CHAPRETRY},
200538544Sbrian  {"choked", NULL, SetVariable, LOCAL_AUTH,
200638544Sbrian  "choked timeout", "set choked [secs]", (const void *)VAR_CHOKED},
200746686Sbrian  {"ctsrts", "crtscts", SetVariable, LOCAL_AUTH | LOCAL_CX,
200846686Sbrian   "Use hardware flow control", "set ctsrts [on|off]",
200946686Sbrian   (const char *)VAR_CRTSCTS},
201036285Sbrian  {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
201136285Sbrian  "deflate window sizes", "set deflate out-winsize in-winsize",
201236285Sbrian  (const void *) VAR_WINSIZE},
201367910Sbrian#ifdef HAVE_DES
201467910Sbrian  {"mppe", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
201567910Sbrian  "MPPE key size", "set mppe {40|56|128}",
201667910Sbrian  (const void *) VAR_KEYBITS},
201767910Sbrian#endif
201836285Sbrian  {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX,
201946686Sbrian  "physical device name", "set device|line device-name[,device-name]",
202036285Sbrian  (const void *) VAR_DEVICE},
202136285Sbrian  {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
202236285Sbrian  "dialing script", "set dial chat-script", (const void *) VAR_DIAL},
202336285Sbrian  {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server",
202436285Sbrian  "set dns pri-addr [sec-addr]", (const void *)VAR_DNS},
202536285Sbrian  {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH,
202636285Sbrian  "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]"},
202736285Sbrian  {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX,
202836285Sbrian  "escape characters", "set escape hex-digit ..."},
202936285Sbrian  {"filter", NULL, filter_Set, LOCAL_AUTH,
203036285Sbrian  "packet filters", "set filter alive|dial|in|out rule-no permit|deny "
203149388Sbrian  "[src_addr[/width]] [dst_addr[/width]] [tcp|udp|icmp|ospf|igmp "
203248142Sbrian  "[src [lt|eq|gt port]] [dst [lt|eq|gt port]] [estab] [syn] [finrst]]"},
203336285Sbrian  {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
203436285Sbrian  "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
203536285Sbrian  {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address",
203631343Sbrian  "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"},
203761534Sbrian  {"ifqueue", NULL, SetVariable, LOCAL_AUTH, "interface queue",
203861534Sbrian  "set ifqueue packets", (const void *)VAR_IFQUEUE},
203944305Sbrian  {"ipcpretry", "ipcpretries", SetVariable, LOCAL_AUTH, "IPCP retries",
204044305Sbrian   "set ipcpretry value [attempts]", (const void *)VAR_IPCPRETRY},
204144305Sbrian  {"lcpretry", "lcpretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "LCP retries",
204244305Sbrian   "set lcpretry value [attempts]", (const void *)VAR_LCPRETRY},
204336712Sbrian  {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level",
204467916Sbrian  "set log [local] [+|-]all|async|cbcp|ccp|chat|command|connect|debug|dns|hdlc|"
204558033Sbrian  "id0|ipcp|lcp|lqm|phase|physical|sync|tcp/ip|timer|tun..."},
204636285Sbrian  {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
204736285Sbrian  "login script", "set login chat-script", (const void *) VAR_LOGIN},
204852488Sbrian  {"logout", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
204952488Sbrian  "logout script", "set logout chat-script", (const void *) VAR_LOGOUT},
205036285Sbrian  {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
205136285Sbrian  "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD},
205236285Sbrian  {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value",
205336285Sbrian  "set mode interactive|auto|ddial|background", (const void *)VAR_MODE},
205436285Sbrian  {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value",
205536285Sbrian  "set mrru value", (const void *)VAR_MRRU},
205636285Sbrian  {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
205736285Sbrian  "MRU value", "set mru value", (const void *)VAR_MRU},
205836285Sbrian  {"mtu", NULL, SetVariable, LOCAL_AUTH,
205936285Sbrian  "interface MTU value", "set mtu value", (const void *)VAR_MTU},
206036285Sbrian  {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server",
206136285Sbrian  "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS},
206236285Sbrian  {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode",
206336285Sbrian  "set openmode active|passive [secs]", (const void *)VAR_OPENMODE},
206444305Sbrian  {"papretry", "papretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "PAP retries",
206544305Sbrian   "set papretry value [attempts]", (const void *)VAR_PAPRETRY},
206646686Sbrian  {"parity", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "serial parity",
206746686Sbrian   "set parity [odd|even|none]", (const void *)VAR_PARITY},
206836285Sbrian  {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)",
206936285Sbrian  "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE},
207040679Sbrian  {"proctitle", "title", SetProcTitle, LOCAL_AUTH,
207140679Sbrian  "Process title", "set proctitle [value]"},
207243313Sbrian#ifndef NORADIUS
207343313Sbrian  {"radius", NULL, SetVariable, LOCAL_AUTH,
207443313Sbrian  "RADIUS Config", "set radius cfgfile", (const void *)VAR_RADIUS},
207543313Sbrian#endif
207636285Sbrian  {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX,
207736285Sbrian  "Reconnect timeout", "set reconnect value ntries"},
207840665Sbrian  {"recvpipe", NULL, SetVariable, LOCAL_AUTH,
207940665Sbrian  "RECVPIPE value", "set recvpipe value", (const void *)VAR_RECVPIPE},
208036285Sbrian  {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX,
208144468Sbrian  "Redial timeout", "set redial secs[+inc[-incmax]][.next] [attempts]"},
208240665Sbrian  {"sendpipe", NULL, SetVariable, LOCAL_AUTH,
208340665Sbrian  "SENDPIPE value", "set sendpipe value", (const void *)VAR_SENDPIPE},
208471657Sbrian  {"server", "socket", SetServer, LOCAL_AUTH, "diagnostic port",
208571657Sbrian  "set server|socket TcpPort|LocalName|none|open|closed [password [mask]]"},
208636285Sbrian  {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX,
208746686Sbrian  "physical speed", "set speed value|sync"},
208836285Sbrian  {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX,
208936285Sbrian  "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"},
209036285Sbrian  {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout",
209136285Sbrian  "set timeout idletime", (const void *)VAR_IDLETIMEOUT},
209251048Sbrian  {"urgent", NULL, SetVariable, LOCAL_AUTH, "urgent ports",
209351048Sbrian  "set urgent [tcp|udp] [+|-]port...", (const void *)VAR_URGENTPORTS},
209436285Sbrian  {"vj", NULL, ipcp_vjset, LOCAL_AUTH,
209536285Sbrian  "vj values", "set vj slots|slotcomp [value]"},
209628679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
209731343Sbrian  "Display this message", "set help|? [command]", SetCommands},
209828679Sbrian  {NULL, NULL, NULL},
20996059Samurai};
21006059Samurai
21016059Samuraistatic int
210231343SbrianSetCommand(struct cmdargs const *arg)
21036059Samurai{
210436285Sbrian  if (arg->argc > arg->argn)
210536285Sbrian    FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv,
210636285Sbrian             arg->prompt, arg->cx);
210736285Sbrian  else if (arg->prompt)
210836285Sbrian    prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for"
210958044Sbrian	          " syntax help.\n");
21106059Samurai  else
211136285Sbrian    log_Printf(LogWARN, "set command must have arguments\n");
211226516Sbrian
211326516Sbrian  return 0;
21146059Samurai}
21156059Samurai
21166059Samuraistatic int
211731343SbrianAddCommand(struct cmdargs const *arg)
21186059Samurai{
21196059Samurai  struct in_addr dest, gateway, netmask;
212036285Sbrian  int gw, addrs;
21216059Samurai
212236285Sbrian  if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2)
212331598Sbrian    return -1;
212431598Sbrian
212536285Sbrian  addrs = 0;
212636285Sbrian  if (arg->argc == arg->argn+2) {
212736285Sbrian    if (!strcasecmp(arg->argv[arg->argn], "default"))
212836285Sbrian      dest.s_addr = netmask.s_addr = INADDR_ANY;
212931598Sbrian    else {
213036285Sbrian      int width;
213136285Sbrian
213243313Sbrian      if (!ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn],
213336285Sbrian	             &dest, &netmask, &width))
213436285Sbrian        return -1;
213536285Sbrian      if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6))
213636285Sbrian        addrs = ROUTE_DSTMYADDR;
213736285Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7))
213836285Sbrian        addrs = ROUTE_DSTHISADDR;
213958044Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "DNS0", 4))
214058044Sbrian        addrs = ROUTE_DSTDNS0;
214158044Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "DNS1", 4))
214258044Sbrian        addrs = ROUTE_DSTDNS1;
214331598Sbrian    }
214436285Sbrian    gw = 1;
214534536Sbrian  } else {
214636285Sbrian    if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
214736285Sbrian      addrs = ROUTE_DSTMYADDR;
214836285Sbrian      dest = arg->bundle->ncp.ipcp.my_ip;
214936285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
215036285Sbrian      addrs = ROUTE_DSTHISADDR;
215136285Sbrian      dest = arg->bundle->ncp.ipcp.peer_ip;
215258044Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) {
215358044Sbrian      addrs = ROUTE_DSTDNS0;
215458044Sbrian      dest = arg->bundle->ncp.ipcp.ns.dns[0];
215558044Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) {
215658044Sbrian      addrs = ROUTE_DSTDNS1;
215758044Sbrian      dest = arg->bundle->ncp.ipcp.ns.dns[1];
215865263Sbrian    } else {
215936285Sbrian      dest = GetIpAddr(arg->argv[arg->argn]);
216065263Sbrian      if (dest.s_addr == INADDR_NONE) {
216165263Sbrian        log_Printf(LogWARN, "%s: Invalid destination address\n",
216265263Sbrian                   arg->argv[arg->argn]);
216365263Sbrian        return -1;
216465263Sbrian      }
216565263Sbrian    }
216636285Sbrian    netmask = GetIpAddr(arg->argv[arg->argn+1]);
216731598Sbrian    gw = 2;
21686059Samurai  }
216936285Sbrian
217036285Sbrian  if (strcasecmp(arg->argv[arg->argn+gw], "HISADDR") == 0) {
217136285Sbrian    gateway = arg->bundle->ncp.ipcp.peer_ip;
217236285Sbrian    addrs |= ROUTE_GWHISADDR;
217365263Sbrian  } else {
217436285Sbrian    gateway = GetIpAddr(arg->argv[arg->argn+gw]);
217565263Sbrian    if (gateway.s_addr == INADDR_NONE) {
217665263Sbrian      log_Printf(LogWARN, "%s: Invalid gateway address\n",
217765263Sbrian                 arg->argv[arg->argn + gw]);
217865263Sbrian      return -1;
217965263Sbrian    }
218065263Sbrian  }
218136285Sbrian
218236285Sbrian  if (bundle_SetRoute(arg->bundle, RTM_ADD, dest, gateway, netmask,
218343313Sbrian                  arg->cmd->args ? 1 : 0, (addrs & ROUTE_GWHISADDR) ? 1 : 0)
218443313Sbrian      && addrs != ROUTE_STATIC)
218536285Sbrian    route_Add(&arg->bundle->ncp.ipcp.route, addrs, dest, netmask, gateway);
218636285Sbrian
218731598Sbrian  return 0;
21886059Samurai}
21896059Samurai
21906059Samuraistatic int
219131343SbrianDeleteCommand(struct cmdargs const *arg)
21926059Samurai{
219331598Sbrian  struct in_addr dest, none;
219436285Sbrian  int addrs;
21956059Samurai
219636285Sbrian  if (arg->argc == arg->argn+1) {
219736285Sbrian    if(strcasecmp(arg->argv[arg->argn], "all") == 0) {
219836285Sbrian      route_IfDelete(arg->bundle, 0);
219936285Sbrian      route_DeleteAll(&arg->bundle->ncp.ipcp.route);
220036285Sbrian    } else {
220136285Sbrian      addrs = 0;
220236285Sbrian      if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
220336285Sbrian        dest = arg->bundle->ncp.ipcp.my_ip;
220436285Sbrian        addrs = ROUTE_DSTMYADDR;
220536285Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
220636285Sbrian        dest = arg->bundle->ncp.ipcp.peer_ip;
220736285Sbrian        addrs = ROUTE_DSTHISADDR;
220858044Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) {
220958044Sbrian        dest = arg->bundle->ncp.ipcp.ns.dns[0];
221058044Sbrian        addrs = ROUTE_DSTDNS0;
221158044Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) {
221258044Sbrian        dest = arg->bundle->ncp.ipcp.ns.dns[1];
221358044Sbrian        addrs = ROUTE_DSTDNS1;
221436285Sbrian      } else {
221544279Sbrian        dest = GetIpAddr(arg->argv[arg->argn]);
221644279Sbrian        if (dest.s_addr == INADDR_NONE) {
221744279Sbrian          log_Printf(LogWARN, "%s: Invalid IP address\n", arg->argv[arg->argn]);
221844279Sbrian          return -1;
221944279Sbrian        }
222036285Sbrian        addrs = ROUTE_STATIC;
222136285Sbrian      }
222231598Sbrian      none.s_addr = INADDR_ANY;
222336285Sbrian      bundle_SetRoute(arg->bundle, RTM_DELETE, dest, none, none,
222437927Sbrian                      arg->cmd->args ? 1 : 0, 0);
222536285Sbrian      route_Delete(&arg->bundle->ncp.ipcp.route, addrs, dest);
222631598Sbrian    }
222734536Sbrian  } else
222826516Sbrian    return -1;
222926516Sbrian
223026516Sbrian  return 0;
22316059Samurai}
22326059Samurai
223350059Sbrian#ifndef NONAT
223426031Sbrianstatic int
223558867SbrianNatEnable(struct cmdargs const *arg)
223626031Sbrian{
223736285Sbrian  if (arg->argc == arg->argn+1) {
223836285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
223950059Sbrian      if (!arg->bundle->NatEnabled) {
224046686Sbrian        if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
224146686Sbrian          PacketAliasSetAddress(arg->bundle->ncp.ipcp.my_ip);
224250059Sbrian        arg->bundle->NatEnabled = 1;
224346686Sbrian      }
224437191Sbrian      return 0;
224536285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) {
224650059Sbrian      arg->bundle->NatEnabled = 0;
224740561Sbrian      arg->bundle->cfg.opt &= ~OPT_IFACEALIAS;
224840561Sbrian      /* Don't iface_Clear() - there may be manually configured addresses */
224926516Sbrian      return 0;
225026142Sbrian    }
225135449Sbrian  }
225236285Sbrian
225326516Sbrian  return -1;
225426031Sbrian}
225526031Sbrian
225626031Sbrian
225726031Sbrianstatic int
225858867SbrianNatOption(struct cmdargs const *arg)
225926031Sbrian{
226038559Sbrian  long param = (long)arg->cmd->args;
226138559Sbrian
226236285Sbrian  if (arg->argc == arg->argn+1) {
226336285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
226450059Sbrian      if (arg->bundle->NatEnabled) {
226537191Sbrian	PacketAliasSetMode(param, param);
226628679Sbrian	return 0;
226728679Sbrian      }
226850059Sbrian      log_Printf(LogWARN, "nat not enabled\n");
226936285Sbrian    } else if (strcmp(arg->argv[arg->argn], "no") == 0) {
227050059Sbrian      if (arg->bundle->NatEnabled) {
227137191Sbrian	PacketAliasSetMode(0, param);
227228679Sbrian	return 0;
227328679Sbrian      }
227450059Sbrian      log_Printf(LogWARN, "nat not enabled\n");
227528679Sbrian    }
227635449Sbrian  }
227728679Sbrian  return -1;
227826031Sbrian}
227950059Sbrian#endif /* #ifndef NONAT */
228031121Sbrian
228131121Sbrianstatic int
228236285SbrianLinkCommand(struct cmdargs const *arg)
228336285Sbrian{
228436285Sbrian  if (arg->argc > arg->argn+1) {
228536285Sbrian    char namelist[LINE_LEN];
228636285Sbrian    struct datalink *cx;
228736285Sbrian    char *name;
228836285Sbrian    int result = 0;
228936285Sbrian
229036285Sbrian    if (!strcmp(arg->argv[arg->argn], "*")) {
229136285Sbrian      struct datalink *dl;
229236285Sbrian
229336285Sbrian      cx = arg->bundle->links;
229436285Sbrian      while (cx) {
229536285Sbrian        /* Watch it, the command could be a ``remove'' */
229636285Sbrian        dl = cx->next;
229736285Sbrian        FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
229836285Sbrian                 arg->prompt, cx);
229936285Sbrian        for (cx = arg->bundle->links; cx; cx = cx->next)
230036285Sbrian          if (cx == dl)
230136285Sbrian            break;		/* Pointer's still valid ! */
230236285Sbrian      }
230336285Sbrian    } else {
230436285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
230536285Sbrian      namelist[sizeof namelist - 1] = '\0';
230636285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
230736285Sbrian        if (!bundle2datalink(arg->bundle, name)) {
230836285Sbrian          log_Printf(LogWARN, "link: %s: Invalid link name\n", name);
230936285Sbrian          return 1;
231036285Sbrian        }
231136285Sbrian
231236285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
231336285Sbrian      namelist[sizeof namelist - 1] = '\0';
231436285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) {
231536285Sbrian        cx = bundle2datalink(arg->bundle, name);
231636285Sbrian        if (cx)
231736285Sbrian          FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
231836285Sbrian                   arg->prompt, cx);
231936285Sbrian        else {
232036285Sbrian          log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name);
232136285Sbrian          result++;
232236285Sbrian        }
232336285Sbrian      }
232436285Sbrian    }
232536285Sbrian    return result;
232636285Sbrian  }
232736285Sbrian
232836285Sbrian  log_Printf(LogWARN, "Usage: %s\n", arg->cmd->syntax);
232936285Sbrian  return 2;
233036285Sbrian}
233136285Sbrian
233236285Sbrianstruct link *
233336285Sbriancommand_ChooseLink(struct cmdargs const *arg)
233436285Sbrian{
233536285Sbrian  if (arg->cx)
233636285Sbrian    return &arg->cx->physical->link;
233737210Sbrian  else if (!arg->bundle->ncp.mp.cfg.mrru) {
233836285Sbrian    struct datalink *dl = bundle2datalink(arg->bundle, NULL);
233937210Sbrian    if (dl)
234037210Sbrian      return &dl->physical->link;
234136285Sbrian  }
234237210Sbrian  return &arg->bundle->ncp.mp.link;
234336285Sbrian}
234436285Sbrian
234536285Sbrianstatic const char *
234636285Sbrianident_cmd(const char *cmd, unsigned *keep, unsigned *add)
234736285Sbrian{
234836285Sbrian  const char *result;
234936285Sbrian
235036285Sbrian  switch (*cmd) {
235136285Sbrian    case 'A':
235236285Sbrian    case 'a':
235336285Sbrian      result = "accept";
235436285Sbrian      *keep = NEG_MYMASK;
235536285Sbrian      *add = NEG_ACCEPTED;
235636285Sbrian      break;
235736285Sbrian    case 'D':
235836285Sbrian    case 'd':
235936285Sbrian      switch (cmd[1]) {
236036285Sbrian        case 'E':
236136285Sbrian        case 'e':
236236285Sbrian          result = "deny";
236336285Sbrian          *keep = NEG_MYMASK;
236436285Sbrian          *add = 0;
236536285Sbrian          break;
236636285Sbrian        case 'I':
236736285Sbrian        case 'i':
236836285Sbrian          result = "disable";
236936285Sbrian          *keep = NEG_HISMASK;
237036285Sbrian          *add = 0;
237136285Sbrian          break;
237236285Sbrian        default:
237336285Sbrian          return NULL;
237436285Sbrian      }
237536285Sbrian      break;
237636285Sbrian    case 'E':
237736285Sbrian    case 'e':
237836285Sbrian      result = "enable";
237936285Sbrian      *keep = NEG_HISMASK;
238036285Sbrian      *add = NEG_ENABLED;
238136285Sbrian      break;
238236285Sbrian    default:
238336285Sbrian      return NULL;
238436285Sbrian  }
238536285Sbrian
238636285Sbrian  return result;
238736285Sbrian}
238836285Sbrian
238936285Sbrianstatic int
239036285SbrianOptSet(struct cmdargs const *arg)
239136285Sbrian{
239237574Sbrian  int bit = (int)(long)arg->cmd->args;
239336285Sbrian  const char *cmd;
239436285Sbrian  unsigned keep;			/* Keep these bits */
239536285Sbrian  unsigned add;				/* Add these bits */
239636285Sbrian
239736285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
239836285Sbrian    return 1;
239936285Sbrian
240036285Sbrian  if (add)
240136285Sbrian    arg->bundle->cfg.opt |= bit;
240236285Sbrian  else
240336285Sbrian    arg->bundle->cfg.opt &= ~bit;
240436285Sbrian  return 0;
240536285Sbrian}
240636285Sbrian
240736285Sbrianstatic int
240840561SbrianIfaceAliasOptSet(struct cmdargs const *arg)
240940561Sbrian{
241040561Sbrian  unsigned save = arg->bundle->cfg.opt;
241140561Sbrian  int result = OptSet(arg);
241240561Sbrian
241340561Sbrian  if (result == 0)
241450059Sbrian    if (Enabled(arg->bundle, OPT_IFACEALIAS) && !arg->bundle->NatEnabled) {
241540561Sbrian      arg->bundle->cfg.opt = save;
241650059Sbrian      log_Printf(LogWARN, "Cannot enable iface-alias without NAT\n");
241740561Sbrian      result = 2;
241840561Sbrian    }
241940561Sbrian
242040561Sbrian  return result;
242140561Sbrian}
242240561Sbrian
242340561Sbrianstatic int
242436285SbrianNegotiateSet(struct cmdargs const *arg)
242536285Sbrian{
242637210Sbrian  long param = (long)arg->cmd->args;
242736285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
242836285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
242936285Sbrian  const char *cmd;
243036285Sbrian  unsigned keep;			/* Keep these bits */
243136285Sbrian  unsigned add;				/* Add these bits */
243236285Sbrian
243336285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
243436285Sbrian    return 1;
243536285Sbrian
243636285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
243736285Sbrian    log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n",
243836285Sbrian              cmd, arg->cmd->name);
243936285Sbrian    return 2;
244036285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
244136285Sbrian    log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n",
244236285Sbrian              cmd, arg->cmd->name, cx->name);
244336285Sbrian    cx = NULL;
244436285Sbrian  }
244536285Sbrian
244636285Sbrian  switch (param) {
244736285Sbrian    case NEG_ACFCOMP:
244836285Sbrian      cx->physical->link.lcp.cfg.acfcomp &= keep;
244936285Sbrian      cx->physical->link.lcp.cfg.acfcomp |= add;
245036285Sbrian      break;
245144106Sbrian    case NEG_CHAP05:
245244106Sbrian      cx->physical->link.lcp.cfg.chap05 &= keep;
245344106Sbrian      cx->physical->link.lcp.cfg.chap05 |= add;
245436285Sbrian      break;
245544106Sbrian#ifdef HAVE_DES
245644106Sbrian    case NEG_CHAP80:
245744106Sbrian      cx->physical->link.lcp.cfg.chap80nt &= keep;
245844106Sbrian      cx->physical->link.lcp.cfg.chap80nt |= add;
245944106Sbrian      break;
246044106Sbrian    case NEG_CHAP80LM:
246144106Sbrian      cx->physical->link.lcp.cfg.chap80lm &= keep;
246244106Sbrian      cx->physical->link.lcp.cfg.chap80lm |= add;
246344106Sbrian      break;
246467910Sbrian    case NEG_CHAP81:
246567910Sbrian      cx->physical->link.lcp.cfg.chap81 &= keep;
246667910Sbrian      cx->physical->link.lcp.cfg.chap81 |= add;
246767910Sbrian      break;
246867910Sbrian    case NEG_MPPE:
246967910Sbrian      l->ccp.cfg.neg[CCP_NEG_MPPE] &= keep;
247067910Sbrian      l->ccp.cfg.neg[CCP_NEG_MPPE] |= add;
247167910Sbrian      break;
247244106Sbrian#endif
247336285Sbrian    case NEG_DEFLATE:
247436285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep;
247536285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add;
247636285Sbrian      break;
247736285Sbrian    case NEG_DNS:
247836285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep;
247936285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add;
248036285Sbrian      break;
248147858Sbrian    case NEG_ENDDISC:
248247858Sbrian      arg->bundle->ncp.mp.cfg.negenddisc &= keep;
248347858Sbrian      arg->bundle->ncp.mp.cfg.negenddisc |= add;
248447858Sbrian      break;
248536285Sbrian    case NEG_LQR:
248636285Sbrian      cx->physical->link.lcp.cfg.lqr &= keep;
248736285Sbrian      cx->physical->link.lcp.cfg.lqr |= add;
248836285Sbrian      break;
248936285Sbrian    case NEG_PAP:
249036285Sbrian      cx->physical->link.lcp.cfg.pap &= keep;
249136285Sbrian      cx->physical->link.lcp.cfg.pap |= add;
249236285Sbrian      break;
249336285Sbrian    case NEG_PPPDDEFLATE:
249436285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep;
249536285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add;
249636285Sbrian      break;
249736285Sbrian    case NEG_PRED1:
249836285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep;
249936285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] |= add;
250036285Sbrian      break;
250136285Sbrian    case NEG_PROTOCOMP:
250236285Sbrian      cx->physical->link.lcp.cfg.protocomp &= keep;
250336285Sbrian      cx->physical->link.lcp.cfg.protocomp |= add;
250436285Sbrian      break;
250536285Sbrian    case NEG_SHORTSEQ:
250640622Sbrian      switch (bundle_Phase(arg->bundle)) {
250740622Sbrian        case PHASE_DEAD:
250840622Sbrian          break;
250940622Sbrian        case PHASE_ESTABLISH:
251040622Sbrian          /* Make sure none of our links are DATALINK_LCP or greater */
251140622Sbrian          if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
251240622Sbrian            log_Printf(LogWARN, "shortseq: Only changable before"
251340622Sbrian                       " LCP negotiations\n");
251440622Sbrian            return 1;
251540622Sbrian          }
251640622Sbrian          break;
251740622Sbrian        default:
251840622Sbrian          log_Printf(LogWARN, "shortseq: Only changable at phase"
251940622Sbrian                     " DEAD/ESTABLISH\n");
252040622Sbrian          return 1;
252136285Sbrian      }
252240622Sbrian      arg->bundle->ncp.mp.cfg.shortseq &= keep;
252340622Sbrian      arg->bundle->ncp.mp.cfg.shortseq |= add;
252436285Sbrian      break;
252536285Sbrian    case NEG_VJCOMP:
252636285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg &= keep;
252736285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg |= add;
252836285Sbrian      break;
252936285Sbrian  }
253036285Sbrian
253136285Sbrian  return 0;
253236285Sbrian}
253336285Sbrian
253436285Sbrianstatic struct cmdtab const NegotiateCommands[] = {
253562778Sbrian  {"filter-decapsulation", NULL, OptSet, LOCAL_AUTH,
253662778Sbrian  "filter on PPPoUDP payloads", "disable|enable",
253762778Sbrian  (const void *)OPT_FILTERDECAP},
253836285Sbrian  {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids",
253936285Sbrian  "disable|enable", (const void *)OPT_IDCHECK},
254040666Sbrian  {"iface-alias", NULL, IfaceAliasOptSet, LOCAL_AUTH,
254162778Sbrian  "retain interface addresses", "disable|enable",
254262778Sbrian  (const void *)OPT_IFACEALIAS},
254347689Sbrian  {"keep-session", NULL, OptSet, LOCAL_AUTH, "Retain device session leader",
254447689Sbrian  "disable|enable", (const void *)OPT_KEEPSESSION},
254536285Sbrian  {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface",
254636285Sbrian  "disable|enable", (const void *)OPT_LOOPBACK},
254736285Sbrian  {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file",
254836285Sbrian  "disable|enable", (const void *)OPT_PASSWDAUTH},
254940665Sbrian  {"proxy", NULL, OptSet, LOCAL_AUTH, "Create a proxy ARP entry",
255036285Sbrian  "disable|enable", (const void *)OPT_PROXY},
255140665Sbrian  {"proxyall", NULL, OptSet, LOCAL_AUTH, "Proxy ARP for all remote hosts",
255240665Sbrian  "disable|enable", (const void *)OPT_PROXYALL},
255336285Sbrian  {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes",
255436285Sbrian  "disable|enable", (const void *)OPT_SROUTES},
255569303Sbrian  {"tcpmssfixup", "mssfixup", OptSet, LOCAL_AUTH, "Modify MSS options",
255669303Sbrian  "disable|enable", (const void *)OPT_TCPMSSFIXUP},
255736285Sbrian  {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput",
255836285Sbrian  "disable|enable", (const void *)OPT_THROUGHPUT},
255936285Sbrian  {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp",
256036285Sbrian  "disable|enable", (const void *)OPT_UTMP},
256136285Sbrian
256269303Sbrian#define OPT_MAX 11	/* accept/deny allowed below and not above */
256336285Sbrian
256436285Sbrian  {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
256536285Sbrian  "Address & Control field compression", "accept|deny|disable|enable",
256636285Sbrian  (const void *)NEG_ACFCOMP},
256744106Sbrian  {"chap", "chap05", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
256836285Sbrian  "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable",
256944106Sbrian  (const void *)NEG_CHAP05},
257044106Sbrian#ifdef HAVE_DES
257144106Sbrian  {"mschap", "chap80nt", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
257244106Sbrian  "Microsoft (NT) CHAP", "accept|deny|disable|enable",
257344106Sbrian  (const void *)NEG_CHAP80},
257444106Sbrian  {"LANMan", "chap80lm", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
257544106Sbrian  "Microsoft (NT) CHAP", "accept|deny|disable|enable",
257644106Sbrian  (const void *)NEG_CHAP80LM},
257767910Sbrian  {"mschapv2", "chap81", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
257867910Sbrian  "Microsoft CHAP v2", "accept|deny|disable|enable",
257967910Sbrian  (const void *)NEG_CHAP81},
258067910Sbrian  {"mppe", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
258167910Sbrian  "MPPE encryption", "accept|deny|disable|enable",
258267910Sbrian  (const void *)NEG_MPPE},
258344106Sbrian#endif
258436285Sbrian  {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
258536285Sbrian  "Deflate compression", "accept|deny|disable|enable",
258636285Sbrian  (const void *)NEG_DEFLATE},
258736285Sbrian  {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
258836285Sbrian  "Deflate (type 24) compression", "accept|deny|disable|enable",
258936285Sbrian  (const void *)NEG_PPPDDEFLATE},
259036285Sbrian  {"dns", NULL, NegotiateSet, LOCAL_AUTH,
259136285Sbrian  "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS},
259247858Sbrian  {"enddisc", NULL, NegotiateSet, LOCAL_AUTH, "ENDDISC negotiation",
259347858Sbrian  "accept|deny|disable|enable", (const void *)NEG_ENDDISC},
259436285Sbrian  {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
259536285Sbrian  "Link Quality Reports", "accept|deny|disable|enable",
259636285Sbrian  (const void *)NEG_LQR},
259736285Sbrian  {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
259836285Sbrian  "Password Authentication protocol", "accept|deny|disable|enable",
259936285Sbrian  (const void *)NEG_PAP},
260036285Sbrian  {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
260136285Sbrian  "Predictor 1 compression", "accept|deny|disable|enable",
260236285Sbrian  (const void *)NEG_PRED1},
260336285Sbrian  {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
260436285Sbrian  "Protocol field compression", "accept|deny|disable|enable",
260536285Sbrian  (const void *)NEG_PROTOCOMP},
260636285Sbrian  {"shortseq", NULL, NegotiateSet, LOCAL_AUTH,
260736285Sbrian  "MP Short Sequence Numbers", "accept|deny|disable|enable",
260836285Sbrian  (const void *)NEG_SHORTSEQ},
260936285Sbrian  {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH,
261036285Sbrian  "Van Jacobson header compression", "accept|deny|disable|enable",
261136285Sbrian  (const void *)NEG_VJCOMP},
261236285Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
261336285Sbrian  "Display this message", "accept|deny|disable|enable help|? [value]",
261436285Sbrian  NegotiateCommands},
261536285Sbrian  {NULL, NULL, NULL},
261636285Sbrian};
261736285Sbrian
261836285Sbrianstatic int
261936285SbrianNegotiateCommand(struct cmdargs const *arg)
262036285Sbrian{
262136285Sbrian  if (arg->argc > arg->argn) {
262236285Sbrian    char const *argv[3];
262336285Sbrian    unsigned keep, add;
262436285Sbrian    int n;
262536285Sbrian
262636285Sbrian    if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL)
262736285Sbrian      return -1;
262836285Sbrian    argv[2] = NULL;
262936285Sbrian
263036285Sbrian    for (n = arg->argn; n < arg->argc; n++) {
263136285Sbrian      argv[1] = arg->argv[n];
263236285Sbrian      FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ?
263336285Sbrian               0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx);
263436285Sbrian    }
263536285Sbrian  } else if (arg->prompt)
263636285Sbrian    prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n",
263736285Sbrian	    arg->argv[arg->argn-1]);
263836285Sbrian  else
263936285Sbrian    log_Printf(LogWARN, "%s command must have arguments\n",
264036285Sbrian              arg->argv[arg->argn] );
264136285Sbrian
264236285Sbrian  return 0;
264336285Sbrian}
264436285Sbrian
264536285Sbrianconst char *
264636285Sbriancommand_ShowNegval(unsigned val)
264736285Sbrian{
264836285Sbrian  switch (val&3) {
264936285Sbrian    case 1: return "disabled & accepted";
265036285Sbrian    case 2: return "enabled & denied";
265136285Sbrian    case 3: return "enabled & accepted";
265236285Sbrian  }
265336285Sbrian  return "disabled & denied";
265436285Sbrian}
265536934Sbrian
265636934Sbrianstatic int
265736934SbrianClearCommand(struct cmdargs const *arg)
265836934Sbrian{
265936934Sbrian  struct pppThroughput *t;
266036934Sbrian  struct datalink *cx;
266136934Sbrian  int i, clear_type;
266236934Sbrian
266336934Sbrian  if (arg->argc < arg->argn + 1)
266436934Sbrian    return -1;
266536934Sbrian
266646686Sbrian  if (strcasecmp(arg->argv[arg->argn], "physical") == 0) {
266736934Sbrian    cx = arg->cx;
266836934Sbrian    if (!cx)
266936934Sbrian      cx = bundle2datalink(arg->bundle, NULL);
267036934Sbrian    if (!cx) {
267146686Sbrian      log_Printf(LogWARN, "A link must be specified for ``clear physical''\n");
267236934Sbrian      return 1;
267336934Sbrian    }
267464652Sbrian    t = &cx->physical->link.stats.total;
267536934Sbrian  } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0)
267636934Sbrian    t = &arg->bundle->ncp.ipcp.throughput;
267736934Sbrian  else
267836934Sbrian    return -1;
267936934Sbrian
268036934Sbrian  if (arg->argc > arg->argn + 1) {
268136934Sbrian    clear_type = 0;
268236934Sbrian    for (i = arg->argn + 1; i < arg->argc; i++)
268336934Sbrian      if (strcasecmp(arg->argv[i], "overall") == 0)
268436934Sbrian        clear_type |= THROUGHPUT_OVERALL;
268536934Sbrian      else if (strcasecmp(arg->argv[i], "current") == 0)
268636934Sbrian        clear_type |= THROUGHPUT_CURRENT;
268736934Sbrian      else if (strcasecmp(arg->argv[i], "peak") == 0)
268836934Sbrian        clear_type |= THROUGHPUT_PEAK;
268936934Sbrian      else
269036934Sbrian        return -1;
269136934Sbrian  } else
269236934Sbrian    clear_type = THROUGHPUT_ALL;
269336934Sbrian
269436934Sbrian  throughput_clear(t, clear_type, arg->prompt);
269536934Sbrian  return 0;
269636934Sbrian}
269740561Sbrian
269840561Sbrianstatic int
269940561SbrianRunListCommand(struct cmdargs const *arg)
270040561Sbrian{
270140561Sbrian  const char *cmd = arg->argc ? arg->argv[arg->argc - 1] : "???";
270240561Sbrian
270364801Sbrian#ifndef NONAT
270464801Sbrian  if (arg->cmd->args == NatCommands &&
270564801Sbrian      tolower(*arg->argv[arg->argn - 1]) == 'a') {
270664801Sbrian    if (arg->prompt)
270765550Sbrian      prompt_Printf(arg->prompt, "The alias command is deprecated\n");
270864801Sbrian    else
270965550Sbrian      log_Printf(LogWARN, "The alias command is deprecated\n");
271064801Sbrian  }
271164801Sbrian#endif
271264801Sbrian
271340561Sbrian  if (arg->argc > arg->argn)
271440561Sbrian    FindExec(arg->bundle, arg->cmd->args, arg->argc, arg->argn, arg->argv,
271540561Sbrian             arg->prompt, arg->cx);
271640561Sbrian  else if (arg->prompt)
271740561Sbrian    prompt_Printf(arg->prompt, "Use `%s help' to get a list or `%s help"
271840561Sbrian                  " <option>' for syntax help.\n", cmd, cmd);
271940561Sbrian  else
272040561Sbrian    log_Printf(LogWARN, "%s command must have arguments\n", cmd);
272140561Sbrian
272240561Sbrian  return 0;
272340561Sbrian}
272440561Sbrian
272540561Sbrianstatic int
272640561SbrianIfaceAddCommand(struct cmdargs const *arg)
272740561Sbrian{
272840561Sbrian  int bits, n, how;
272940561Sbrian  struct in_addr ifa, mask, brd;
273040561Sbrian
273140664Sbrian  if (arg->argc == arg->argn + 1) {
273243313Sbrian    if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL))
273340561Sbrian      return -1;
273440664Sbrian    mask.s_addr = brd.s_addr = INADDR_BROADCAST;
273540664Sbrian  } else {
273640664Sbrian    if (arg->argc == arg->argn + 2) {
273743313Sbrian      if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, &mask, &bits))
273840664Sbrian        return -1;
273940664Sbrian      n = 1;
274040664Sbrian    } else if (arg->argc == arg->argn + 3) {
274143313Sbrian      if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL))
274240664Sbrian        return -1;
274343313Sbrian      if (!ParseAddr(NULL, arg->argv[arg->argn + 1], &mask, NULL, NULL))
274440664Sbrian        return -1;
274540664Sbrian      n = 2;
274640664Sbrian    } else
274740561Sbrian      return -1;
274840561Sbrian
274943313Sbrian    if (!ParseAddr(NULL, arg->argv[arg->argn + n], &brd, NULL, NULL))
275040664Sbrian      return -1;
275140664Sbrian  }
275240561Sbrian
275340561Sbrian  how = IFACE_ADD_LAST;
275440561Sbrian  if (arg->cmd->args)
275540561Sbrian    how |= IFACE_FORCE_ADD;
275640561Sbrian
275740561Sbrian  return !iface_inAdd(arg->bundle->iface, ifa, mask, brd, how);
275840561Sbrian}
275940561Sbrian
276040561Sbrianstatic int
276140561SbrianIfaceDeleteCommand(struct cmdargs const *arg)
276240561Sbrian{
276340561Sbrian  struct in_addr ifa;
276440561Sbrian  int ok;
276540561Sbrian
276640561Sbrian  if (arg->argc != arg->argn + 1)
276740561Sbrian    return -1;
276840561Sbrian
276943313Sbrian  if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL))
277040561Sbrian    return -1;
277140561Sbrian
277240561Sbrian  if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED &&
277340561Sbrian      arg->bundle->ncp.ipcp.my_ip.s_addr == ifa.s_addr) {
277440561Sbrian    log_Printf(LogWARN, "%s: Cannot remove active interface address\n",
277540561Sbrian               inet_ntoa(ifa));
277640561Sbrian    return 1;
277740561Sbrian  }
277840561Sbrian
277940561Sbrian  ok = iface_inDelete(arg->bundle->iface, ifa);
278040561Sbrian  if (!ok) {
278140561Sbrian    if (arg->cmd->args)
278240561Sbrian      ok = 1;
278340561Sbrian    else if (arg->prompt)
278440561Sbrian      prompt_Printf(arg->prompt, "%s: No such address\n", inet_ntoa(ifa));
278540561Sbrian    else
278640561Sbrian      log_Printf(LogWARN, "%s: No such address\n", inet_ntoa(ifa));
278740561Sbrian  }
278840561Sbrian
278940561Sbrian  return !ok;
279040561Sbrian}
279140561Sbrian
279240561Sbrianstatic int
279340561SbrianIfaceClearCommand(struct cmdargs const *arg)
279440561Sbrian{
279540561Sbrian  int how;
279640561Sbrian
279740561Sbrian  if (arg->argc != arg->argn)
279840561Sbrian    return -1;
279940561Sbrian
280040941Sbrian  how = arg->bundle->ncp.ipcp.fsm.state == ST_OPENED ||
280140941Sbrian        arg->bundle->phys_type.all & PHYS_AUTO ?
280240561Sbrian        IFACE_CLEAR_ALIASES : IFACE_CLEAR_ALL;
280340561Sbrian  iface_Clear(arg->bundle->iface, how);
280440561Sbrian
280540561Sbrian  return 0;
280640561Sbrian}
280740679Sbrian
280840679Sbrianstatic int
280940679SbrianSetProcTitle(struct cmdargs const *arg)
281040679Sbrian{
281140679Sbrian  static char title[LINE_LEN];
281240679Sbrian  char *argv[MAXARGS], *ptr;
281340679Sbrian  int len, remaining, f, argc = arg->argc - arg->argn;
281440679Sbrian
281540679Sbrian  if (arg->argc == arg->argn) {
281664698Sbrian    SetTitle(NULL);
281740679Sbrian    return 0;
281840679Sbrian  }
281940679Sbrian
282040679Sbrian  if (argc >= sizeof argv / sizeof argv[0]) {
282140679Sbrian    argc = sizeof argv / sizeof argv[0] - 1;
282240679Sbrian    log_Printf(LogWARN, "Truncating proc title to %d args\n", argc);
282340679Sbrian  }
282447849Sbrian  command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 1, getpid());
282540679Sbrian
282640679Sbrian  ptr = title;
282740679Sbrian  remaining = sizeof title - 1;
282840679Sbrian  for (f = 0; f < argc && remaining; f++) {
282940679Sbrian    if (f) {
283040679Sbrian      *ptr++ = ' ';
283140679Sbrian      remaining--;
283240679Sbrian    }
283340679Sbrian    len = strlen(argv[f]);
283440679Sbrian    if (len > remaining)
283540679Sbrian      len = remaining;
283640679Sbrian    memcpy(ptr, argv[f], len);
283740679Sbrian    remaining -= len;
283840679Sbrian    ptr += len;
283940679Sbrian  }
284040679Sbrian  *ptr = '\0';
284140679Sbrian
284264698Sbrian  SetTitle(title);
284340679Sbrian
284440679Sbrian  return 0;
284540679Sbrian}
2846