command.c revision 43888
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 *
2043888Sbrian * $Id: command.c,v 1.179 1999/01/28 09:40:15 brian Exp $
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
4439395Sbrian#ifndef NOALIAS
4539395Sbrian#ifdef __OpenBSD__
4639395Sbrian#include "alias.h"
4739395Sbrian#else
4839395Sbrian#include <alias.h>
4939395Sbrian#endif
5039395Sbrian#endif
5137009Sbrian#include "defs.h"
5231343Sbrian#include "command.h"
5330715Sbrian#include "mbuf.h"
5430715Sbrian#include "log.h"
5530715Sbrian#include "timer.h"
566059Samurai#include "fsm.h"
576059Samurai#include "lcp.h"
5831690Sbrian#include "iplist.h"
5936285Sbrian#include "throughput.h"
6036285Sbrian#include "slcompress.h"
6138557Sbrian#include "lqr.h"
6238557Sbrian#include "hdlc.h"
636059Samurai#include "ipcp.h"
646059Samurai#include "modem.h"
6531343Sbrian#ifndef NOALIAS
6626031Sbrian#include "alias_cmd.h"
6731343Sbrian#endif
6825630Sbrian#include "systems.h"
6936285Sbrian#include "filter.h"
7036285Sbrian#include "descriptor.h"
7130715Sbrian#include "main.h"
7230715Sbrian#include "route.h"
7330715Sbrian#include "ccp.h"
7431080Sbrian#include "auth.h"
7536285Sbrian#include "async.h"
7636285Sbrian#include "link.h"
7736285Sbrian#include "physical.h"
7836285Sbrian#include "mp.h"
7943313Sbrian#ifndef NORADIUS
8043313Sbrian#include "radius.h"
8143313Sbrian#endif
8236285Sbrian#include "bundle.h"
8336285Sbrian#include "server.h"
8436285Sbrian#include "prompt.h"
8536285Sbrian#include "chat.h"
8636285Sbrian#include "chap.h"
8738174Sbrian#include "cbcp.h"
8836285Sbrian#include "datalink.h"
8940561Sbrian#include "iface.h"
906059Samurai
9136285Sbrian/* ``set'' values */
9236285Sbrian#define	VAR_AUTHKEY	0
9336285Sbrian#define	VAR_DIAL	1
9436285Sbrian#define	VAR_LOGIN	2
9536285Sbrian#define	VAR_AUTHNAME	3
9636285Sbrian#define	VAR_AUTOLOAD	4
9736285Sbrian#define	VAR_WINSIZE	5
9836285Sbrian#define	VAR_DEVICE	6
9936285Sbrian#define	VAR_ACCMAP	7
10036285Sbrian#define	VAR_MRRU	8
10136285Sbrian#define	VAR_MRU		9
10236285Sbrian#define	VAR_MTU		10
10336285Sbrian#define	VAR_OPENMODE	11
10436285Sbrian#define	VAR_PHONE	12
10536285Sbrian#define	VAR_HANGUP	13
10636285Sbrian#define	VAR_IDLETIMEOUT	14
10736285Sbrian#define	VAR_LQRPERIOD	15
10836285Sbrian#define	VAR_LCPRETRY	16
10936285Sbrian#define	VAR_CHAPRETRY	17
11036285Sbrian#define	VAR_PAPRETRY	18
11136285Sbrian#define	VAR_CCPRETRY	19
11236285Sbrian#define	VAR_IPCPRETRY	20
11336285Sbrian#define	VAR_DNS		21
11436285Sbrian#define	VAR_NBNS	22
11536285Sbrian#define	VAR_MODE	23
11638174Sbrian#define	VAR_CALLBACK	24
11738174Sbrian#define	VAR_CBCP	25
11838544Sbrian#define	VAR_CHOKED	26
11940665Sbrian#define	VAR_SENDPIPE	27
12040665Sbrian#define	VAR_RECVPIPE	28
12143313Sbrian#define	VAR_RADIUS	29
1226059Samurai
12336285Sbrian/* ``accept|deny|disable|enable'' masks */
12436285Sbrian#define NEG_HISMASK (1)
12536285Sbrian#define NEG_MYMASK (2)
12636285Sbrian
12736285Sbrian/* ``accept|deny|disable|enable'' values */
12836285Sbrian#define NEG_ACFCOMP	40
12936285Sbrian#define NEG_CHAP	41
13036285Sbrian#define NEG_DEFLATE	42
13136285Sbrian#define NEG_LQR		43
13236285Sbrian#define NEG_PAP		44
13336285Sbrian#define NEG_PPPDDEFLATE	45
13436285Sbrian#define NEG_PRED1	46
13536285Sbrian#define NEG_PROTOCOMP	47
13636285Sbrian#define NEG_SHORTSEQ	48
13736285Sbrian#define NEG_VJCOMP	49
13836285Sbrian#define NEG_DNS		50
13936285Sbrian
14043333Sbrianconst char Version[] = "2.1";
14143888Sbrianconst char VersionDate[] = "$Date: 1999/01/28 09:40:15 $";
14236285Sbrian
14336285Sbrianstatic int ShowCommand(struct cmdargs const *);
14436285Sbrianstatic int TerminalCommand(struct cmdargs const *);
14536285Sbrianstatic int QuitCommand(struct cmdargs const *);
14636285Sbrianstatic int OpenCommand(struct cmdargs const *);
14736285Sbrianstatic int CloseCommand(struct cmdargs const *);
14836285Sbrianstatic int DownCommand(struct cmdargs const *);
14936285Sbrianstatic int SetCommand(struct cmdargs const *);
15036285Sbrianstatic int LinkCommand(struct cmdargs const *);
15136285Sbrianstatic int AddCommand(struct cmdargs const *);
15236285Sbrianstatic int DeleteCommand(struct cmdargs const *);
15336285Sbrianstatic int NegotiateCommand(struct cmdargs const *);
15436934Sbrianstatic int ClearCommand(struct cmdargs const *);
15540561Sbrianstatic int RunListCommand(struct cmdargs const *);
15640561Sbrianstatic int IfaceAddCommand(struct cmdargs const *);
15740561Sbrianstatic int IfaceDeleteCommand(struct cmdargs const *);
15840561Sbrianstatic int IfaceClearCommand(struct cmdargs const *);
15940679Sbrianstatic int SetProcTitle(struct cmdargs const *);
16031343Sbrian#ifndef NOALIAS
16136285Sbrianstatic int AliasEnable(struct cmdargs const *);
16236285Sbrianstatic int AliasOption(struct cmdargs const *);
16331343Sbrian#endif
1646059Samurai
16536285Sbrianstatic const char *
16636285Sbrianshowcx(struct cmdtab const *cmd)
16736285Sbrian{
16836285Sbrian  if (cmd->lauth & LOCAL_CX)
16936285Sbrian    return "(c)";
17036285Sbrian  else if (cmd->lauth & LOCAL_CX_OPT)
17136285Sbrian    return "(o)";
17236285Sbrian
17336285Sbrian  return "";
17436285Sbrian}
17536285Sbrian
1766059Samuraistatic int
17731343SbrianHelpCommand(struct cmdargs const *arg)
1786059Samurai{
17928679Sbrian  struct cmdtab const *cmd;
18036285Sbrian  int n, cmax, dmax, cols, cxlen;
18136285Sbrian  const char *cx;
1826059Samurai
18336285Sbrian  if (!arg->prompt) {
18436285Sbrian    log_Printf(LogWARN, "help: Cannot help without a prompt\n");
18526516Sbrian    return 0;
18636285Sbrian  }
18726516Sbrian
18836285Sbrian  if (arg->argc > arg->argn) {
18936285Sbrian    for (cmd = arg->cmdtab; cmd->name || cmd->alias; cmd++)
19036285Sbrian      if ((cmd->lauth & arg->prompt->auth) &&
19136285Sbrian          ((cmd->name && !strcasecmp(cmd->name, arg->argv[arg->argn])) ||
19236285Sbrian           (cmd->alias && !strcasecmp(cmd->alias, arg->argv[arg->argn])))) {
19336285Sbrian	prompt_Printf(arg->prompt, "%s %s\n", cmd->syntax, showcx(cmd));
19428679Sbrian	return 0;
1956059Samurai      }
19626516Sbrian    return -1;
1976059Samurai  }
19836285Sbrian
19931372Sbrian  cmax = dmax = 0;
20036285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
20136285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
20236285Sbrian      if ((n = strlen(cmd->name) + strlen(showcx(cmd))) > cmax)
20331372Sbrian        cmax = n;
20431372Sbrian      if ((n = strlen(cmd->helpmes)) > dmax)
20531372Sbrian        dmax = n;
20631372Sbrian    }
20731372Sbrian
20831372Sbrian  cols = 80 / (dmax + cmax + 3);
2096059Samurai  n = 0;
21036285Sbrian  prompt_Printf(arg->prompt, "(o) = Optional context,"
21136285Sbrian                " (c) = Context required\n");
21236285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
21336285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
21436285Sbrian      cx = showcx(cmd);
21536285Sbrian      cxlen = cmax - strlen(cmd->name);
21640482Sbrian      if (n % cols != 0)
21740482Sbrian        prompt_Printf(arg->prompt, " ");
21840482Sbrian      prompt_Printf(arg->prompt, "%s%-*.*s: %-*.*s",
21936285Sbrian              cmd->name, cxlen, cxlen, cx, dmax, dmax, cmd->helpmes);
22031372Sbrian      if (++n % cols == 0)
22136285Sbrian        prompt_Printf(arg->prompt, "\n");
2226059Samurai    }
22331372Sbrian  if (n % cols != 0)
22436285Sbrian    prompt_Printf(arg->prompt, "\n");
22526516Sbrian
22626516Sbrian  return 0;
2276059Samurai}
2286059Samurai
22936285Sbrianstatic int
23036285SbrianCloneCommand(struct cmdargs const *arg)
2316059Samurai{
23236285Sbrian  char namelist[LINE_LEN];
23336285Sbrian  char *name;
23436285Sbrian  int f;
2356059Samurai
23636285Sbrian  if (arg->argc == arg->argn)
23736285Sbrian    return -1;
23836285Sbrian
23936285Sbrian  namelist[sizeof namelist - 1] = '\0';
24036285Sbrian  for (f = arg->argn; f < arg->argc; f++) {
24136285Sbrian    strncpy(namelist, arg->argv[f], sizeof namelist - 1);
24236285Sbrian    for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
24336285Sbrian      bundle_DatalinkClone(arg->bundle, arg->cx, name);
2446059Samurai  }
24536285Sbrian
24636285Sbrian  return 0;
2476059Samurai}
2486059Samurai
2496059Samuraistatic int
25036285SbrianRemoveCommand(struct cmdargs const *arg)
2516059Samurai{
25236285Sbrian  if (arg->argc != arg->argn)
25336285Sbrian    return -1;
25411336Samurai
25536285Sbrian  if (arg->cx->state != DATALINK_CLOSED) {
25636285Sbrian    log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n");
25736285Sbrian    return 2;
2586059Samurai  }
25926516Sbrian
26036285Sbrian  bundle_DatalinkRemove(arg->bundle, arg->cx);
26136285Sbrian  return 0;
26236285Sbrian}
26332711Sbrian
26436285Sbrianstatic int
26536285SbrianRenameCommand(struct cmdargs const *arg)
26636285Sbrian{
26736285Sbrian  if (arg->argc != arg->argn + 1)
26836285Sbrian    return -1;
26931121Sbrian
27036285Sbrian  if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn]))
27136285Sbrian    return 0;
27236285Sbrian
27336285Sbrian  log_Printf(LogWARN, "%s -> %s: target name already exists\n",
27436285Sbrian             arg->cx->name, arg->argv[arg->argn]);
27536285Sbrian  return 1;
27636285Sbrian}
27736285Sbrian
27836285Sbrianint
27936285SbrianLoadCommand(struct cmdargs const *arg)
28036285Sbrian{
28140797Sbrian  const char *err;
28240797Sbrian  int n, mode;
28336285Sbrian
28440797Sbrian  mode = arg->bundle->phys_type.all;
28536285Sbrian
28640797Sbrian  if (arg->argn < arg->argc) {
28740797Sbrian    for (n = arg->argn; n < arg->argc; n++)
28840797Sbrian      if ((err = system_IsValid(arg->argv[n], arg->prompt, mode)) != NULL) {
28940797Sbrian        log_Printf(LogWARN, "%s: %s\n", arg->argv[n], err);
29040797Sbrian        return 1;
29140797Sbrian      }
29240797Sbrian
29340797Sbrian    for (n = arg->argn; n < arg->argc; n++) {
29440797Sbrian      bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
29540797Sbrian      system_Select(arg->bundle, arg->argv[n], CONFFILE, arg->prompt, arg->cx);
29640797Sbrian    }
29740797Sbrian    bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
29840797Sbrian  } else if ((err = system_IsValid("default", arg->prompt, mode)) != NULL) {
29940797Sbrian    log_Printf(LogWARN, "default: %s\n", err);
30036285Sbrian    return 1;
30136285Sbrian  } else {
30240797Sbrian    bundle_SetLabel(arg->bundle, "default");
30340797Sbrian    system_Select(arg->bundle, "default", CONFFILE, arg->prompt, arg->cx);
30440797Sbrian    bundle_SetLabel(arg->bundle, "default");
30536285Sbrian  }
30640797Sbrian
30726516Sbrian  return 0;
3086059Samurai}
3096059Samurai
31036285Sbrianint
31136285SbrianSaveCommand(struct cmdargs const *arg)
31236285Sbrian{
31336285Sbrian  log_Printf(LogWARN, "save command is not implemented (yet).\n");
31436285Sbrian  return 1;
31536285Sbrian}
31636285Sbrian
31710528Samuraistatic int
31836285SbrianDialCommand(struct cmdargs const *arg)
31928536Sbrian{
32036285Sbrian  int res;
32136285Sbrian
32236465Sbrian  if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO)))
32336465Sbrian      || (!arg->cx &&
32436928Sbrian          (arg->bundle->phys_type.all & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) {
32536285Sbrian    log_Printf(LogWARN, "Manual dial is only available for auto and"
32636285Sbrian              " interactive links\n");
32736285Sbrian    return 1;
32834536Sbrian  }
32936285Sbrian
33036285Sbrian  if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0)
33136285Sbrian    return res;
33236285Sbrian
33337993Sbrian  bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
33436285Sbrian
33536285Sbrian  return 0;
33628536Sbrian}
33728536Sbrian
33838628Sbrian#define isinword(ch) (isalnum(ch) || (ch) == '_')
33938628Sbrian
34038628Sbrianstatic char *
34138628Sbrianstrstrword(char *big, const char *little)
34238628Sbrian{
34338628Sbrian  /* Get the first occurance of the word ``little'' in ``big'' */
34438628Sbrian  char *pos;
34538628Sbrian  int len;
34638628Sbrian
34738628Sbrian  pos = big;
34838628Sbrian  len = strlen(little);
34938628Sbrian
35038628Sbrian  while ((pos = strstr(pos, little)) != NULL)
35138628Sbrian    if ((pos == big || !isinword(pos[-1])) && !isinword(pos[len]))
35238628Sbrian      break;
35338628Sbrian    else
35438628Sbrian      pos++;
35538628Sbrian
35638628Sbrian  return pos;
35738628Sbrian}
35838628Sbrian
35938628Sbrianstatic char *
36038628Sbriansubst(char *tgt, const char *oldstr, const char *newstr)
36138628Sbrian{
36238628Sbrian  /* tgt is a malloc()d area... realloc() as necessary */
36338628Sbrian  char *word, *ntgt;
36438628Sbrian  int ltgt, loldstr, lnewstr, pos;
36538628Sbrian
36638628Sbrian  if ((word = strstrword(tgt, oldstr)) == NULL)
36738628Sbrian    return tgt;
36838628Sbrian
36938628Sbrian  ltgt = strlen(tgt) + 1;
37038628Sbrian  loldstr = strlen(oldstr);
37138628Sbrian  lnewstr = strlen(newstr);
37238628Sbrian  do {
37338628Sbrian    pos = word - tgt;
37438628Sbrian    if (loldstr > lnewstr)
37538628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
37638628Sbrian    if (loldstr != lnewstr) {
37738628Sbrian      ntgt = realloc(tgt, ltgt += lnewstr - loldstr);
37838628Sbrian      if (ntgt == NULL)
37938628Sbrian        break;			/* Oh wonderful ! */
38038628Sbrian      word = ntgt + pos;
38138628Sbrian      tgt = ntgt;
38238628Sbrian    }
38338628Sbrian    if (lnewstr > loldstr)
38438628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
38538628Sbrian    bcopy(newstr, word, lnewstr);
38638628Sbrian  } while ((word = strstrword(word, oldstr)));
38738628Sbrian
38838628Sbrian  return tgt;
38938628Sbrian}
39038628Sbrian
39143888Sbrianvoid
39243888Sbriancommand_Expand(char **nargv, int argc, char const *const *oargv,
39343888Sbrian               struct bundle *bundle, int inc0)
39438628Sbrian{
39538628Sbrian  int arg;
39640678Sbrian  char pid[12];
39738628Sbrian
39841755Sbrian  if (inc0)
39941755Sbrian    arg = 0;		/* Start at arg 0 */
40041755Sbrian  else {
40141755Sbrian    nargv[0] = strdup(oargv[0]);
40241755Sbrian    arg = 1;
40341755Sbrian  }
40440678Sbrian  snprintf(pid, sizeof pid, "%d", getpid());
40541755Sbrian  for (; arg < argc; arg++) {
40638629Sbrian    nargv[arg] = strdup(oargv[arg]);
40738629Sbrian    nargv[arg] = subst(nargv[arg], "HISADDR",
40838628Sbrian                       inet_ntoa(bundle->ncp.ipcp.peer_ip));
40938629Sbrian    nargv[arg] = subst(nargv[arg], "AUTHNAME", bundle->cfg.auth.name);
41040561Sbrian    nargv[arg] = subst(nargv[arg], "INTERFACE", bundle->iface->name);
41138628Sbrian    nargv[arg] = subst(nargv[arg], "MYADDR", inet_ntoa(bundle->ncp.ipcp.my_ip));
41238629Sbrian    nargv[arg] = subst(nargv[arg], "USER", bundle->ncp.mp.peer.authname);
41338629Sbrian    nargv[arg] = subst(nargv[arg], "PEER_ENDDISC",
41438629Sbrian                       mp_Enddisc(bundle->ncp.mp.peer.enddisc.class,
41538629Sbrian                                  bundle->ncp.mp.peer.enddisc.address,
41638629Sbrian                                  bundle->ncp.mp.peer.enddisc.len));
41738629Sbrian    nargv[arg] = subst(nargv[arg], "ENDDISC",
41838629Sbrian                       mp_Enddisc(bundle->ncp.mp.cfg.enddisc.class,
41938629Sbrian                                  bundle->ncp.mp.cfg.enddisc.address,
42038629Sbrian                                  bundle->ncp.mp.cfg.enddisc.len));
42140678Sbrian    nargv[arg] = subst(nargv[arg], "PROCESSID", pid);
42238629Sbrian    nargv[arg] = subst(nargv[arg], "LABEL", bundle_GetLabel(bundle));
42338628Sbrian  }
42438628Sbrian  nargv[arg] = NULL;
42538628Sbrian}
42638628Sbrian
42728536Sbrianstatic int
42831343SbrianShellCommand(struct cmdargs const *arg, int bg)
42910528Samurai{
43010528Samurai  const char *shell;
43110528Samurai  pid_t shpid;
43220813Sjkh
43318856Ssos#ifdef SHELL_ONLY_INTERACTIVELY
43426911Sbrian  /* we're only allowed to shell when we run ppp interactively */
43536285Sbrian  if (arg->prompt && arg->prompt->owner) {
43636285Sbrian    log_Printf(LogWARN, "Can't start a shell from a network connection\n");
43726516Sbrian    return 1;
43810528Samurai  }
43926911Sbrian#endif
44028679Sbrian
44136285Sbrian  if (arg->argc == arg->argn) {
44236285Sbrian    if (!arg->prompt) {
44336285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
44436285Sbrian                " a config file\n");
44528381Sbrian      return 1;
44636285Sbrian    } else if (arg->prompt->owner) {
44736285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
44836285Sbrian                " a socket connection\n");
44936285Sbrian      return 1;
45028381Sbrian    } else if (bg) {
45136285Sbrian      log_Printf(LogWARN, "Can only start an interactive shell in"
45228679Sbrian		" the foreground mode\n");
45328381Sbrian      return 1;
45428381Sbrian    }
45534536Sbrian  }
45634536Sbrian
45728679Sbrian  if ((shpid = fork()) == 0) {
45836285Sbrian    int i, fd;
45918531Sbde
46036285Sbrian    if ((shell = getenv("SHELL")) == 0)
46136285Sbrian      shell = _PATH_BSHELL;
46232017Sbrian
46336285Sbrian    timer_TermService();
46436285Sbrian
46536285Sbrian    if (arg->prompt)
46636285Sbrian      fd = arg->prompt->fd_out;
46736285Sbrian    else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
46836285Sbrian      log_Printf(LogALERT, "Failed to open %s: %s\n",
46936285Sbrian                _PATH_DEVNULL, strerror(errno));
47028679Sbrian      exit(1);
47128679Sbrian    }
47228679Sbrian    for (i = 0; i < 3; i++)
47328679Sbrian      dup2(fd, i);
47426516Sbrian
47536285Sbrian    fcntl(3, F_SETFD, 1);	/* Set close-on-exec flag */
47626516Sbrian
47731061Sbrian    setuid(geteuid());
47836285Sbrian    if (arg->argc > arg->argn) {
47928679Sbrian      /* substitute pseudo args */
48038628Sbrian      char *argv[MAXARGS];
48138628Sbrian      int argc = arg->argc - arg->argn;
48238628Sbrian
48338628Sbrian      if (argc >= sizeof argv / sizeof argv[0]) {
48438628Sbrian        argc = sizeof argv / sizeof argv[0] - 1;
48538628Sbrian        log_Printf(LogWARN, "Truncating shell command to %d args\n", argc);
48631343Sbrian      }
48743888Sbrian      command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 0);
48828679Sbrian      if (bg) {
48928679Sbrian	pid_t p;
49010528Samurai
49128679Sbrian	p = getpid();
49228679Sbrian	if (daemon(1, 1) == -1) {
49336832Sbrian	  log_Printf(LogERROR, "%d: daemon: %s\n", (int)p, strerror(errno));
49428679Sbrian	  exit(1);
49528679Sbrian	}
49636285Sbrian      } else if (arg->prompt)
49736285Sbrian        printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]);
49831343Sbrian      execvp(argv[0], argv);
49930316Sbrian    } else {
50036285Sbrian      if (arg->prompt)
50132017Sbrian        printf("ppp: Pausing until %s finishes\n", shell);
50236285Sbrian      prompt_TtyOldMode(arg->prompt);
50331343Sbrian      execl(shell, shell, NULL);
50430316Sbrian    }
50520813Sjkh
50640665Sbrian    log_Printf(LogWARN, "exec() of %s failed: %s\n",
50740665Sbrian              arg->argc > arg->argn ? arg->argv[arg->argn] : shell,
50840665Sbrian              strerror(errno));
50928679Sbrian    exit(255);
51010528Samurai  }
51136285Sbrian
51236285Sbrian  if (shpid == (pid_t) - 1)
51336285Sbrian    log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno));
51436285Sbrian  else {
51510528Samurai    int status;
51631343Sbrian    waitpid(shpid, &status, 0);
51710528Samurai  }
51820813Sjkh
51936285Sbrian  if (arg->prompt && !arg->prompt->owner)
52036285Sbrian    prompt_TtyCommandMode(arg->prompt);
52120813Sjkh
52236285Sbrian  return 0;
52310528Samurai}
52410528Samurai
52531343Sbrianstatic int
52631343SbrianBgShellCommand(struct cmdargs const *arg)
52731343Sbrian{
52836285Sbrian  if (arg->argc == arg->argn)
52931343Sbrian    return -1;
53031343Sbrian  return ShellCommand(arg, 1);
53131343Sbrian}
53231343Sbrian
53331343Sbrianstatic int
53431343SbrianFgShellCommand(struct cmdargs const *arg)
53531343Sbrian{
53631343Sbrian  return ShellCommand(arg, 0);
53731343Sbrian}
53831343Sbrian
53940561Sbrian#ifndef NOALIAS
54040561Sbrianstatic struct cmdtab const AliasCommands[] =
54140561Sbrian{
54240561Sbrian  {"addr", NULL, alias_RedirectAddr, LOCAL_AUTH,
54340561Sbrian   "static address translation", "alias addr [addr_local addr_alias]"},
54440561Sbrian  {"deny_incoming", NULL, AliasOption, LOCAL_AUTH,
54540561Sbrian   "stop incoming connections", "alias deny_incoming [yes|no]",
54640561Sbrian   (const void *) PKT_ALIAS_DENY_INCOMING},
54740561Sbrian  {"enable", NULL, AliasEnable, LOCAL_AUTH,
54840561Sbrian   "enable IP aliasing", "alias enable [yes|no]"},
54940561Sbrian  {"log", NULL, AliasOption, LOCAL_AUTH,
55040561Sbrian   "log aliasing link creation", "alias log [yes|no]",
55140561Sbrian   (const void *) PKT_ALIAS_LOG},
55240561Sbrian  {"port", NULL, alias_RedirectPort, LOCAL_AUTH,
55340561Sbrian   "port redirection", "alias port [proto addr_local:port_local  port_alias]"},
55440561Sbrian  {"same_ports", NULL, AliasOption, LOCAL_AUTH,
55540561Sbrian   "try to leave port numbers unchanged", "alias same_ports [yes|no]",
55640561Sbrian   (const void *) PKT_ALIAS_SAME_PORTS},
55740561Sbrian  {"unregistered_only", NULL, AliasOption, LOCAL_AUTH,
55840561Sbrian   "alias unregistered (private) IP address space only",
55940561Sbrian   "alias unregistered_only [yes|no]",
56040561Sbrian   (const void *) PKT_ALIAS_UNREGISTERED_ONLY},
56140561Sbrian  {"use_sockets", NULL, AliasOption, LOCAL_AUTH,
56240561Sbrian   "allocate host sockets", "alias use_sockets [yes|no]",
56340561Sbrian   (const void *) PKT_ALIAS_USE_SOCKETS},
56440561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
56540561Sbrian   "Display this message", "alias help|? [command]", AliasCommands},
56640561Sbrian  {NULL, NULL, NULL},
56740561Sbrian};
56840561Sbrian#endif
56940561Sbrian
57040561Sbrianstatic struct cmdtab const AllowCommands[] = {
57140561Sbrian  {"modes", "mode", AllowModes, LOCAL_AUTH,
57240561Sbrian  "Only allow certain ppp modes", "allow modes mode..."},
57340561Sbrian  {"users", "user", AllowUsers, LOCAL_AUTH,
57440561Sbrian  "Only allow ppp access to certain users", "allow users logname..."},
57540561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
57640561Sbrian  "Display this message", "allow help|? [command]", AllowCommands},
57740561Sbrian  {NULL, NULL, NULL},
57840561Sbrian};
57940561Sbrian
58040561Sbrianstatic struct cmdtab const IfaceCommands[] =
58140561Sbrian{
58240561Sbrian  {"add", NULL, IfaceAddCommand, LOCAL_AUTH,
58340561Sbrian   "Add iface address", "iface add addr[/bits| mask] peer", NULL},
58440561Sbrian  {NULL, "add!", IfaceAddCommand, LOCAL_AUTH,
58540561Sbrian   "Add or change an iface address", "iface add! addr[/bits| mask] peer",
58640561Sbrian   (void *)1},
58740561Sbrian  {"clear", NULL, IfaceClearCommand, LOCAL_AUTH,
58840561Sbrian   "Clear iface address(es)", "iface clear"},
58940561Sbrian  {"delete", "rm", IfaceDeleteCommand, LOCAL_AUTH,
59040561Sbrian   "Delete iface address", "iface delete addr", NULL},
59140561Sbrian  {NULL, "rm!", IfaceDeleteCommand, LOCAL_AUTH,
59240561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
59340561Sbrian  {NULL, "delete!", IfaceDeleteCommand, LOCAL_AUTH,
59440561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
59540561Sbrian  {"show", NULL, iface_Show, LOCAL_AUTH,
59640561Sbrian   "Show iface address(es)", "iface show"},
59740561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
59840561Sbrian   "Display this message", "alias help|? [command]", IfaceCommands},
59940561Sbrian  {NULL, NULL, NULL},
60040561Sbrian};
60140561Sbrian
60230715Sbrianstatic struct cmdtab const Commands[] = {
60336285Sbrian  {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
60428679Sbrian  "accept option request", "accept option .."},
60528679Sbrian  {"add", NULL, AddCommand, LOCAL_AUTH,
60632109Sbrian  "add route", "add dest mask gateway", NULL},
60736285Sbrian  {NULL, "add!", AddCommand, LOCAL_AUTH,
60832109Sbrian  "add or change route", "add! dest mask gateway", (void *)1},
60936285Sbrian#ifndef NOALIAS
61040561Sbrian  {"alias", NULL, RunListCommand, LOCAL_AUTH,
61140561Sbrian  "alias control", "alias option [yes|no]", AliasCommands},
61236285Sbrian#endif
61340561Sbrian  {"allow", "auth", RunListCommand, LOCAL_AUTH,
61440561Sbrian  "Allow ppp access", "allow users|modes ....", AllowCommands},
61528679Sbrian  {"bg", "!bg", BgShellCommand, LOCAL_AUTH,
61631372Sbrian  "Run a background command", "[!]bg command"},
61736934Sbrian  {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT,
61836934Sbrian  "Clear throughput statistics", "clear ipcp|modem [current|overall|peak]..."},
61936285Sbrian  {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX,
62036285Sbrian  "Clone a link", "clone newname..."},
62136285Sbrian  {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT,
62236285Sbrian  "Close an FSM", "close [lcp|ccp]"},
62328679Sbrian  {"delete", NULL, DeleteCommand, LOCAL_AUTH,
62432109Sbrian  "delete route", "delete dest", NULL},
62536285Sbrian  {NULL, "delete!", DeleteCommand, LOCAL_AUTH,
62632109Sbrian  "delete a route if it exists", "delete! dest", (void *)1},
62736285Sbrian  {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
62828679Sbrian  "Deny option request", "deny option .."},
62936285Sbrian  {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT,
63040797Sbrian  "Dial and login", "dial|call [system ...]", NULL},
63136285Sbrian  {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
63228679Sbrian  "Disable option", "disable option .."},
63336285Sbrian  {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT,
63436285Sbrian  "Generate a down event", "down"},
63536285Sbrian  {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
63628679Sbrian  "Enable option", "enable option .."},
63740561Sbrian  {"iface", "interface", RunListCommand, LOCAL_AUTH,
63840561Sbrian  "interface control", "iface option ...", IfaceCommands},
63936285Sbrian  {"link", "datalink", LinkCommand, LOCAL_AUTH,
64036285Sbrian  "Link specific commands", "link name command ..."},
64137008Sbrian  {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT,
64240797Sbrian  "Load settings", "load [system ...]"},
64336285Sbrian  {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT,
64437955Sbrian  "Open an FSM", "open! [lcp|ccp|ipcp]", (void *)1},
64536285Sbrian  {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH,
64636285Sbrian  "Password for manipulation", "passwd LocalPassword"},
64736285Sbrian  {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
64836285Sbrian  "Quit PPP program", "quit|bye [all]"},
64936285Sbrian  {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX,
65036285Sbrian  "Remove a link", "remove"},
65136285Sbrian  {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX,
65236285Sbrian  "Rename a link", "rename name"},
65328679Sbrian  {"save", NULL, SaveCommand, LOCAL_AUTH,
65428679Sbrian  "Save settings", "save"},
65536285Sbrian  {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT,
65628679Sbrian  "Set parameters", "set[up] var value"},
65728679Sbrian  {"shell", "!", FgShellCommand, LOCAL_AUTH,
65828679Sbrian  "Run a subshell", "shell|! [sh command]"},
65936285Sbrian  {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT,
66031372Sbrian  "Show status and stats", "show var"},
66136285Sbrian  {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX,
66231372Sbrian  "Enter terminal mode", "term"},
66328679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
66431343Sbrian  "Display this message", "help|? [command]", Commands},
66528679Sbrian  {NULL, NULL, NULL},
6666059Samurai};
6676059Samurai
66828536Sbrianstatic int
66931343SbrianShowEscape(struct cmdargs const *arg)
6706059Samurai{
67136285Sbrian  if (arg->cx->physical->async.cfg.EscMap[32]) {
67236285Sbrian    int code, bit;
67336285Sbrian    const char *sep = "";
6746059Samurai
67526516Sbrian    for (code = 0; code < 32; code++)
67636285Sbrian      if (arg->cx->physical->async.cfg.EscMap[code])
67728679Sbrian	for (bit = 0; bit < 8; bit++)
67836285Sbrian	  if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) {
67936285Sbrian	    prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit);
68036285Sbrian            sep = ", ";
68136285Sbrian          }
68236285Sbrian    prompt_Printf(arg->prompt, "\n");
6836059Samurai  }
68431077Sbrian  return 0;
6856059Samurai}
6866059Samurai
68728679Sbrianstatic int
68836285SbrianShowTimerList(struct cmdargs const *arg)
6896059Samurai{
69036285Sbrian  timer_Show(0, arg->prompt);
69131077Sbrian  return 0;
6926059Samurai}
6936059Samurai
69428679Sbrianstatic int
69531343SbrianShowStopped(struct cmdargs const *arg)
69628327Sbrian{
69736285Sbrian  prompt_Printf(arg->prompt, " Stopped Timer:  LCP: ");
69836285Sbrian  if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load)
69936285Sbrian    prompt_Printf(arg->prompt, "Disabled");
70028327Sbrian  else
70136285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
70236285Sbrian                  arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS);
70328461Sbrian
70436285Sbrian  prompt_Printf(arg->prompt, ", CCP: ");
70536285Sbrian  if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load)
70636285Sbrian    prompt_Printf(arg->prompt, "Disabled");
70728461Sbrian  else
70836285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
70936285Sbrian                  arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS);
71028461Sbrian
71136285Sbrian  prompt_Printf(arg->prompt, "\n");
71228461Sbrian
71331077Sbrian  return 0;
71428327Sbrian}
71528327Sbrian
71628679Sbrianstatic int
71731343SbrianShowVersion(struct cmdargs const *arg)
7186059Samurai{
71936285Sbrian  prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, VersionDate);
72031077Sbrian  return 0;
7216059Samurai}
7226059Samurai
72328679Sbrianstatic int
72436285SbrianShowProtocolStats(struct cmdargs const *arg)
72526326Sbrian{
72636285Sbrian  struct link *l = command_ChooseLink(arg);
72726326Sbrian
72836285Sbrian  prompt_Printf(arg->prompt, "%s:\n", l->name);
72936285Sbrian  link_ReportProtocolStatus(l, arg->prompt);
73031077Sbrian  return 0;
73126326Sbrian}
73226326Sbrian
73330715Sbrianstatic struct cmdtab const ShowCommands[] = {
73436285Sbrian  {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH,
73536285Sbrian  "bundle details", "show bundle"},
73636285Sbrian  {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT,
73736285Sbrian  "CCP status", "show cpp"},
73836285Sbrian  {"compress", NULL, sl_Show, LOCAL_AUTH,
73936285Sbrian  "VJ compression stats", "show compress"},
74036285Sbrian  {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX,
74136285Sbrian  "escape characters", "show escape"},
74236285Sbrian  {"filter", NULL, filter_Show, LOCAL_AUTH,
74336285Sbrian  "packet filters", "show filter [in|out|dial|alive]"},
74436285Sbrian  {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX,
74536285Sbrian  "HDLC errors", "show hdlc"},
74640561Sbrian  {"iface", "interface", iface_Show, LOCAL_AUTH,
74740561Sbrian  "Interface status", "show iface"},
74836285Sbrian  {"ipcp", NULL, ipcp_Show, LOCAL_AUTH,
74936285Sbrian  "IPCP status", "show ipcp"},
75036285Sbrian  {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX,
75136285Sbrian  "LCP status", "show lcp"},
75236285Sbrian  {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX,
75336285Sbrian  "(high-level) link info", "show link"},
75436285Sbrian  {"links", NULL, bundle_ShowLinks, LOCAL_AUTH,
75536285Sbrian  "available link names", "show links"},
75636285Sbrian  {"log", NULL, log_ShowLevel, LOCAL_AUTH,
75736285Sbrian  "log levels", "show log"},
75836285Sbrian  {"mem", NULL, mbuf_Show, LOCAL_AUTH,
75936285Sbrian  "mbuf allocations", "show mem"},
76036285Sbrian  {"modem", NULL, modem_ShowStatus, LOCAL_AUTH | LOCAL_CX,
76136285Sbrian  "(low-level) link info", "show modem"},
76236285Sbrian  {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH,
76336285Sbrian  "multilink setup", "show mp"},
76436285Sbrian  {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT,
76536285Sbrian  "protocol summary", "show proto"},
76636285Sbrian  {"route", NULL, route_Show, LOCAL_AUTH,
76736285Sbrian  "routing table", "show route"},
76836285Sbrian  {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX,
76936285Sbrian  "STOPPED timeout", "show stopped"},
77036285Sbrian  {"timers", NULL, ShowTimerList, LOCAL_AUTH,
77136285Sbrian  "alarm timers", "show timers"},
77228679Sbrian  {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH,
77336285Sbrian  "version string", "show version"},
77436285Sbrian  {"who", NULL, log_ShowWho, LOCAL_AUTH,
77536285Sbrian  "client list", "show who"},
77628679Sbrian  {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH,
77731343Sbrian  "Display this message", "show help|? [command]", ShowCommands},
77828679Sbrian  {NULL, NULL, NULL},
7796059Samurai};
7806059Samurai
78130715Sbrianstatic struct cmdtab const *
78231343SbrianFindCommand(struct cmdtab const *cmds, const char *str, int *pmatch)
7836059Samurai{
78426516Sbrian  int nmatch;
78526516Sbrian  int len;
78628679Sbrian  struct cmdtab const *found;
7876059Samurai
78826516Sbrian  found = NULL;
78926516Sbrian  len = strlen(str);
79026516Sbrian  nmatch = 0;
7916059Samurai  while (cmds->func) {
79225566Sbrian    if (cmds->name && strncasecmp(str, cmds->name, len) == 0) {
79326516Sbrian      if (cmds->name[len] == '\0') {
79428679Sbrian	*pmatch = 1;
79528679Sbrian	return cmds;
79626516Sbrian      }
7976059Samurai      nmatch++;
7986059Samurai      found = cmds;
79928679Sbrian    } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) {
80026516Sbrian      if (cmds->alias[len] == '\0') {
80128679Sbrian	*pmatch = 1;
80228679Sbrian	return cmds;
80326516Sbrian      }
8046059Samurai      nmatch++;
8056059Samurai      found = cmds;
8066059Samurai    }
8076059Samurai    cmds++;
8086059Samurai  }
8096059Samurai  *pmatch = nmatch;
81026516Sbrian  return found;
8116059Samurai}
8126059Samurai
81336285Sbrianstatic const char *
81436285SbrianmkPrefix(int argc, char const *const *argv, char *tgt, int sz)
81536285Sbrian{
81636285Sbrian  int f, tlen, len;
81736285Sbrian
81836285Sbrian  tlen = 0;
81936285Sbrian  for (f = 0; f < argc && tlen < sz - 2; f++) {
82036285Sbrian    if (f)
82136285Sbrian      tgt[tlen++] = ' ';
82236285Sbrian    len = strlen(argv[f]);
82336285Sbrian    if (len > sz - tlen - 1)
82436285Sbrian      len = sz - tlen - 1;
82536285Sbrian    strncpy(tgt+tlen, argv[f], len);
82636285Sbrian    tlen += len;
82736285Sbrian  }
82836285Sbrian  tgt[tlen] = '\0';
82936285Sbrian  return tgt;
83036285Sbrian}
83136285Sbrian
83230715Sbrianstatic int
83336285SbrianFindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn,
83436285Sbrian         char const *const *argv, struct prompt *prompt, struct datalink *cx)
8356059Samurai{
83628679Sbrian  struct cmdtab const *cmd;
8376059Samurai  int val = 1;
8386059Samurai  int nmatch;
83931343Sbrian  struct cmdargs arg;
84036285Sbrian  char prefix[100];
8416059Samurai
84236285Sbrian  cmd = FindCommand(cmds, argv[argn], &nmatch);
8436059Samurai  if (nmatch > 1)
84436285Sbrian    log_Printf(LogWARN, "%s: Ambiguous command\n",
84536285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
84636285Sbrian  else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) {
84736285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
84836285Sbrian      /* We've got no context, but we require it */
84936285Sbrian      cx = bundle2datalink(bundle, NULL);
85036285Sbrian
85136285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
85236285Sbrian      log_Printf(LogWARN, "%s: No context (use the `link' command)\n",
85336285Sbrian                mkPrefix(argn+1, argv, prefix, sizeof prefix));
85436285Sbrian    else {
85536285Sbrian      if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
85636285Sbrian        log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n",
85736285Sbrian                  mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name);
85836285Sbrian        cx = NULL;
85936285Sbrian      }
86036285Sbrian      arg.cmdtab = cmds;
86136285Sbrian      arg.cmd = cmd;
86236285Sbrian      arg.argc = argc;
86336285Sbrian      arg.argn = argn+1;
86436285Sbrian      arg.argv = argv;
86536285Sbrian      arg.bundle = bundle;
86636285Sbrian      arg.cx = cx;
86736285Sbrian      arg.prompt = prompt;
86836285Sbrian      val = (*cmd->func) (&arg);
86936285Sbrian    }
87031343Sbrian  } else
87136285Sbrian    log_Printf(LogWARN, "%s: Invalid command\n",
87236285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
87326516Sbrian
87426516Sbrian  if (val == -1)
87536285Sbrian    log_Printf(LogWARN, "Usage: %s\n", cmd->syntax);
87628679Sbrian  else if (val)
87736285Sbrian    log_Printf(LogWARN, "%s: Failed %d\n",
87836285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix), val);
87926516Sbrian
88026516Sbrian  return val;
8816059Samurai}
8826059Samurai
88337009Sbrianint
88437009Sbriancommand_Interpret(char *buff, int nb, char *argv[MAXARGS])
8856059Samurai{
8866059Samurai  char *cp;
8876059Samurai
8886059Samurai  if (nb > 0) {
8896059Samurai    cp = buff + strcspn(buff, "\r\n");
8906059Samurai    if (cp)
8916059Samurai      *cp = '\0';
89237009Sbrian    return MakeArgs(buff, argv, MAXARGS);
89337009Sbrian  }
89437009Sbrian  return 0;
89531121Sbrian}
8966059Samurai
89731822Sbrianstatic int
89831822Sbrianarghidden(int argc, char const *const *argv, int n)
89931822Sbrian{
90031822Sbrian  /* Is arg n of the given command to be hidden from the log ? */
90131828Sbrian
90231828Sbrian  /* set authkey xxxxx */
90331828Sbrian  /* set key xxxxx */
90431822Sbrian  if (n == 2 && !strncasecmp(argv[0], "se", 2) &&
90531822Sbrian      (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2)))
90631822Sbrian    return 1;
90731822Sbrian
90831828Sbrian  /* passwd xxxxx */
90931828Sbrian  if (n == 1 && !strncasecmp(argv[0], "p", 1))
91031828Sbrian    return 1;
91131828Sbrian
91236285Sbrian  /* set server port xxxxx .... */
91336285Sbrian  if (n == 3 && !strncasecmp(argv[0], "se", 2) &&
91436285Sbrian      !strncasecmp(argv[1], "se", 2))
91536285Sbrian    return 1;
91636285Sbrian
91731822Sbrian  return 0;
91831822Sbrian}
91931822Sbrian
92031121Sbrianvoid
92136285Sbriancommand_Run(struct bundle *bundle, int argc, char const *const *argv,
92237008Sbrian           struct prompt *prompt, const char *label, struct datalink *cx)
92331121Sbrian{
92431156Sbrian  if (argc > 0) {
92536285Sbrian    if (log_IsKept(LogCOMMAND)) {
92631156Sbrian      static char buf[LINE_LEN];
92731156Sbrian      int f, n;
92831156Sbrian
92931156Sbrian      *buf = '\0';
93031156Sbrian      if (label) {
93131962Sbrian        strncpy(buf, label, sizeof buf - 3);
93231962Sbrian        buf[sizeof buf - 3] = '\0';
93331156Sbrian        strcat(buf, ": ");
93431156Sbrian      }
93531156Sbrian      n = strlen(buf);
93631156Sbrian      for (f = 0; f < argc; f++) {
93731962Sbrian        if (n < sizeof buf - 1 && f)
93831156Sbrian          buf[n++] = ' ';
93931822Sbrian        if (arghidden(argc, argv, f))
94036285Sbrian          strncpy(buf+n, "********", sizeof buf - n - 1);
94131822Sbrian        else
94231962Sbrian          strncpy(buf+n, argv[f], sizeof buf - n - 1);
94331156Sbrian        n += strlen(buf+n);
94431156Sbrian      }
94536285Sbrian      log_Printf(LogCOMMAND, "%s\n", buf);
94631156Sbrian    }
94737008Sbrian    FindExec(bundle, Commands, argc, 0, argv, prompt, cx);
94831156Sbrian  }
9496059Samurai}
9506059Samurai
95131121Sbrianvoid
95236285Sbriancommand_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt,
95336285Sbrian              const char *label)
95431121Sbrian{
95531121Sbrian  int argc;
95637009Sbrian  char *argv[MAXARGS];
95731121Sbrian
95837009Sbrian  argc = command_Interpret(buff, nb, argv);
95937008Sbrian  command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL);
96031121Sbrian}
96131121Sbrian
9626059Samuraistatic int
96331343SbrianShowCommand(struct cmdargs const *arg)
9646059Samurai{
96536285Sbrian  if (!arg->prompt)
96636285Sbrian    log_Printf(LogWARN, "show: Cannot show without a prompt\n");
96736285Sbrian  else if (arg->argc > arg->argn)
96836285Sbrian    FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv,
96936285Sbrian             arg->prompt, arg->cx);
9706059Samurai  else
97136285Sbrian    prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n");
97226516Sbrian
97326516Sbrian  return 0;
9746059Samurai}
9756059Samurai
9766059Samuraistatic int
97731343SbrianTerminalCommand(struct cmdargs const *arg)
9786059Samurai{
97936285Sbrian  if (!arg->prompt) {
98036285Sbrian    log_Printf(LogWARN, "term: Need a prompt\n");
98126516Sbrian    return 1;
9826059Samurai  }
98336285Sbrian
98436285Sbrian  if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) {
98536285Sbrian    prompt_Printf(arg->prompt, "LCP state is [%s]\n",
98636285Sbrian                  State2Nam(arg->cx->physical->link.lcp.fsm.state));
98736285Sbrian    return 1;
9886059Samurai  }
98936285Sbrian
99036285Sbrian  datalink_Up(arg->cx, 0, 0);
99136285Sbrian  prompt_TtyTermMode(arg->prompt, arg->cx);
99236285Sbrian  return 0;
9936059Samurai}
9946059Samurai
9956059Samuraistatic int
99631343SbrianQuitCommand(struct cmdargs const *arg)
9976059Samurai{
99836285Sbrian  if (!arg->prompt || prompt_IsController(arg->prompt) ||
99936285Sbrian      (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") &&
100036285Sbrian       (arg->prompt->auth & LOCAL_AUTH)))
100136285Sbrian    Cleanup(EX_NORMAL);
100236285Sbrian  if (arg->prompt)
100336285Sbrian    prompt_Destroy(arg->prompt, 1);
100426516Sbrian
100526516Sbrian  return 0;
10066059Samurai}
10076059Samurai
10086059Samuraistatic int
100936285SbrianOpenCommand(struct cmdargs const *arg)
10106059Samurai{
101137160Sbrian  if (arg->argc == arg->argn)
101237993Sbrian    bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
101337160Sbrian  else if (arg->argc == arg->argn + 1) {
101437160Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
101537385Sbrian      struct datalink *cx = arg->cx ?
101637385Sbrian        arg->cx : bundle2datalink(arg->bundle, NULL);
101737385Sbrian      if (cx) {
101837385Sbrian        if (cx->physical->link.lcp.fsm.state == ST_OPENED)
101937385Sbrian          fsm_Reopen(&cx->physical->link.lcp.fsm);
102037160Sbrian        else
102137993Sbrian          bundle_Open(arg->bundle, cx->name, PHYS_ALL, 1);
102237160Sbrian      } else
102337160Sbrian        log_Printf(LogWARN, "open lcp: You must specify a link\n");
102437160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
102537160Sbrian      struct fsm *fp;
10266059Samurai
102737210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
102837160Sbrian      if (fp->link->lcp.fsm.state != ST_OPENED)
102937160Sbrian        log_Printf(LogWARN, "open: LCP must be open before opening CCP\n");
103037160Sbrian      else if (fp->state == ST_OPENED)
103137160Sbrian        fsm_Reopen(fp);
103237160Sbrian      else {
103337160Sbrian        fp->open_mode = 0;	/* Not passive any more */
103437160Sbrian        if (fp->state == ST_STOPPED) {
103537160Sbrian          fsm_Down(fp);
103637160Sbrian          fsm_Up(fp);
103737160Sbrian        } else {
103837160Sbrian          fsm_Up(fp);
103937160Sbrian          fsm_Open(fp);
104037160Sbrian        }
104136285Sbrian      }
104237160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) {
104337160Sbrian      if (arg->cx)
104437160Sbrian        log_Printf(LogWARN, "open ipcp: You need not specify a link\n");
104537160Sbrian      if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
104637160Sbrian        fsm_Reopen(&arg->bundle->ncp.ipcp.fsm);
104737160Sbrian      else
104837993Sbrian        bundle_Open(arg->bundle, NULL, PHYS_ALL, 1);
104937160Sbrian    } else
105037160Sbrian      return -1;
105136285Sbrian  } else
105236285Sbrian    return -1;
105336285Sbrian
105426516Sbrian  return 0;
10556059Samurai}
10566059Samurai
105725067Sbrianstatic int
105836285SbrianCloseCommand(struct cmdargs const *arg)
10596059Samurai{
106037007Sbrian  if (arg->argc == arg->argn)
106137007Sbrian    bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN);
106237007Sbrian  else if (arg->argc == arg->argn + 1) {
106337007Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp"))
106437007Sbrian      bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP);
106537007Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "ccp") ||
106637007Sbrian             !strcasecmp(arg->argv[arg->argn], "ccp!")) {
106737007Sbrian      struct fsm *fp;
10686059Samurai
106937210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
107037007Sbrian      if (fp->state == ST_OPENED) {
107137007Sbrian        fsm_Close(fp);
107237007Sbrian        if (arg->argv[arg->argn][3] == '!')
107337007Sbrian          fp->open_mode = 0;		/* Stay ST_CLOSED */
107437007Sbrian        else
107537007Sbrian          fp->open_mode = OPEN_PASSIVE;	/* Wait for the peer to start */
107637007Sbrian      }
107737007Sbrian    } else
107836285Sbrian      return -1;
107936285Sbrian  } else
108036285Sbrian    return -1;
108136285Sbrian
108236285Sbrian  return 0;
10836059Samurai}
10846059Samurai
108525067Sbrianstatic int
108636285SbrianDownCommand(struct cmdargs const *arg)
108711336Samurai{
108837018Sbrian  if (arg->argc == arg->argn) {
108937018Sbrian      if (arg->cx)
109037018Sbrian        datalink_Down(arg->cx, CLOSE_STAYDOWN);
109137018Sbrian      else
109237018Sbrian        bundle_Down(arg->bundle, CLOSE_STAYDOWN);
109337018Sbrian  } else if (arg->argc == arg->argn + 1) {
109437018Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
109537018Sbrian      if (arg->cx)
109637018Sbrian        datalink_Down(arg->cx, CLOSE_LCP);
109737018Sbrian      else
109837018Sbrian        bundle_Down(arg->bundle, CLOSE_LCP);
109937018Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
110037018Sbrian      struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm :
110137018Sbrian                                 &arg->bundle->ncp.mp.link.ccp.fsm;
110237060Sbrian      fsm2initial(fp);
110337018Sbrian    } else
110437018Sbrian      return -1;
110536285Sbrian  } else
110636285Sbrian    return -1;
110736285Sbrian
110836285Sbrian  return 0;
110925067Sbrian}
111025067Sbrian
111125067Sbrianstatic int
111236285SbrianSetModemSpeed(struct cmdargs const *arg)
111325067Sbrian{
111436285Sbrian  long speed;
111536285Sbrian  char *end;
111611336Samurai
111736285Sbrian  if (arg->argc > arg->argn && *arg->argv[arg->argn]) {
111836285Sbrian    if (arg->argc > arg->argn+1) {
111936285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Too many arguments");
112036285Sbrian      return -1;
112111336Samurai    }
112236285Sbrian    if (strcasecmp(arg->argv[arg->argn], "sync") == 0) {
112336285Sbrian      physical_SetSync(arg->cx->physical);
112436285Sbrian      return 0;
112536285Sbrian    }
112636285Sbrian    end = NULL;
112736285Sbrian    speed = strtol(arg->argv[arg->argn], &end, 10);
112836285Sbrian    if (*end) {
112936285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"",
113036285Sbrian                arg->argv[arg->argn]);
113136285Sbrian      return -1;
113236285Sbrian    }
113336285Sbrian    if (physical_SetSpeed(arg->cx->physical, speed))
113436285Sbrian      return 0;
113536285Sbrian    log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]);
113636285Sbrian  } else
113736285Sbrian    log_Printf(LogWARN, "SetModemSpeed: No speed specified\n");
113824939Sbrian
113926516Sbrian  return -1;
114011336Samurai}
114111336Samurai
114225067Sbrianstatic int
114331343SbrianSetStoppedTimeout(struct cmdargs const *arg)
114428327Sbrian{
114536285Sbrian  struct link *l = &arg->cx->physical->link;
114636285Sbrian
114736285Sbrian  l->lcp.fsm.StoppedTimer.load = 0;
114836285Sbrian  l->ccp.fsm.StoppedTimer.load = 0;
114936285Sbrian  if (arg->argc <= arg->argn+2) {
115036285Sbrian    if (arg->argc > arg->argn) {
115136285Sbrian      l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS;
115236285Sbrian      if (arg->argc > arg->argn+1)
115336285Sbrian        l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS;
115428461Sbrian    }
115528327Sbrian    return 0;
115628327Sbrian  }
115728327Sbrian  return -1;
115828327Sbrian}
115928327Sbrian
116031081Sbrian#define ismask(x) \
116131081Sbrian  (*x == '0' && strlen(x) == 4 && strspn(x+1, "0123456789.") == 3)
116231081Sbrian
116328327Sbrianstatic int
116431343SbrianSetServer(struct cmdargs const *arg)
116526940Sbrian{
116626940Sbrian  int res = -1;
116726940Sbrian
116836285Sbrian  if (arg->argc > arg->argn && arg->argc < arg->argn+4) {
116931081Sbrian    const char *port, *passwd, *mask;
117031081Sbrian
117131081Sbrian    /* What's what ? */
117236285Sbrian    port = arg->argv[arg->argn];
117336285Sbrian    if (arg->argc == arg->argn + 2) {
117436285Sbrian      passwd = arg->argv[arg->argn+1];
117536285Sbrian      mask = NULL;
117636285Sbrian    } else if (arg->argc == arg->argn + 3) {
117736285Sbrian      passwd = arg->argv[arg->argn+1];
117836285Sbrian      mask = arg->argv[arg->argn+2];
117931081Sbrian      if (!ismask(mask))
118031081Sbrian        return -1;
118136285Sbrian    } else if (strcasecmp(port, "none") == 0) {
118236285Sbrian      if (server_Close(arg->bundle))
118336285Sbrian        log_Printf(LogPHASE, "Disabled server port.\n");
118436285Sbrian      return 0;
118531081Sbrian    } else
118636285Sbrian      return -1;
118731081Sbrian
118836285Sbrian    strncpy(server.passwd, passwd, sizeof server.passwd - 1);
118936285Sbrian    server.passwd[sizeof server.passwd - 1] = '\0';
119031081Sbrian
119136285Sbrian    if (*port == '/') {
119231081Sbrian      mode_t imask;
119336285Sbrian      char *ptr, name[LINE_LEN + 12];
119428679Sbrian
119531081Sbrian      if (mask != NULL) {
119628679Sbrian	unsigned m;
119728679Sbrian
119831081Sbrian	if (sscanf(mask, "%o", &m) == 1)
119931081Sbrian	  imask = m;
120031081Sbrian        else
120131081Sbrian          return -1;
120231081Sbrian      } else
120331081Sbrian        imask = (mode_t)-1;
120436285Sbrian
120536285Sbrian      ptr = strstr(port, "%d");
120636285Sbrian      if (ptr) {
120736285Sbrian        snprintf(name, sizeof name, "%.*s%d%s",
120837210Sbrian                 (int)(ptr - port), port, arg->bundle->unit, ptr + 2);
120936285Sbrian        port = name;
121036285Sbrian      }
121136285Sbrian      res = server_LocalOpen(arg->bundle, port, imask);
121227346Sbrian    } else {
121336285Sbrian      int iport, add = 0;
121428679Sbrian
121531081Sbrian      if (mask != NULL)
121631081Sbrian        return -1;
121728679Sbrian
121836285Sbrian      if (*port == '+') {
121936285Sbrian        port++;
122036285Sbrian        add = 1;
122136285Sbrian      }
122231081Sbrian      if (strspn(port, "0123456789") != strlen(port)) {
122331081Sbrian        struct servent *s;
122431081Sbrian
122531081Sbrian        if ((s = getservbyname(port, "tcp")) == NULL) {
122631081Sbrian	  iport = 0;
122736285Sbrian	  log_Printf(LogWARN, "%s: Invalid port or service\n", port);
122828679Sbrian	} else
122931081Sbrian	  iport = ntohs(s->s_port);
123027346Sbrian      } else
123131081Sbrian        iport = atoi(port);
123236285Sbrian
123336285Sbrian      if (iport) {
123436285Sbrian        if (add)
123536285Sbrian          iport += arg->bundle->unit;
123636285Sbrian        res = server_TcpOpen(arg->bundle, iport);
123736285Sbrian      } else
123836285Sbrian        res = -1;
123927346Sbrian    }
124031081Sbrian  }
124126940Sbrian
124226940Sbrian  return res;
124326940Sbrian}
124426940Sbrian
124526940Sbrianstatic int
124631343SbrianSetModemParity(struct cmdargs const *arg)
12476059Samurai{
124836285Sbrian  return arg->argc > arg->argn ? modem_SetParity(arg->cx->physical,
124936285Sbrian                                                 arg->argv[arg->argn]) : -1;
12506059Samurai}
12516059Samurai
12526059Samuraistatic int
125331343SbrianSetEscape(struct cmdargs const *arg)
12546059Samurai{
12556059Samurai  int code;
125636285Sbrian  int argc = arg->argc - arg->argn;
125736285Sbrian  char const *const *argv = arg->argv + arg->argn;
12586059Samurai
12596059Samurai  for (code = 0; code < 33; code++)
126036285Sbrian    arg->cx->physical->async.cfg.EscMap[code] = 0;
126131343Sbrian
12626059Samurai  while (argc-- > 0) {
12636059Samurai    sscanf(*argv++, "%x", &code);
12646059Samurai    code &= 0xff;
126536285Sbrian    arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7));
126636285Sbrian    arg->cx->physical->async.cfg.EscMap[32] = 1;
12676059Samurai  }
126826516Sbrian  return 0;
12696059Samurai}
12706059Samurai
127130715Sbrianstatic struct in_addr
127231343SbrianGetIpAddr(const char *cp)
12736059Samurai{
12746059Samurai  struct hostent *hp;
12756059Samurai  struct in_addr ipaddr;
12766059Samurai
127732124Sbrian  if (inet_aton(cp, &ipaddr) == 0) {
127832124Sbrian    hp = gethostbyname(cp);
127932124Sbrian    if (hp && hp->h_addrtype == AF_INET)
128032124Sbrian      memcpy(&ipaddr, hp->h_addr, hp->h_length);
128132124Sbrian    else
128232124Sbrian      ipaddr.s_addr = 0;
128332124Sbrian  }
128428679Sbrian  return (ipaddr);
12856059Samurai}
12866059Samurai
12876059Samuraistatic int
128831343SbrianSetInterfaceAddr(struct cmdargs const *arg)
12896059Samurai{
129036285Sbrian  struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
129132267Sbrian  const char *hisaddr;
129232267Sbrian
129340561Sbrian  if (arg->argc > arg->argn + 4)
129440561Sbrian    return -1;
129540561Sbrian
129632267Sbrian  hisaddr = NULL;
129736285Sbrian  ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY;
129836285Sbrian  ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY;
129936285Sbrian  ipcp->cfg.HaveTriggerAddress = 0;
130036285Sbrian  ipcp->cfg.netmask.s_addr = INADDR_ANY;
130136285Sbrian  iplist_reset(&ipcp->cfg.peer_list);
130228394Sbrian
130336285Sbrian  if (arg->argc > arg->argn) {
130443313Sbrian    if (!ParseAddr(ipcp, arg->argv[arg->argn],
130536285Sbrian                   &ipcp->cfg.my_range.ipaddr, &ipcp->cfg.my_range.mask,
130636285Sbrian                   &ipcp->cfg.my_range.width))
130728679Sbrian      return 1;
130836285Sbrian    if (arg->argc > arg->argn+1) {
130936285Sbrian      hisaddr = arg->argv[arg->argn+1];
131036285Sbrian      if (arg->argc > arg->argn+2) {
131136285Sbrian        ipcp->cfg.netmask = GetIpAddr(arg->argv[arg->argn+2]);
131236285Sbrian	if (arg->argc > arg->argn+3) {
131336285Sbrian	  ipcp->cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]);
131436285Sbrian	  ipcp->cfg.HaveTriggerAddress = 1;
13159440Samurai	}
13166059Samurai      }
13176059Samurai    }
13186059Samurai  }
131928394Sbrian
132040561Sbrian  /* 0.0.0.0 means any address (0 bits) */
132136285Sbrian  if (ipcp->cfg.my_range.ipaddr.s_addr == INADDR_ANY) {
132236285Sbrian    ipcp->cfg.my_range.mask.s_addr = INADDR_ANY;
132336285Sbrian    ipcp->cfg.my_range.width = 0;
13246059Samurai  }
132536285Sbrian  ipcp->my_ip.s_addr = ipcp->cfg.my_range.ipaddr.s_addr;
132636285Sbrian
132736285Sbrian  if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr,
132836928Sbrian                                  arg->bundle->phys_type.all & PHYS_AUTO))
132932267Sbrian    return 4;
133031121Sbrian
133126516Sbrian  return 0;
13326059Samurai}
13336059Samurai
133418752Sjkhstatic int
133531343SbrianSetVariable(struct cmdargs const *arg)
13366059Samurai{
133737210Sbrian  long long_val, param = (long)arg->cmd->args;
133837210Sbrian  int mode, dummyint;
133931343Sbrian  const char *argp;
134036285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
134136285Sbrian  const char *err = NULL;
134236285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
134336285Sbrian  struct in_addr dummyaddr, *addr;
13446059Samurai
134536285Sbrian  if (arg->argc > arg->argn)
134636285Sbrian    argp = arg->argv[arg->argn];
134726551Sbrian  else
134831343Sbrian    argp = "";
134926551Sbrian
135036285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
135136285Sbrian    log_Printf(LogWARN, "set %s: No context (use the `link' command)\n",
135236285Sbrian              arg->cmd->name);
135336285Sbrian    return 1;
135436285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
135536285Sbrian    log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n",
135636285Sbrian              arg->cmd->name, cx->name);
135736285Sbrian    cx = NULL;
135836285Sbrian  }
135936285Sbrian
136026551Sbrian  switch (param) {
136128679Sbrian  case VAR_AUTHKEY:
136240622Sbrian    switch (bundle_Phase(arg->bundle)) {
136340622Sbrian      case PHASE_DEAD:
136440622Sbrian      case PHASE_ESTABLISH:
136540622Sbrian        strncpy(arg->bundle->cfg.auth.key, argp,
136640622Sbrian                sizeof arg->bundle->cfg.auth.key - 1);
136740622Sbrian        arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0';
136840622Sbrian        break;
136940622Sbrian      default:
137040622Sbrian        err = "set authkey: Only available at phase DEAD/ESTABLISH\n";
137140622Sbrian        log_Printf(LogWARN, err);
137240622Sbrian        break;
137336285Sbrian    }
137428679Sbrian    break;
137537210Sbrian
137628679Sbrian  case VAR_AUTHNAME:
137740622Sbrian    switch (bundle_Phase(arg->bundle)) {
137840622Sbrian      case PHASE_DEAD:
137940622Sbrian      case PHASE_ESTABLISH:
138040622Sbrian        strncpy(arg->bundle->cfg.auth.name, argp,
138140622Sbrian                sizeof arg->bundle->cfg.auth.name - 1);
138240622Sbrian        arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name-1] = '\0';
138340622Sbrian        break;
138440622Sbrian      default:
138540622Sbrian        err = "set authname: Only available at phase DEAD/ESTABLISH\n";
138640622Sbrian        log_Printf(LogWARN, err);
138740622Sbrian        break;
138836285Sbrian    }
138928679Sbrian    break;
139037210Sbrian
139136285Sbrian  case VAR_AUTOLOAD:
139236285Sbrian    if (arg->argc == arg->argn + 2 || arg->argc == arg->argn + 4) {
139336285Sbrian      arg->bundle->autoload.running = 1;
139436285Sbrian      arg->bundle->cfg.autoload.max.timeout = atoi(arg->argv[arg->argn]);
139536285Sbrian      arg->bundle->cfg.autoload.max.packets = atoi(arg->argv[arg->argn + 1]);
139636285Sbrian      if (arg->argc == arg->argn + 4) {
139736285Sbrian        arg->bundle->cfg.autoload.min.timeout = atoi(arg->argv[arg->argn + 2]);
139836285Sbrian        arg->bundle->cfg.autoload.min.packets = atoi(arg->argv[arg->argn + 3]);
139936285Sbrian      } else {
140036285Sbrian        arg->bundle->cfg.autoload.min.timeout = 0;
140136285Sbrian        arg->bundle->cfg.autoload.min.packets = 0;
140236285Sbrian      }
140336285Sbrian    } else {
140436285Sbrian      err = "Set autoload requires two or four arguments\n";
140536285Sbrian      log_Printf(LogWARN, err);
140636285Sbrian    }
140736285Sbrian    break;
140837210Sbrian
140928679Sbrian  case VAR_DIAL:
141036285Sbrian    strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1);
141136285Sbrian    cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0';
141228679Sbrian    break;
141337210Sbrian
141428679Sbrian  case VAR_LOGIN:
141536285Sbrian    strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1);
141636285Sbrian    cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0';
141728679Sbrian    break;
141837210Sbrian
141936285Sbrian  case VAR_WINSIZE:
142036285Sbrian    if (arg->argc > arg->argn) {
142136285Sbrian      l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]);
142236285Sbrian      if (l->ccp.cfg.deflate.out.winsize < 8 ||
142336285Sbrian          l->ccp.cfg.deflate.out.winsize > 15) {
142436285Sbrian          log_Printf(LogWARN, "%d: Invalid outgoing window size\n",
142536285Sbrian                    l->ccp.cfg.deflate.out.winsize);
142636285Sbrian          l->ccp.cfg.deflate.out.winsize = 15;
142736285Sbrian      }
142836285Sbrian      if (arg->argc > arg->argn+1) {
142936285Sbrian        l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]);
143036285Sbrian        if (l->ccp.cfg.deflate.in.winsize < 8 ||
143136285Sbrian            l->ccp.cfg.deflate.in.winsize > 15) {
143236285Sbrian            log_Printf(LogWARN, "%d: Invalid incoming window size\n",
143336285Sbrian                      l->ccp.cfg.deflate.in.winsize);
143436285Sbrian            l->ccp.cfg.deflate.in.winsize = 15;
143536285Sbrian        }
143636285Sbrian      } else
143736285Sbrian        l->ccp.cfg.deflate.in.winsize = 0;
143836285Sbrian    } else {
143936285Sbrian      err = "No window size specified\n";
144036285Sbrian      log_Printf(LogWARN, err);
144136285Sbrian    }
144236285Sbrian    break;
144337210Sbrian
144428679Sbrian  case VAR_DEVICE:
144536285Sbrian    physical_SetDeviceList(cx->physical, arg->argc - arg->argn,
144636285Sbrian                           arg->argv + arg->argn);
144736285Sbrian    break;
144837210Sbrian
144936285Sbrian  case VAR_ACCMAP:
145036285Sbrian    if (arg->argc > arg->argn) {
145137210Sbrian      u_long ulong_val;
145236285Sbrian      sscanf(argp, "%lx", &ulong_val);
145337210Sbrian      cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val;
145436285Sbrian    } else {
145536285Sbrian      err = "No accmap specified\n";
145636285Sbrian      log_Printf(LogWARN, err);
145736285Sbrian    }
145836285Sbrian    break;
145937210Sbrian
146036285Sbrian  case VAR_MODE:
146136285Sbrian    mode = Nam2mode(argp);
146236285Sbrian    if (mode == PHYS_NONE || mode == PHYS_ALL) {
146336285Sbrian      log_Printf(LogWARN, "%s: Invalid mode\n", argp);
146436285Sbrian      return -1;
146536285Sbrian    }
146636285Sbrian    bundle_SetMode(arg->bundle, cx, mode);
146736285Sbrian    break;
146837210Sbrian
146936285Sbrian  case VAR_MRRU:
147040622Sbrian    switch (bundle_Phase(arg->bundle)) {
147140622Sbrian      case PHASE_DEAD:
147240622Sbrian        break;
147340622Sbrian      case PHASE_ESTABLISH:
147440622Sbrian        /* Make sure none of our links are DATALINK_LCP or greater */
147540622Sbrian        if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
147640622Sbrian          log_Printf(LogWARN, "mrru: Only changable before LCP negotiations\n");
147740622Sbrian          return 1;
147840622Sbrian        }
147940622Sbrian        break;
148040622Sbrian      default:
148140622Sbrian        log_Printf(LogWARN, "mrru: Only changable at phase DEAD/ESTABLISH\n");
148240622Sbrian        return 1;
148329696Sbrian    }
148437210Sbrian    long_val = atol(argp);
148537210Sbrian    if (long_val && long_val < MIN_MRU) {
148637210Sbrian      log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU);
148737210Sbrian      return 1;
148837210Sbrian    } else if (long_val > MAX_MRU) {
148937210Sbrian      log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU);
149037210Sbrian      return 1;
149137210Sbrian    } else
149237210Sbrian      arg->bundle->ncp.mp.cfg.mrru = long_val;
149328679Sbrian    break;
149437210Sbrian
149536285Sbrian  case VAR_MRU:
149637210Sbrian    long_val = atol(argp);
149737210Sbrian    if (long_val == 0)
149837210Sbrian      l->lcp.cfg.mru = DEF_MRU;
149937210Sbrian    else if (long_val < MIN_MRU) {
150037210Sbrian      log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU);
150137210Sbrian      return 1;
150237210Sbrian    } else if (long_val > MAX_MRU) {
150337210Sbrian      log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU);
150437210Sbrian      return 1;
150537210Sbrian    } else
150637210Sbrian      l->lcp.cfg.mru = long_val;
150728679Sbrian    break;
150837210Sbrian
150936285Sbrian  case VAR_MTU:
151037210Sbrian    long_val = atol(argp);
151137210Sbrian    if (long_val && long_val < MIN_MTU) {
151237210Sbrian      log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU);
151337210Sbrian      return 1;
151437210Sbrian    } else if (long_val > MAX_MTU) {
151537210Sbrian      log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU);
151637210Sbrian      return 1;
151737210Sbrian    } else
151837210Sbrian      arg->bundle->cfg.mtu = long_val;
151936285Sbrian    break;
152037210Sbrian
152136285Sbrian  case VAR_OPENMODE:
152236285Sbrian    if (strcasecmp(argp, "active") == 0)
152336285Sbrian      cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ?
152436285Sbrian        atoi(arg->argv[arg->argn+1]) : 1;
152536285Sbrian    else if (strcasecmp(argp, "passive") == 0)
152636285Sbrian      cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE;
152736285Sbrian    else {
152836285Sbrian      err = "%s: Invalid openmode\n";
152936285Sbrian      log_Printf(LogWARN, err, argp);
153036285Sbrian    }
153136285Sbrian    break;
153237210Sbrian
153328679Sbrian  case VAR_PHONE:
153436285Sbrian    strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1);
153536285Sbrian    cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0';
153638174Sbrian    cx->phone.alt = cx->phone.next = NULL;
153728679Sbrian    break;
153837210Sbrian
153928679Sbrian  case VAR_HANGUP:
154036285Sbrian    strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1);
154136285Sbrian    cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0';
154228679Sbrian    break;
154337210Sbrian
154436285Sbrian  case VAR_IDLETIMEOUT:
154536285Sbrian    if (arg->argc > arg->argn+1)
154636285Sbrian      err = "Too many idle timeout values\n";
154736285Sbrian    else if (arg->argc == arg->argn+1)
154836285Sbrian      bundle_SetIdleTimer(arg->bundle, atoi(argp));
154936285Sbrian    if (err)
155036285Sbrian      log_Printf(LogWARN, err);
155129549Sbrian    break;
155237210Sbrian
155336285Sbrian  case VAR_LQRPERIOD:
155437210Sbrian    long_val = atol(argp);
155537210Sbrian    if (long_val < MIN_LQRPERIOD) {
155637210Sbrian      log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n",
155737210Sbrian                 long_val, MIN_LQRPERIOD);
155837210Sbrian      return 1;
155936285Sbrian    } else
156037210Sbrian      l->lcp.cfg.lqrperiod = long_val;
156136285Sbrian    break;
156237210Sbrian
156336285Sbrian  case VAR_LCPRETRY:
156437210Sbrian    long_val = atol(argp);
156537210Sbrian    if (long_val < MIN_FSMRETRY) {
156637210Sbrian      log_Printf(LogWARN, "%ld: Invalid LCP FSM retry period - min %d\n",
156737210Sbrian                 long_val, MIN_FSMRETRY);
156837210Sbrian      return 1;
156936285Sbrian    } else
157037210Sbrian      cx->physical->link.lcp.cfg.fsmretry = long_val;
157136285Sbrian    break;
157237210Sbrian
157336285Sbrian  case VAR_CHAPRETRY:
157437210Sbrian    long_val = atol(argp);
157537210Sbrian    if (long_val < MIN_FSMRETRY) {
157637210Sbrian      log_Printf(LogWARN, "%ld: Invalid CHAP FSM retry period - min %d\n",
157737210Sbrian                 long_val, MIN_FSMRETRY);
157837210Sbrian      return 1;
157936285Sbrian    } else
158037210Sbrian      cx->chap.auth.cfg.fsmretry = long_val;
158136285Sbrian    break;
158237210Sbrian
158336285Sbrian  case VAR_PAPRETRY:
158437210Sbrian    long_val = atol(argp);
158537210Sbrian    if (long_val < MIN_FSMRETRY) {
158637210Sbrian      log_Printf(LogWARN, "%ld: Invalid PAP FSM retry period - min %d\n",
158737210Sbrian                 long_val, MIN_FSMRETRY);
158837210Sbrian      return 1;
158936285Sbrian    } else
159037210Sbrian      cx->pap.cfg.fsmretry = long_val;
159136285Sbrian    break;
159237210Sbrian
159336285Sbrian  case VAR_CCPRETRY:
159437210Sbrian    long_val = atol(argp);
159537210Sbrian    if (long_val < MIN_FSMRETRY) {
159637210Sbrian      log_Printf(LogWARN, "%ld: Invalid CCP FSM retry period - min %d\n",
159737210Sbrian                 long_val, MIN_FSMRETRY);
159837210Sbrian      return 1;
159936285Sbrian    } else
160037210Sbrian      l->ccp.cfg.fsmretry = long_val;
160136285Sbrian    break;
160237210Sbrian
160336285Sbrian  case VAR_IPCPRETRY:
160437210Sbrian    long_val = atol(argp);
160537210Sbrian    if (long_val < MIN_FSMRETRY) {
160637210Sbrian      log_Printf(LogWARN, "%ld: Invalid IPCP FSM retry period - min %d\n",
160737210Sbrian                 long_val, MIN_FSMRETRY);
160837210Sbrian      return 1;
160936285Sbrian    } else
161037210Sbrian      arg->bundle->ncp.ipcp.cfg.fsmretry = long_val;
161136285Sbrian    break;
161237210Sbrian
161336285Sbrian  case VAR_NBNS:
161436285Sbrian  case VAR_DNS:
161536285Sbrian    if (param == VAR_DNS)
161636285Sbrian      addr = arg->bundle->ncp.ipcp.cfg.ns.dns;
161736285Sbrian    else
161836285Sbrian      addr = arg->bundle->ncp.ipcp.cfg.ns.nbns;
161936285Sbrian
162036285Sbrian    addr[0].s_addr = addr[1].s_addr = INADDR_ANY;
162136285Sbrian
162236285Sbrian    if (arg->argc > arg->argn) {
162343313Sbrian      ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn],
162436285Sbrian                addr, &dummyaddr, &dummyint);
162536285Sbrian      if (arg->argc > arg->argn+1)
162643313Sbrian        ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn + 1],
162736285Sbrian                  addr + 1, &dummyaddr, &dummyint);
162836285Sbrian
162936285Sbrian      if (addr[1].s_addr == INADDR_ANY)
163036285Sbrian        addr[1].s_addr = addr[0].s_addr;
163136285Sbrian      if (addr[0].s_addr == INADDR_ANY)
163236285Sbrian        addr[0].s_addr = addr[1].s_addr;
163336285Sbrian    }
163436285Sbrian    break;
163538174Sbrian
163638174Sbrian  case VAR_CALLBACK:
163738174Sbrian    cx->cfg.callback.opmask = 0;
163838174Sbrian    for (dummyint = arg->argn; dummyint < arg->argc; dummyint++) {
163938174Sbrian      if (!strcasecmp(arg->argv[dummyint], "auth"))
164038174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_AUTH);
164138174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "cbcp"))
164238174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_CBCP);
164338174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "e.164")) {
164438174Sbrian        if (dummyint == arg->argc - 1)
164538174Sbrian          log_Printf(LogWARN, "No E.164 arg (E.164 ignored) !\n");
164638174Sbrian        else {
164738174Sbrian          cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_E164);
164838174Sbrian          strncpy(cx->cfg.callback.msg, arg->argv[++dummyint],
164938174Sbrian                  sizeof cx->cfg.callback.msg - 1);
165038174Sbrian          cx->cfg.callback.msg[sizeof cx->cfg.callback.msg - 1] = '\0';
165138174Sbrian        }
165238174Sbrian      } else if (!strcasecmp(arg->argv[dummyint], "none"))
165338174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_NONE);
165438174Sbrian      else
165538174Sbrian        return -1;
165638174Sbrian    }
165738174Sbrian    if (cx->cfg.callback.opmask == CALLBACK_BIT(CALLBACK_NONE))
165838174Sbrian      cx->cfg.callback.opmask = 0;
165938174Sbrian    break;
166038174Sbrian
166138174Sbrian  case VAR_CBCP:
166238174Sbrian    cx->cfg.cbcp.delay = 0;
166338174Sbrian    *cx->cfg.cbcp.phone = '\0';
166438174Sbrian    cx->cfg.cbcp.fsmretry = DEF_FSMRETRY;
166538174Sbrian    if (arg->argc > arg->argn) {
166638174Sbrian      strncpy(cx->cfg.cbcp.phone, arg->argv[arg->argn],
166738174Sbrian              sizeof cx->cfg.cbcp.phone - 1);
166838174Sbrian      cx->cfg.cbcp.phone[sizeof cx->cfg.cbcp.phone - 1] = '\0';
166938174Sbrian      if (arg->argc > arg->argn + 1) {
167038174Sbrian        cx->cfg.cbcp.delay = atoi(arg->argv[arg->argn + 1]);
167138174Sbrian        if (arg->argc > arg->argn + 2) {
167238174Sbrian          long_val = atol(arg->argv[arg->argn + 2]);
167338174Sbrian          if (long_val < MIN_FSMRETRY)
167438174Sbrian            log_Printf(LogWARN, "%ld: Invalid CBCP FSM retry period - min %d\n",
167538174Sbrian                       long_val, MIN_FSMRETRY);
167638174Sbrian          else
167738174Sbrian            cx->cfg.cbcp.fsmretry = long_val;
167838174Sbrian        }
167938174Sbrian      }
168038174Sbrian    }
168138174Sbrian    break;
168238544Sbrian
168338544Sbrian  case VAR_CHOKED:
168438544Sbrian    arg->bundle->cfg.choked.timeout = atoi(argp);
168538544Sbrian    if (arg->bundle->cfg.choked.timeout <= 0)
168638544Sbrian      arg->bundle->cfg.choked.timeout = CHOKED_TIMEOUT;
168738544Sbrian    break;
168840665Sbrian
168940665Sbrian  case VAR_SENDPIPE:
169040665Sbrian    long_val = atol(argp);
169140665Sbrian    arg->bundle->ncp.ipcp.cfg.sendpipe = long_val;
169240665Sbrian    break;
169340665Sbrian
169440665Sbrian  case VAR_RECVPIPE:
169540665Sbrian    long_val = atol(argp);
169640665Sbrian    arg->bundle->ncp.ipcp.cfg.recvpipe = long_val;
169740665Sbrian    break;
169843313Sbrian
169943313Sbrian#ifndef NORADIUS
170043313Sbrian  case VAR_RADIUS:
170143313Sbrian    if (!*argp)
170243313Sbrian      *arg->bundle->radius.cfg.file = '\0';
170343313Sbrian    else if (access(argp, R_OK)) {
170443313Sbrian      log_Printf(LogWARN, "%s: %s\n", argp, strerror(errno));
170543313Sbrian      return 1;
170643313Sbrian    } else {
170743313Sbrian      strncpy(arg->bundle->radius.cfg.file, argp,
170843313Sbrian              sizeof arg->bundle->radius.cfg.file - 1);
170943313Sbrian      arg->bundle->radius.cfg.file
171043313Sbrian        [sizeof arg->bundle->radius.cfg.file - 1] = '\0';
171143313Sbrian    }
171243313Sbrian    break;
171343313Sbrian#endif
17146059Samurai  }
171536285Sbrian
171636285Sbrian  return err ? 1 : 0;
17176059Samurai}
17186059Samurai
171928679Sbrianstatic int
172031343SbrianSetCtsRts(struct cmdargs const *arg)
172120812Sjkh{
172236285Sbrian  if (arg->argc == arg->argn+1) {
172336285Sbrian    if (strcmp(arg->argv[arg->argn], "on") == 0)
172436285Sbrian      physical_SetRtsCts(arg->cx->physical, 1);
172536285Sbrian    else if (strcmp(arg->argv[arg->argn], "off") == 0)
172636285Sbrian      physical_SetRtsCts(arg->cx->physical, 0);
172720812Sjkh    else
172826516Sbrian      return -1;
172926516Sbrian    return 0;
173020812Sjkh  }
173126516Sbrian  return -1;
173220812Sjkh}
173320812Sjkh
173430715Sbrianstatic struct cmdtab const SetCommands[] = {
173536285Sbrian  {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
173636285Sbrian  "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP},
173728679Sbrian  {"authkey", "key", SetVariable, LOCAL_AUTH,
173836285Sbrian  "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY},
173928679Sbrian  {"authname", NULL, SetVariable, LOCAL_AUTH,
174036285Sbrian  "authentication name", "set authname name", (const void *)VAR_AUTHNAME},
174136285Sbrian  {"autoload", NULL, SetVariable, LOCAL_AUTH,
174236285Sbrian  "auto link [de]activation", "set autoload maxtime maxload mintime minload",
174336285Sbrian  (const void *)VAR_AUTOLOAD},
174438174Sbrian  {"callback", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
174538174Sbrian  "callback control", "set callback [none|auth|cbcp|"
174638174Sbrian  "E.164 *|number[,number]...]...", (const void *)VAR_CALLBACK},
174738174Sbrian  {"cbcp", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
174838174Sbrian  "CBCP control", "set cbcp [*|phone[,phone...] [delay [timeout]]]",
174938174Sbrian  (const void *)VAR_CBCP},
175036285Sbrian  {"ccpretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
175136285Sbrian  "FSM retry period", "set ccpretry value", (const void *)VAR_CCPRETRY},
175236285Sbrian  {"chapretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
175336285Sbrian  "CHAP retry period", "set chapretry value", (const void *)VAR_CHAPRETRY},
175438544Sbrian  {"choked", NULL, SetVariable, LOCAL_AUTH,
175538544Sbrian  "choked timeout", "set choked [secs]", (const void *)VAR_CHOKED},
175636285Sbrian  {"ctsrts", "crtscts", SetCtsRts, LOCAL_AUTH | LOCAL_CX,
175736285Sbrian  "Use hardware flow control", "set ctsrts [on|off]"},
175836285Sbrian  {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
175936285Sbrian  "deflate window sizes", "set deflate out-winsize in-winsize",
176036285Sbrian  (const void *) VAR_WINSIZE},
176136285Sbrian  {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX,
176236285Sbrian  "modem device name", "set device|line device-name[,device-name]",
176336285Sbrian  (const void *) VAR_DEVICE},
176436285Sbrian  {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
176536285Sbrian  "dialing script", "set dial chat-script", (const void *) VAR_DIAL},
176636285Sbrian  {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server",
176736285Sbrian  "set dns pri-addr [sec-addr]", (const void *)VAR_DNS},
176836285Sbrian  {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH,
176936285Sbrian  "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]"},
177036285Sbrian  {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX,
177136285Sbrian  "escape characters", "set escape hex-digit ..."},
177236285Sbrian  {"filter", NULL, filter_Set, LOCAL_AUTH,
177336285Sbrian  "packet filters", "set filter alive|dial|in|out rule-no permit|deny "
177436285Sbrian  "[src_addr[/width]] [dst_addr[/width]] [tcp|udp|icmp [src [lt|eq|gt port]] "
177536285Sbrian  "[dst [lt|eq|gt port]] [estab] [syn] [finrst]]"},
177636285Sbrian  {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
177736285Sbrian  "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
177836285Sbrian  {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address",
177931343Sbrian  "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"},
178036285Sbrian  {"ipcpretry", NULL, SetVariable, LOCAL_AUTH,
178136285Sbrian  "FSM retry period", "set ipcpretry value", (const void *)VAR_IPCPRETRY},
178236285Sbrian  {"lcpretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
178336285Sbrian  "FSM retry period", "set lcpretry value", (const void *)VAR_LCPRETRY},
178436712Sbrian  {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level",
178538622Sbrian  "set log [local] [+|-]async|cbcp|ccp|chat|command|connect|debug|hdlc|id0|"
178638622Sbrian  "ipcp|lcp|lqm|phase|tcp/ip|timer|tun..."},
178736285Sbrian  {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
178836285Sbrian  "login script", "set login chat-script", (const void *) VAR_LOGIN},
178936285Sbrian  {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
179036285Sbrian  "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD},
179136285Sbrian  {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value",
179236285Sbrian  "set mode interactive|auto|ddial|background", (const void *)VAR_MODE},
179336285Sbrian  {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value",
179436285Sbrian  "set mrru value", (const void *)VAR_MRRU},
179536285Sbrian  {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
179636285Sbrian  "MRU value", "set mru value", (const void *)VAR_MRU},
179736285Sbrian  {"mtu", NULL, SetVariable, LOCAL_AUTH,
179836285Sbrian  "interface MTU value", "set mtu value", (const void *)VAR_MTU},
179936285Sbrian  {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server",
180036285Sbrian  "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS},
180136285Sbrian  {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode",
180236285Sbrian  "set openmode active|passive [secs]", (const void *)VAR_OPENMODE},
180336285Sbrian  {"papretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
180436285Sbrian  "PAP retry period", "set papretry value", (const void *)VAR_PAPRETRY},
180536285Sbrian  {"parity", NULL, SetModemParity, LOCAL_AUTH | LOCAL_CX,
180636285Sbrian  "modem parity", "set parity [odd|even|none]"},
180736285Sbrian  {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)",
180836285Sbrian  "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE},
180940679Sbrian  {"proctitle", "title", SetProcTitle, LOCAL_AUTH,
181040679Sbrian  "Process title", "set proctitle [value]"},
181143313Sbrian#ifndef NORADIUS
181243313Sbrian  {"radius", NULL, SetVariable, LOCAL_AUTH,
181343313Sbrian  "RADIUS Config", "set radius cfgfile", (const void *)VAR_RADIUS},
181443313Sbrian#endif
181536285Sbrian  {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX,
181636285Sbrian  "Reconnect timeout", "set reconnect value ntries"},
181740665Sbrian  {"recvpipe", NULL, SetVariable, LOCAL_AUTH,
181840665Sbrian  "RECVPIPE value", "set recvpipe value", (const void *)VAR_RECVPIPE},
181936285Sbrian  {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX,
182036285Sbrian  "Redial timeout", "set redial value|random[.value|random] [attempts]"},
182140665Sbrian  {"sendpipe", NULL, SetVariable, LOCAL_AUTH,
182240665Sbrian  "SENDPIPE value", "set sendpipe value", (const void *)VAR_SENDPIPE},
182328679Sbrian  {"server", "socket", SetServer, LOCAL_AUTH,
182436774Sbrian  "server port", "set server|socket TcpPort|LocalName|none password [mask]"},
182536285Sbrian  {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX,
182636285Sbrian  "modem speed", "set speed value"},
182736285Sbrian  {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX,
182836285Sbrian  "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"},
182936285Sbrian  {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout",
183036285Sbrian  "set timeout idletime", (const void *)VAR_IDLETIMEOUT},
183136285Sbrian  {"vj", NULL, ipcp_vjset, LOCAL_AUTH,
183236285Sbrian  "vj values", "set vj slots|slotcomp [value]"},
183336285Sbrian  {"weight", NULL, mp_SetDatalinkWeight, LOCAL_AUTH | LOCAL_CX,
183436285Sbrian  "datalink weighting", "set weight n"},
183528679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
183631343Sbrian  "Display this message", "set help|? [command]", SetCommands},
183728679Sbrian  {NULL, NULL, NULL},
18386059Samurai};
18396059Samurai
18406059Samuraistatic int
184131343SbrianSetCommand(struct cmdargs const *arg)
18426059Samurai{
184336285Sbrian  if (arg->argc > arg->argn)
184436285Sbrian    FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv,
184536285Sbrian             arg->prompt, arg->cx);
184636285Sbrian  else if (arg->prompt)
184736285Sbrian    prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for"
184826516Sbrian	    " syntax help.\n");
18496059Samurai  else
185036285Sbrian    log_Printf(LogWARN, "set command must have arguments\n");
185126516Sbrian
185226516Sbrian  return 0;
18536059Samurai}
18546059Samurai
18556059Samuraistatic int
185631343SbrianAddCommand(struct cmdargs const *arg)
18576059Samurai{
18586059Samurai  struct in_addr dest, gateway, netmask;
185936285Sbrian  int gw, addrs;
18606059Samurai
186136285Sbrian  if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2)
186231598Sbrian    return -1;
186331598Sbrian
186436285Sbrian  addrs = 0;
186536285Sbrian  if (arg->argc == arg->argn+2) {
186636285Sbrian    if (!strcasecmp(arg->argv[arg->argn], "default"))
186736285Sbrian      dest.s_addr = netmask.s_addr = INADDR_ANY;
186831598Sbrian    else {
186936285Sbrian      int width;
187036285Sbrian
187143313Sbrian      if (!ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn],
187236285Sbrian	             &dest, &netmask, &width))
187336285Sbrian        return -1;
187436285Sbrian      if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6))
187536285Sbrian        addrs = ROUTE_DSTMYADDR;
187636285Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7))
187736285Sbrian        addrs = ROUTE_DSTHISADDR;
187831598Sbrian    }
187936285Sbrian    gw = 1;
188034536Sbrian  } else {
188136285Sbrian    if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
188236285Sbrian      addrs = ROUTE_DSTMYADDR;
188336285Sbrian      dest = arg->bundle->ncp.ipcp.my_ip;
188436285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
188536285Sbrian      addrs = ROUTE_DSTHISADDR;
188636285Sbrian      dest = arg->bundle->ncp.ipcp.peer_ip;
188736285Sbrian    } else
188836285Sbrian      dest = GetIpAddr(arg->argv[arg->argn]);
188936285Sbrian    netmask = GetIpAddr(arg->argv[arg->argn+1]);
189031598Sbrian    gw = 2;
18916059Samurai  }
189236285Sbrian
189336285Sbrian  if (strcasecmp(arg->argv[arg->argn+gw], "HISADDR") == 0) {
189436285Sbrian    gateway = arg->bundle->ncp.ipcp.peer_ip;
189536285Sbrian    addrs |= ROUTE_GWHISADDR;
189640561Sbrian  } else
189736285Sbrian    gateway = GetIpAddr(arg->argv[arg->argn+gw]);
189836285Sbrian
189936285Sbrian  if (bundle_SetRoute(arg->bundle, RTM_ADD, dest, gateway, netmask,
190043313Sbrian                  arg->cmd->args ? 1 : 0, (addrs & ROUTE_GWHISADDR) ? 1 : 0)
190143313Sbrian      && addrs != ROUTE_STATIC)
190236285Sbrian    route_Add(&arg->bundle->ncp.ipcp.route, addrs, dest, netmask, gateway);
190336285Sbrian
190431598Sbrian  return 0;
19056059Samurai}
19066059Samurai
19076059Samuraistatic int
190831343SbrianDeleteCommand(struct cmdargs const *arg)
19096059Samurai{
191031598Sbrian  struct in_addr dest, none;
191136285Sbrian  int addrs;
19126059Samurai
191336285Sbrian  if (arg->argc == arg->argn+1) {
191436285Sbrian    if(strcasecmp(arg->argv[arg->argn], "all") == 0) {
191536285Sbrian      route_IfDelete(arg->bundle, 0);
191636285Sbrian      route_DeleteAll(&arg->bundle->ncp.ipcp.route);
191736285Sbrian    } else {
191836285Sbrian      addrs = 0;
191936285Sbrian      if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
192036285Sbrian        dest = arg->bundle->ncp.ipcp.my_ip;
192136285Sbrian        addrs = ROUTE_DSTMYADDR;
192236285Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
192336285Sbrian        dest = arg->bundle->ncp.ipcp.peer_ip;
192436285Sbrian        addrs = ROUTE_DSTHISADDR;
192536285Sbrian      } else {
192636285Sbrian        if (strcasecmp(arg->argv[arg->argn], "default") == 0)
192736285Sbrian          dest.s_addr = INADDR_ANY;
192836285Sbrian        else
192936285Sbrian          dest = GetIpAddr(arg->argv[arg->argn]);
193036285Sbrian        addrs = ROUTE_STATIC;
193136285Sbrian      }
193231598Sbrian      none.s_addr = INADDR_ANY;
193336285Sbrian      bundle_SetRoute(arg->bundle, RTM_DELETE, dest, none, none,
193437927Sbrian                      arg->cmd->args ? 1 : 0, 0);
193536285Sbrian      route_Delete(&arg->bundle->ncp.ipcp.route, addrs, dest);
193631598Sbrian    }
193734536Sbrian  } else
193826516Sbrian    return -1;
193926516Sbrian
194026516Sbrian  return 0;
19416059Samurai}
19426059Samurai
194331343Sbrian#ifndef NOALIAS
194426031Sbrianstatic int
194531343SbrianAliasEnable(struct cmdargs const *arg)
194626031Sbrian{
194736285Sbrian  if (arg->argc == arg->argn+1) {
194836285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
194937191Sbrian      arg->bundle->AliasEnabled = 1;
195037191Sbrian      return 0;
195136285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) {
195237191Sbrian      arg->bundle->AliasEnabled = 0;
195340561Sbrian      arg->bundle->cfg.opt &= ~OPT_IFACEALIAS;
195440561Sbrian      /* Don't iface_Clear() - there may be manually configured addresses */
195526516Sbrian      return 0;
195626142Sbrian    }
195735449Sbrian  }
195836285Sbrian
195926516Sbrian  return -1;
196026031Sbrian}
196126031Sbrian
196226031Sbrian
196326031Sbrianstatic int
196431343SbrianAliasOption(struct cmdargs const *arg)
196526031Sbrian{
196638559Sbrian  long param = (long)arg->cmd->args;
196738559Sbrian
196836285Sbrian  if (arg->argc == arg->argn+1) {
196936285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
197037191Sbrian      if (arg->bundle->AliasEnabled) {
197137191Sbrian	PacketAliasSetMode(param, param);
197228679Sbrian	return 0;
197328679Sbrian      }
197436285Sbrian      log_Printf(LogWARN, "alias not enabled\n");
197536285Sbrian    } else if (strcmp(arg->argv[arg->argn], "no") == 0) {
197637191Sbrian      if (arg->bundle->AliasEnabled) {
197737191Sbrian	PacketAliasSetMode(0, param);
197828679Sbrian	return 0;
197928679Sbrian      }
198036285Sbrian      log_Printf(LogWARN, "alias not enabled\n");
198128679Sbrian    }
198235449Sbrian  }
198328679Sbrian  return -1;
198426031Sbrian}
198531343Sbrian#endif /* #ifndef NOALIAS */
198631121Sbrian
198731121Sbrianstatic int
198836285SbrianLinkCommand(struct cmdargs const *arg)
198936285Sbrian{
199036285Sbrian  if (arg->argc > arg->argn+1) {
199136285Sbrian    char namelist[LINE_LEN];
199236285Sbrian    struct datalink *cx;
199336285Sbrian    char *name;
199436285Sbrian    int result = 0;
199536285Sbrian
199636285Sbrian    if (!strcmp(arg->argv[arg->argn], "*")) {
199736285Sbrian      struct datalink *dl;
199836285Sbrian
199936285Sbrian      cx = arg->bundle->links;
200036285Sbrian      while (cx) {
200136285Sbrian        /* Watch it, the command could be a ``remove'' */
200236285Sbrian        dl = cx->next;
200336285Sbrian        FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
200436285Sbrian                 arg->prompt, cx);
200536285Sbrian        for (cx = arg->bundle->links; cx; cx = cx->next)
200636285Sbrian          if (cx == dl)
200736285Sbrian            break;		/* Pointer's still valid ! */
200836285Sbrian      }
200936285Sbrian    } else {
201036285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
201136285Sbrian      namelist[sizeof namelist - 1] = '\0';
201236285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
201336285Sbrian        if (!bundle2datalink(arg->bundle, name)) {
201436285Sbrian          log_Printf(LogWARN, "link: %s: Invalid link name\n", name);
201536285Sbrian          return 1;
201636285Sbrian        }
201736285Sbrian
201836285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
201936285Sbrian      namelist[sizeof namelist - 1] = '\0';
202036285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) {
202136285Sbrian        cx = bundle2datalink(arg->bundle, name);
202236285Sbrian        if (cx)
202336285Sbrian          FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
202436285Sbrian                   arg->prompt, cx);
202536285Sbrian        else {
202636285Sbrian          log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name);
202736285Sbrian          result++;
202836285Sbrian        }
202936285Sbrian      }
203036285Sbrian    }
203136285Sbrian    return result;
203236285Sbrian  }
203336285Sbrian
203436285Sbrian  log_Printf(LogWARN, "Usage: %s\n", arg->cmd->syntax);
203536285Sbrian  return 2;
203636285Sbrian}
203736285Sbrian
203836285Sbrianstruct link *
203936285Sbriancommand_ChooseLink(struct cmdargs const *arg)
204036285Sbrian{
204136285Sbrian  if (arg->cx)
204236285Sbrian    return &arg->cx->physical->link;
204337210Sbrian  else if (!arg->bundle->ncp.mp.cfg.mrru) {
204436285Sbrian    struct datalink *dl = bundle2datalink(arg->bundle, NULL);
204537210Sbrian    if (dl)
204637210Sbrian      return &dl->physical->link;
204736285Sbrian  }
204837210Sbrian  return &arg->bundle->ncp.mp.link;
204936285Sbrian}
205036285Sbrian
205136285Sbrianstatic const char *
205236285Sbrianident_cmd(const char *cmd, unsigned *keep, unsigned *add)
205336285Sbrian{
205436285Sbrian  const char *result;
205536285Sbrian
205636285Sbrian  switch (*cmd) {
205736285Sbrian    case 'A':
205836285Sbrian    case 'a':
205936285Sbrian      result = "accept";
206036285Sbrian      *keep = NEG_MYMASK;
206136285Sbrian      *add = NEG_ACCEPTED;
206236285Sbrian      break;
206336285Sbrian    case 'D':
206436285Sbrian    case 'd':
206536285Sbrian      switch (cmd[1]) {
206636285Sbrian        case 'E':
206736285Sbrian        case 'e':
206836285Sbrian          result = "deny";
206936285Sbrian          *keep = NEG_MYMASK;
207036285Sbrian          *add = 0;
207136285Sbrian          break;
207236285Sbrian        case 'I':
207336285Sbrian        case 'i':
207436285Sbrian          result = "disable";
207536285Sbrian          *keep = NEG_HISMASK;
207636285Sbrian          *add = 0;
207736285Sbrian          break;
207836285Sbrian        default:
207936285Sbrian          return NULL;
208036285Sbrian      }
208136285Sbrian      break;
208236285Sbrian    case 'E':
208336285Sbrian    case 'e':
208436285Sbrian      result = "enable";
208536285Sbrian      *keep = NEG_HISMASK;
208636285Sbrian      *add = NEG_ENABLED;
208736285Sbrian      break;
208836285Sbrian    default:
208936285Sbrian      return NULL;
209036285Sbrian  }
209136285Sbrian
209236285Sbrian  return result;
209336285Sbrian}
209436285Sbrian
209536285Sbrianstatic int
209636285SbrianOptSet(struct cmdargs const *arg)
209736285Sbrian{
209837574Sbrian  int bit = (int)(long)arg->cmd->args;
209936285Sbrian  const char *cmd;
210036285Sbrian  unsigned keep;			/* Keep these bits */
210136285Sbrian  unsigned add;				/* Add these bits */
210236285Sbrian
210336285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
210436285Sbrian    return 1;
210536285Sbrian
210636285Sbrian  if (add)
210736285Sbrian    arg->bundle->cfg.opt |= bit;
210836285Sbrian  else
210936285Sbrian    arg->bundle->cfg.opt &= ~bit;
211036285Sbrian  return 0;
211136285Sbrian}
211236285Sbrian
211336285Sbrianstatic int
211440561SbrianIfaceAliasOptSet(struct cmdargs const *arg)
211540561Sbrian{
211640561Sbrian  unsigned save = arg->bundle->cfg.opt;
211740561Sbrian  int result = OptSet(arg);
211840561Sbrian
211940561Sbrian  if (result == 0)
212040561Sbrian    if (Enabled(arg->bundle, OPT_IFACEALIAS) && !arg->bundle->AliasEnabled) {
212140561Sbrian      arg->bundle->cfg.opt = save;
212240561Sbrian      log_Printf(LogWARN, "Cannot enable iface-alias without IP aliasing\n");
212340561Sbrian      result = 2;
212440561Sbrian    }
212540561Sbrian
212640561Sbrian  return result;
212740561Sbrian}
212840561Sbrian
212940561Sbrianstatic int
213036285SbrianNegotiateSet(struct cmdargs const *arg)
213136285Sbrian{
213237210Sbrian  long param = (long)arg->cmd->args;
213336285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
213436285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
213536285Sbrian  const char *cmd;
213636285Sbrian  unsigned keep;			/* Keep these bits */
213736285Sbrian  unsigned add;				/* Add these bits */
213836285Sbrian
213936285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
214036285Sbrian    return 1;
214136285Sbrian
214236285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
214336285Sbrian    log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n",
214436285Sbrian              cmd, arg->cmd->name);
214536285Sbrian    return 2;
214636285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
214736285Sbrian    log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n",
214836285Sbrian              cmd, arg->cmd->name, cx->name);
214936285Sbrian    cx = NULL;
215036285Sbrian  }
215136285Sbrian
215236285Sbrian  switch (param) {
215336285Sbrian    case NEG_ACFCOMP:
215436285Sbrian      cx->physical->link.lcp.cfg.acfcomp &= keep;
215536285Sbrian      cx->physical->link.lcp.cfg.acfcomp |= add;
215636285Sbrian      break;
215736285Sbrian    case NEG_CHAP:
215836285Sbrian      cx->physical->link.lcp.cfg.chap &= keep;
215936285Sbrian      cx->physical->link.lcp.cfg.chap |= add;
216036285Sbrian      break;
216136285Sbrian    case NEG_DEFLATE:
216236285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep;
216336285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add;
216436285Sbrian      break;
216536285Sbrian    case NEG_DNS:
216636285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep;
216736285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add;
216836285Sbrian      break;
216936285Sbrian    case NEG_LQR:
217036285Sbrian      cx->physical->link.lcp.cfg.lqr &= keep;
217136285Sbrian      cx->physical->link.lcp.cfg.lqr |= add;
217236285Sbrian      break;
217336285Sbrian    case NEG_PAP:
217436285Sbrian      cx->physical->link.lcp.cfg.pap &= keep;
217536285Sbrian      cx->physical->link.lcp.cfg.pap |= add;
217636285Sbrian      break;
217736285Sbrian    case NEG_PPPDDEFLATE:
217836285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep;
217936285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add;
218036285Sbrian      break;
218136285Sbrian    case NEG_PRED1:
218236285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep;
218336285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] |= add;
218436285Sbrian      break;
218536285Sbrian    case NEG_PROTOCOMP:
218636285Sbrian      cx->physical->link.lcp.cfg.protocomp &= keep;
218736285Sbrian      cx->physical->link.lcp.cfg.protocomp |= add;
218836285Sbrian      break;
218936285Sbrian    case NEG_SHORTSEQ:
219040622Sbrian      switch (bundle_Phase(arg->bundle)) {
219140622Sbrian        case PHASE_DEAD:
219240622Sbrian          break;
219340622Sbrian        case PHASE_ESTABLISH:
219440622Sbrian          /* Make sure none of our links are DATALINK_LCP or greater */
219540622Sbrian          if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
219640622Sbrian            log_Printf(LogWARN, "shortseq: Only changable before"
219740622Sbrian                       " LCP negotiations\n");
219840622Sbrian            return 1;
219940622Sbrian          }
220040622Sbrian          break;
220140622Sbrian        default:
220240622Sbrian          log_Printf(LogWARN, "shortseq: Only changable at phase"
220340622Sbrian                     " DEAD/ESTABLISH\n");
220440622Sbrian          return 1;
220536285Sbrian      }
220640622Sbrian      arg->bundle->ncp.mp.cfg.shortseq &= keep;
220740622Sbrian      arg->bundle->ncp.mp.cfg.shortseq |= add;
220836285Sbrian      break;
220936285Sbrian    case NEG_VJCOMP:
221036285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg &= keep;
221136285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg |= add;
221236285Sbrian      break;
221336285Sbrian  }
221436285Sbrian
221536285Sbrian  return 0;
221636285Sbrian}
221736285Sbrian
221836285Sbrianstatic struct cmdtab const NegotiateCommands[] = {
221936285Sbrian  {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids",
222036285Sbrian  "disable|enable", (const void *)OPT_IDCHECK},
222140666Sbrian  {"iface-alias", NULL, IfaceAliasOptSet, LOCAL_AUTH,
222240666Sbrian   "retain interface addresses", "disable|enable",
222340666Sbrian   (const void *)OPT_IFACEALIAS},
222436285Sbrian  {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface",
222536285Sbrian  "disable|enable", (const void *)OPT_LOOPBACK},
222636285Sbrian  {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file",
222736285Sbrian  "disable|enable", (const void *)OPT_PASSWDAUTH},
222840665Sbrian  {"proxy", NULL, OptSet, LOCAL_AUTH, "Create a proxy ARP entry",
222936285Sbrian  "disable|enable", (const void *)OPT_PROXY},
223040665Sbrian  {"proxyall", NULL, OptSet, LOCAL_AUTH, "Proxy ARP for all remote hosts",
223140665Sbrian  "disable|enable", (const void *)OPT_PROXYALL},
223236285Sbrian  {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes",
223336285Sbrian  "disable|enable", (const void *)OPT_SROUTES},
223436285Sbrian  {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput",
223536285Sbrian  "disable|enable", (const void *)OPT_THROUGHPUT},
223636285Sbrian  {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp",
223736285Sbrian  "disable|enable", (const void *)OPT_UTMP},
223836285Sbrian
223940665Sbrian#define OPT_MAX 9	/* accept/deny allowed below and not above */
224036285Sbrian
224136285Sbrian  {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
224236285Sbrian  "Address & Control field compression", "accept|deny|disable|enable",
224336285Sbrian  (const void *)NEG_ACFCOMP},
224436285Sbrian  {"chap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
224536285Sbrian  "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable",
224636285Sbrian  (const void *)NEG_CHAP},
224736285Sbrian  {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
224836285Sbrian  "Deflate compression", "accept|deny|disable|enable",
224936285Sbrian  (const void *)NEG_DEFLATE},
225036285Sbrian  {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
225136285Sbrian  "Deflate (type 24) compression", "accept|deny|disable|enable",
225236285Sbrian  (const void *)NEG_PPPDDEFLATE},
225336285Sbrian  {"dns", NULL, NegotiateSet, LOCAL_AUTH,
225436285Sbrian  "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS},
225536285Sbrian  {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
225636285Sbrian  "Link Quality Reports", "accept|deny|disable|enable",
225736285Sbrian  (const void *)NEG_LQR},
225836285Sbrian  {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
225936285Sbrian  "Password Authentication protocol", "accept|deny|disable|enable",
226036285Sbrian  (const void *)NEG_PAP},
226136285Sbrian  {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
226236285Sbrian  "Predictor 1 compression", "accept|deny|disable|enable",
226336285Sbrian  (const void *)NEG_PRED1},
226436285Sbrian  {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
226536285Sbrian  "Protocol field compression", "accept|deny|disable|enable",
226636285Sbrian  (const void *)NEG_PROTOCOMP},
226736285Sbrian  {"shortseq", NULL, NegotiateSet, LOCAL_AUTH,
226836285Sbrian  "MP Short Sequence Numbers", "accept|deny|disable|enable",
226936285Sbrian  (const void *)NEG_SHORTSEQ},
227036285Sbrian  {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH,
227136285Sbrian  "Van Jacobson header compression", "accept|deny|disable|enable",
227236285Sbrian  (const void *)NEG_VJCOMP},
227336285Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
227436285Sbrian  "Display this message", "accept|deny|disable|enable help|? [value]",
227536285Sbrian  NegotiateCommands},
227636285Sbrian  {NULL, NULL, NULL},
227736285Sbrian};
227836285Sbrian
227936285Sbrianstatic int
228036285SbrianNegotiateCommand(struct cmdargs const *arg)
228136285Sbrian{
228236285Sbrian  if (arg->argc > arg->argn) {
228336285Sbrian    char const *argv[3];
228436285Sbrian    unsigned keep, add;
228536285Sbrian    int n;
228636285Sbrian
228736285Sbrian    if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL)
228836285Sbrian      return -1;
228936285Sbrian    argv[2] = NULL;
229036285Sbrian
229136285Sbrian    for (n = arg->argn; n < arg->argc; n++) {
229236285Sbrian      argv[1] = arg->argv[n];
229336285Sbrian      FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ?
229436285Sbrian               0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx);
229536285Sbrian    }
229636285Sbrian  } else if (arg->prompt)
229736285Sbrian    prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n",
229836285Sbrian	    arg->argv[arg->argn-1]);
229936285Sbrian  else
230036285Sbrian    log_Printf(LogWARN, "%s command must have arguments\n",
230136285Sbrian              arg->argv[arg->argn] );
230236285Sbrian
230336285Sbrian  return 0;
230436285Sbrian}
230536285Sbrian
230636285Sbrianconst char *
230736285Sbriancommand_ShowNegval(unsigned val)
230836285Sbrian{
230936285Sbrian  switch (val&3) {
231036285Sbrian    case 1: return "disabled & accepted";
231136285Sbrian    case 2: return "enabled & denied";
231236285Sbrian    case 3: return "enabled & accepted";
231336285Sbrian  }
231436285Sbrian  return "disabled & denied";
231536285Sbrian}
231636934Sbrian
231736934Sbrianstatic int
231836934SbrianClearCommand(struct cmdargs const *arg)
231936934Sbrian{
232036934Sbrian  struct pppThroughput *t;
232136934Sbrian  struct datalink *cx;
232236934Sbrian  int i, clear_type;
232336934Sbrian
232436934Sbrian  if (arg->argc < arg->argn + 1)
232536934Sbrian    return -1;
232636934Sbrian
232736934Sbrian  if (strcasecmp(arg->argv[arg->argn], "modem") == 0) {
232836934Sbrian    cx = arg->cx;
232936934Sbrian    if (!cx)
233036934Sbrian      cx = bundle2datalink(arg->bundle, NULL);
233136934Sbrian    if (!cx) {
233236934Sbrian      log_Printf(LogWARN, "A link must be specified for ``clear modem''\n");
233336934Sbrian      return 1;
233436934Sbrian    }
233536934Sbrian    t = &cx->physical->link.throughput;
233636934Sbrian  } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0)
233736934Sbrian    t = &arg->bundle->ncp.ipcp.throughput;
233836934Sbrian  else
233936934Sbrian    return -1;
234036934Sbrian
234136934Sbrian  if (arg->argc > arg->argn + 1) {
234236934Sbrian    clear_type = 0;
234336934Sbrian    for (i = arg->argn + 1; i < arg->argc; i++)
234436934Sbrian      if (strcasecmp(arg->argv[i], "overall") == 0)
234536934Sbrian        clear_type |= THROUGHPUT_OVERALL;
234636934Sbrian      else if (strcasecmp(arg->argv[i], "current") == 0)
234736934Sbrian        clear_type |= THROUGHPUT_CURRENT;
234836934Sbrian      else if (strcasecmp(arg->argv[i], "peak") == 0)
234936934Sbrian        clear_type |= THROUGHPUT_PEAK;
235036934Sbrian      else
235136934Sbrian        return -1;
235236934Sbrian  } else
235336934Sbrian    clear_type = THROUGHPUT_ALL;
235436934Sbrian
235536934Sbrian  throughput_clear(t, clear_type, arg->prompt);
235636934Sbrian  return 0;
235736934Sbrian}
235840561Sbrian
235940561Sbrianstatic int
236040561SbrianRunListCommand(struct cmdargs const *arg)
236140561Sbrian{
236240561Sbrian  const char *cmd = arg->argc ? arg->argv[arg->argc - 1] : "???";
236340561Sbrian
236440561Sbrian  if (arg->argc > arg->argn)
236540561Sbrian    FindExec(arg->bundle, arg->cmd->args, arg->argc, arg->argn, arg->argv,
236640561Sbrian             arg->prompt, arg->cx);
236740561Sbrian  else if (arg->prompt)
236840561Sbrian    prompt_Printf(arg->prompt, "Use `%s help' to get a list or `%s help"
236940561Sbrian                  " <option>' for syntax help.\n", cmd, cmd);
237040561Sbrian  else
237140561Sbrian    log_Printf(LogWARN, "%s command must have arguments\n", cmd);
237240561Sbrian
237340561Sbrian  return 0;
237440561Sbrian}
237540561Sbrian
237640561Sbrianstatic int
237740561SbrianIfaceAddCommand(struct cmdargs const *arg)
237840561Sbrian{
237940561Sbrian  int bits, n, how;
238040561Sbrian  struct in_addr ifa, mask, brd;
238140561Sbrian
238240664Sbrian  if (arg->argc == arg->argn + 1) {
238343313Sbrian    if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL))
238440561Sbrian      return -1;
238540664Sbrian    mask.s_addr = brd.s_addr = INADDR_BROADCAST;
238640664Sbrian  } else {
238740664Sbrian    if (arg->argc == arg->argn + 2) {
238843313Sbrian      if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, &mask, &bits))
238940664Sbrian        return -1;
239040664Sbrian      n = 1;
239140664Sbrian    } else if (arg->argc == arg->argn + 3) {
239243313Sbrian      if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL))
239340664Sbrian        return -1;
239443313Sbrian      if (!ParseAddr(NULL, arg->argv[arg->argn + 1], &mask, NULL, NULL))
239540664Sbrian        return -1;
239640664Sbrian      n = 2;
239740664Sbrian    } else
239840561Sbrian      return -1;
239940561Sbrian
240043313Sbrian    if (!ParseAddr(NULL, arg->argv[arg->argn + n], &brd, NULL, NULL))
240140664Sbrian      return -1;
240240664Sbrian  }
240340561Sbrian
240440561Sbrian  how = IFACE_ADD_LAST;
240540561Sbrian  if (arg->cmd->args)
240640561Sbrian    how |= IFACE_FORCE_ADD;
240740561Sbrian
240840561Sbrian  return !iface_inAdd(arg->bundle->iface, ifa, mask, brd, how);
240940561Sbrian}
241040561Sbrian
241140561Sbrianstatic int
241240561SbrianIfaceDeleteCommand(struct cmdargs const *arg)
241340561Sbrian{
241440561Sbrian  struct in_addr ifa;
241540561Sbrian  int ok;
241640561Sbrian
241740561Sbrian  if (arg->argc != arg->argn + 1)
241840561Sbrian    return -1;
241940561Sbrian
242043313Sbrian  if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL))
242140561Sbrian    return -1;
242240561Sbrian
242340561Sbrian  if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED &&
242440561Sbrian      arg->bundle->ncp.ipcp.my_ip.s_addr == ifa.s_addr) {
242540561Sbrian    log_Printf(LogWARN, "%s: Cannot remove active interface address\n",
242640561Sbrian               inet_ntoa(ifa));
242740561Sbrian    return 1;
242840561Sbrian  }
242940561Sbrian
243040561Sbrian  ok = iface_inDelete(arg->bundle->iface, ifa);
243140561Sbrian  if (!ok) {
243240561Sbrian    if (arg->cmd->args)
243340561Sbrian      ok = 1;
243440561Sbrian    else if (arg->prompt)
243540561Sbrian      prompt_Printf(arg->prompt, "%s: No such address\n", inet_ntoa(ifa));
243640561Sbrian    else
243740561Sbrian      log_Printf(LogWARN, "%s: No such address\n", inet_ntoa(ifa));
243840561Sbrian  }
243940561Sbrian
244040561Sbrian  return !ok;
244140561Sbrian}
244240561Sbrian
244340561Sbrianstatic int
244440561SbrianIfaceClearCommand(struct cmdargs const *arg)
244540561Sbrian{
244640561Sbrian  int how;
244740561Sbrian
244840561Sbrian  if (arg->argc != arg->argn)
244940561Sbrian    return -1;
245040561Sbrian
245140941Sbrian  how = arg->bundle->ncp.ipcp.fsm.state == ST_OPENED ||
245240941Sbrian        arg->bundle->phys_type.all & PHYS_AUTO ?
245340561Sbrian        IFACE_CLEAR_ALIASES : IFACE_CLEAR_ALL;
245440561Sbrian  iface_Clear(arg->bundle->iface, how);
245540561Sbrian
245640561Sbrian  return 0;
245740561Sbrian}
245840679Sbrian
245940679Sbrianstatic int
246040679SbrianSetProcTitle(struct cmdargs const *arg)
246140679Sbrian{
246240679Sbrian  static char title[LINE_LEN];
246340679Sbrian  char *argv[MAXARGS], *ptr;
246440679Sbrian  int len, remaining, f, argc = arg->argc - arg->argn;
246540679Sbrian
246640679Sbrian  if (arg->argc == arg->argn) {
246740679Sbrian    arg->bundle->argv[0] = arg->bundle->argv0;
246840679Sbrian    arg->bundle->argv[1] = arg->bundle->argv1;
246940679Sbrian    return 0;
247040679Sbrian  }
247140679Sbrian
247240679Sbrian  if (argc >= sizeof argv / sizeof argv[0]) {
247340679Sbrian    argc = sizeof argv / sizeof argv[0] - 1;
247440679Sbrian    log_Printf(LogWARN, "Truncating proc title to %d args\n", argc);
247540679Sbrian  }
247643888Sbrian  command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 1);
247740679Sbrian
247840679Sbrian  ptr = title;
247940679Sbrian  remaining = sizeof title - 1;
248040679Sbrian  for (f = 0; f < argc && remaining; f++) {
248140679Sbrian    if (f) {
248240679Sbrian      *ptr++ = ' ';
248340679Sbrian      remaining--;
248440679Sbrian    }
248540679Sbrian    len = strlen(argv[f]);
248640679Sbrian    if (len > remaining)
248740679Sbrian      len = remaining;
248840679Sbrian    memcpy(ptr, argv[f], len);
248940679Sbrian    remaining -= len;
249040679Sbrian    ptr += len;
249140679Sbrian  }
249240679Sbrian  *ptr = '\0';
249340679Sbrian
249440679Sbrian  arg->bundle->argv[0] = title;
249540679Sbrian  arg->bundle->argv[1] = NULL;
249640679Sbrian
249740679Sbrian  return 0;
249840679Sbrian}
2499