Index: cvs2svn/branches/MP/usr.sbin/ppp/auth.c =================================================================== --- cvs2svn/branches/MP/usr.sbin/ppp/auth.c (revision 33933) +++ cvs2svn/branches/MP/usr.sbin/ppp/auth.c (revision 33934) @@ -1,245 +1,245 @@ /* * PPP Secret Key Module * * Written by Toshiharu OHNO (tony-o@iij.ad.jp) * * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the Internet Initiative Japan, Inc. The name of the * IIJ may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: auth.c,v 1.27.2.8 1998/02/13 05:10:05 brian Exp $ + * $Id: auth.c,v 1.27.2.9 1998/02/21 01:44:57 brian Exp $ * * TODO: * o Implement check against with registered IP addresses. */ #include #include #include #include #include #include #include #include "command.h" #include "mbuf.h" #include "defs.h" #include "timer.h" #include "fsm.h" #include "iplist.h" #include "throughput.h" #include "ipcp.h" #include "loadalias.h" #include "vars.h" #include "auth.h" #include "systems.h" #include "lcp.h" #include "hdlc.h" #include "async.h" #include "link.h" #include "descriptor.h" #include "physical.h" #include "chat.h" #include "lcpproto.h" const char * Auth2Nam(u_short auth) { switch (auth) { case PROTO_PAP: return "PAP"; case PROTO_CHAP: return "CHAP"; case 0: return "none"; } return "unknown"; } void LocalAuthInit() { if (!(mode&MODE_DAEMON)) /* We're allowed in interactive mode */ VarLocalAuth = LOCAL_AUTH; else if (VarHaveLocalAuthKey) VarLocalAuth = *VarLocalAuthKey == '\0' ? LOCAL_AUTH : LOCAL_NO_AUTH; else switch (LocalAuthValidate(SECRETFILE, VarShortHost, "")) { case NOT_FOUND: VarLocalAuth = LOCAL_DENY; break; case VALID: VarLocalAuth = LOCAL_AUTH; break; case INVALID: VarLocalAuth = LOCAL_NO_AUTH; break; } } LOCAL_AUTH_VALID LocalAuthValidate(const char *fname, const char *system, const char *key) { FILE *fp; int n; char *vector[3]; char buff[LINE_LEN]; LOCAL_AUTH_VALID rc; rc = NOT_FOUND; /* No system entry */ fp = OpenSecret(fname); if (fp == NULL) return (rc); while (fgets(buff, sizeof buff, fp)) { if (buff[0] == '#') continue; buff[strlen(buff) - 1] = 0; memset(vector, '\0', sizeof vector); n = MakeArgs(buff, vector, VECSIZE(vector)); if (n < 1) continue; if (strcmp(vector[0], system) == 0) { if ((vector[1] == (char *) NULL && (key == NULL || *key == '\0')) || (vector[1] != (char *) NULL && strcmp(vector[1], key) == 0)) { rc = VALID; /* Valid */ } else { rc = INVALID; /* Invalid */ } break; } } CloseSecret(fp); return (rc); } int AuthValidate(struct bundle *bundle, const char *fname, const char *system, const char *key, struct physical *physical) { FILE *fp; int n; char *vector[5]; char buff[LINE_LEN]; char passwd[100]; fp = OpenSecret(fname); if (fp == NULL) return (0); while (fgets(buff, sizeof buff, fp)) { if (buff[0] == '#') continue; buff[strlen(buff) - 1] = 0; memset(vector, '\0', sizeof vector); n = MakeArgs(buff, vector, VECSIZE(vector)); if (n < 2) continue; if (strcmp(vector[0], system) == 0) { chat_ExpandString(NULL, vector[1], passwd, sizeof passwd, 0); if (strcmp(passwd, key) == 0) { CloseSecret(fp); if (n > 2 && !UseHisaddr(bundle, vector[2], 1)) return (0); /* XXX This should be deferred - we may join an existing bundle ! */ ipcp_Setup(&IpcpInfo); if (n > 3) SetLabel(vector[3]); return (1); /* Valid */ } } } CloseSecret(fp); return (0); /* Invalid */ } char * AuthGetSecret(struct bundle *bundle, const char *fname, const char *system, int len, int setaddr, struct physical *physical) { FILE *fp; int n; char *vector[5]; char buff[LINE_LEN]; static char passwd[100]; fp = OpenSecret(fname); if (fp == NULL) return (NULL); while (fgets(buff, sizeof buff, fp)) { if (buff[0] == '#') continue; buff[strlen(buff) - 1] = 0; memset(vector, '\0', sizeof vector); n = MakeArgs(buff, vector, VECSIZE(vector)); if (n < 2) continue; if (strlen(vector[0]) == len && strncmp(vector[0], system, len) == 0) { chat_ExpandString(NULL, vector[1], passwd, sizeof passwd, 0); if (setaddr) memset(&IpcpInfo.cfg.peer_range, '\0', sizeof IpcpInfo.cfg.peer_range); if (n > 2 && setaddr) if (UseHisaddr(bundle, vector[2], 1)) /* XXX This should be deferred - we may join an existing bundle ! */ ipcp_Setup(&IpcpInfo); else return NULL; if (n > 3) SetLabel(vector[3]); return (passwd); } } CloseSecret(fp); return (NULL); /* Invalid */ } static void AuthTimeout(void *vauthp) { - struct pppTimer *tp; struct authinfo *authp = (struct authinfo *)vauthp; - tp = &authp->authtimer; - StopTimer(tp); + StopTimer(&authp->authtimer); if (--authp->retry > 0) { - StartTimer(tp); - (authp->ChallengeFunc) (++authp->id, authp->physical); + StartTimer(&authp->authtimer); + (*authp->ChallengeFunc)(authp, ++authp->id, authp->physical); } } void -StartAuthChallenge(struct authinfo *authp, struct physical *physical) +authinfo_Init(struct authinfo *authinfo) { - struct pppTimer *tp; + memset(authinfo, '\0', sizeof(struct authinfo)); +} - assert(authp->physical == NULL); - +void +StartAuthChallenge(struct authinfo *authp, struct physical *physical, + void (*fn)(struct authinfo *, int, struct physical *)) +{ + authp->ChallengeFunc = fn; authp->physical = physical; - - tp = &authp->authtimer; - StopTimer(tp); - tp->func = AuthTimeout; - tp->load = VarRetryTimeout * SECTICKS; - tp->state = TIMER_STOPPED; - tp->arg = (void *) authp; - StartTimer(tp); + StopTimer(&authp->authtimer); + authp->authtimer.func = AuthTimeout; + authp->authtimer.load = VarRetryTimeout * SECTICKS; + authp->authtimer.state = TIMER_STOPPED; + authp->authtimer.arg = (void *) authp; authp->retry = 3; authp->id = 1; - (authp->ChallengeFunc) (authp->id, physical); + (*authp->ChallengeFunc)(authp, authp->id, physical); + StartTimer(&authp->authtimer); } void StopAuthTimer(struct authinfo *authp) { StopTimer(&authp->authtimer); authp->physical = NULL; } Index: cvs2svn/branches/MP/usr.sbin/ppp/auth.h =================================================================== --- cvs2svn/branches/MP/usr.sbin/ppp/auth.h (revision 33933) +++ cvs2svn/branches/MP/usr.sbin/ppp/auth.h (revision 33934) @@ -1,47 +1,50 @@ /* * Written by Toshiharu OHNO (tony-o@iij.ad.jp) * * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the Internet Initiative Japan. The name of the * IIJ may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: auth.h,v 1.10.2.2 1998/02/02 19:32:01 brian Exp $ + * $Id: auth.h,v 1.10.2.3 1998/02/07 20:49:20 brian Exp $ * * TODO: */ struct physical; typedef enum { VALID, INVALID, NOT_FOUND } LOCAL_AUTH_VALID; struct authinfo { - void (*ChallengeFunc) (int, struct physical *); + void (*ChallengeFunc)(struct authinfo *, int, struct physical *); struct pppTimer authtimer; int retry; int id; struct physical *physical; }; +extern void authinfo_Init(struct authinfo *); + extern const char *Auth2Nam(u_short); extern LOCAL_AUTH_VALID LocalAuthValidate(const char *, const char *, const char *); extern void StopAuthTimer(struct authinfo *); -extern void StartAuthChallenge(struct authinfo *, struct physical *); +extern void StartAuthChallenge(struct authinfo *, struct physical *, + void (*fn)(struct authinfo *, int, struct physical *)); extern void LocalAuthInit(void); extern int AuthValidate(struct bundle *, const char *, const char *, const char *, struct physical *); extern char *AuthGetSecret(struct bundle *, const char *, const char *, int, int, struct physical *); Index: cvs2svn/branches/MP/usr.sbin/ppp/bundle.c =================================================================== --- cvs2svn/branches/MP/usr.sbin/ppp/bundle.c (revision 33933) +++ cvs2svn/branches/MP/usr.sbin/ppp/bundle.c (revision 33934) @@ -1,723 +1,729 @@ /*- * Copyright (c) 1998 Brian Somers * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: bundle.c,v 1.1.2.16 1998/02/23 00:38:16 brian Exp $ + * $Id: bundle.c,v 1.1.2.17 1998/02/27 01:22:16 brian Exp $ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "command.h" #include "mbuf.h" #include "log.h" #include "id.h" #include "defs.h" #include "timer.h" #include "fsm.h" #include "iplist.h" #include "hdlc.h" #include "throughput.h" #include "ipcp.h" #include "link.h" #include "bundle.h" #include "loadalias.h" #include "vars.h" #include "arp.h" #include "systems.h" #include "route.h" #include "lcp.h" #include "ccp.h" #include "async.h" #include "descriptor.h" #include "physical.h" #include "modem.h" #include "main.h" #include "auth.h" #include "lcpproto.h" #include "pap.h" #include "chap.h" #include "tun.h" #include "prompt.h" #include "chat.h" #include "datalink.h" #include "ip.h" static const char *PhaseNames[] = { "Dead", "Establish", "Authenticate", "Network", "Terminate" }; const char * bundle_PhaseName(struct bundle *bundle) { return bundle->phase <= PHASE_TERMINATE ? PhaseNames[bundle->phase] : "unknown"; } void bundle_NewPhase(struct bundle *bundle, struct physical *physical, u_int new) { if (new == bundle->phase) return; - if (new <= PHASE_NETWORK) - LogPrintf(LogPHASE, "bundle_NewPhase: %s\n", PhaseNames[new]); + if (new <= PHASE_TERMINATE) + LogPrintf(LogPHASE, "bundle: %s\n", PhaseNames[new]); switch (new) { case PHASE_DEAD: bundle->phase = new; break; case PHASE_ESTABLISH: bundle->phase = new; break; case PHASE_AUTHENTICATE: - LcpInfo.auth_ineed = LcpInfo.want_auth; - LcpInfo.auth_iwait = LcpInfo.his_auth; - if (LcpInfo.his_auth || LcpInfo.want_auth) { - LogPrintf(LogPHASE, " his = %s, mine = %s\n", - Auth2Nam(LcpInfo.his_auth), Auth2Nam(LcpInfo.want_auth)); - /* XXX-ML AuthPapInfo and AuthChapInfo must be allocated! */ - if (LcpInfo.his_auth == PROTO_PAP) - StartAuthChallenge(&AuthPapInfo, physical); - if (LcpInfo.want_auth == PROTO_CHAP) - StartAuthChallenge(&AuthChapInfo, physical); - bundle->phase = new; - prompt_Display(&prompt, bundle); - } else - bundle_NewPhase(bundle, physical, PHASE_NETWORK); + bundle->phase = new; + prompt_Display(&prompt, bundle); break; case PHASE_NETWORK: tun_configure(bundle, LcpInfo.his_mru, modem_Speed(physical)); ipcp_Setup(&IpcpInfo); FsmUp(&IpcpInfo.fsm); FsmOpen(&IpcpInfo.fsm); /* Fall through */ case PHASE_TERMINATE: bundle->phase = new; prompt_Display(&prompt, bundle); break; } } static int bundle_CleanInterface(const struct bundle *bundle) { int s; struct ifreq ifrq; struct ifaliasreq ifra; s = ID0socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { LogPrintf(LogERROR, "bundle_CleanInterface: socket(): %s\n", strerror(errno)); return (-1); } strncpy(ifrq.ifr_name, bundle->ifname, sizeof ifrq.ifr_name - 1); ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; while (ID0ioctl(s, SIOCGIFADDR, &ifrq) == 0) { memset(&ifra.ifra_mask, '\0', sizeof ifra.ifra_mask); strncpy(ifra.ifra_name, bundle->ifname, sizeof ifra.ifra_name - 1); ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0'; ifra.ifra_addr = ifrq.ifr_addr; if (ID0ioctl(s, SIOCGIFDSTADDR, &ifrq) < 0) { if (ifra.ifra_addr.sa_family == AF_INET) LogPrintf(LogERROR, "bundle_CleanInterface: Can't get dst for %s on %s !\n", inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr), bundle->ifname); return 0; } ifra.ifra_broadaddr = ifrq.ifr_dstaddr; if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) { if (ifra.ifra_addr.sa_family == AF_INET) LogPrintf(LogERROR, "bundle_CleanInterface: Can't delete %s address on %s !\n", inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr), bundle->ifname); return 0; } } return 1; } static void bundle_LayerStart(void *v, struct fsm *fp) { /* The given FSM is about to start up ! */ struct bundle *bundle = (struct bundle *)v; if (fp == &LcpInfo.fsm) bundle_NewPhase(bundle, link2physical(fp->link), PHASE_ESTABLISH); } static void bundle_LayerUp(void *v, struct fsm *fp) { /* * The given fsm is now up - * If it's a datalink, authenticate. + * If it's a datalink, enter network phase * If it's an NCP, tell our background mode parent to go away. */ struct bundle *bundle = (struct bundle *)v; - if (fp == &LcpInfo.fsm) - bundle_NewPhase(bundle, link2physical(fp->link), PHASE_AUTHENTICATE); + if (fp->proto == PROTO_LCP) + bundle_NewPhase(bundle, link2physical(fp->link), PHASE_NETWORK); if (fp == &IpcpInfo.fsm) if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) { char c = EX_NORMAL; if (write(BGFiledes[1], &c, 1) == 1) LogPrintf(LogPHASE, "Parent notified of success.\n"); else LogPrintf(LogPHASE, "Failed to notify parent of success.\n"); close(BGFiledes[1]); BGFiledes[1] = -1; } } static void bundle_LayerDown(void *v, struct fsm *fp) { /* * The given FSM has been told to come down. * We don't do anything here, as the FSM will eventually * come up or down and will call LayerUp or LayerFinish. */ } static void bundle_LayerFinish(void *v, struct fsm *fp) { /* The given fsm is now down (fp cannot be NULL) * * If it's the last LCP, FsmDown all NCPs * If it's the last NCP, FsmClose all LCPs and enter TERMINATE phase. */ struct bundle *bundle = (struct bundle *)v; if (fp == &LcpInfo.fsm) { FsmDown(&IpcpInfo.fsm); /* You've lost your underlings */ FsmClose(&IpcpInfo.fsm); /* ST_INITIAL please */ } else if (fp == &IpcpInfo.fsm) { struct datalink *dl; bundle_NewPhase(bundle, NULL, PHASE_TERMINATE); for (dl = bundle->links; dl; dl = dl->next) datalink_Close(dl, 1); } } int bundle_LinkIsUp(const struct bundle *bundle) { return IpcpInfo.fsm.state == ST_OPENED; } void bundle_Close(struct bundle *bundle, const char *name, int staydown) { /* * Please close the given datalink. * * If name == NULL or name is the last datalink, enter TERMINATE phase. * * If name == NULL, FsmClose all NCPs. * * If name is the last datalink, FsmClose all NCPs. * * If isn't the last datalink, just Close that datalink. */ struct datalink *dl; if (IpcpInfo.fsm.state > ST_CLOSED || IpcpInfo.fsm.state == ST_STARTING) { bundle_NewPhase(bundle, NULL, PHASE_TERMINATE); FsmClose(&IpcpInfo.fsm); if (staydown) for (dl = bundle->links; dl; dl = dl->next) datalink_StayDown(dl); } else for (dl = bundle->links; dl; dl = dl->next) datalink_Close(dl, staydown); } /* * Open tunnel device and returns its descriptor */ #define MAX_TUN 256 /* * MAX_TUN is set at 256 because that is the largest minor number * we can use (certainly with mknod(1) anyway. The search for a * device aborts when it reaches the first `Device not configured' * (ENXIO) or the third `No such file or directory' (ENOENT) error. */ struct bundle * bundle_Create(const char *prefix) { int s, enoentcount, err; struct ifreq ifrq; static struct bundle bundle; /* there can be only one */ if (bundle.ifname != NULL) { /* Already allocated ! */ LogPrintf(LogERROR, "bundle_Create: There's only one BUNDLE !\n"); return NULL; } err = ENOENT; enoentcount = 0; for (bundle.unit = 0; bundle.unit <= MAX_TUN; bundle.unit++) { snprintf(bundle.dev, sizeof bundle.dev, "%s%d", prefix, bundle.unit); bundle.tun_fd = ID0open(bundle.dev, O_RDWR); if (bundle.tun_fd >= 0) break; if (errno == ENXIO) { bundle.unit = MAX_TUN; err = errno; } else if (errno == ENOENT) { if (++enoentcount > 2) bundle.unit = MAX_TUN; } else err = errno; } if (bundle.unit > MAX_TUN) { prompt_Printf(&prompt, "No tunnel device is available (%s).\n", strerror(err)); return NULL; } LogSetTun(bundle.unit); s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { LogPrintf(LogERROR, "bundle_Create: socket(): %s\n", strerror(errno)); close(bundle.tun_fd); return NULL; } bundle.ifname = strrchr(bundle.dev, '/'); if (bundle.ifname == NULL) bundle.ifname = bundle.dev; else bundle.ifname++; /* * Now, bring up the interface. */ memset(&ifrq, '\0', sizeof ifrq); strncpy(ifrq.ifr_name, bundle.ifname, sizeof ifrq.ifr_name - 1); ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { LogPrintf(LogERROR, "OpenTunnel: ioctl(SIOCGIFFLAGS): %s\n", strerror(errno)); close(s); close(bundle.tun_fd); bundle.ifname = NULL; return NULL; } ifrq.ifr_flags |= IFF_UP; if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { LogPrintf(LogERROR, "OpenTunnel: ioctl(SIOCSIFFLAGS): %s\n", strerror(errno)); close(s); close(bundle.tun_fd); bundle.ifname = NULL; return NULL; } close(s); if ((bundle.ifIndex = GetIfIndex(bundle.ifname)) < 0) { LogPrintf(LogERROR, "OpenTunnel: Can't find ifindex.\n"); close(bundle.tun_fd); bundle.ifname = NULL; return NULL; } prompt_Printf(&prompt, "Using interface: %s\n", bundle.ifname); LogPrintf(LogPHASE, "Using interface: %s\n", bundle.ifname); bundle.routing_seq = 0; bundle.phase = 0; bundle.fsm.LayerStart = bundle_LayerStart; bundle.fsm.LayerUp = bundle_LayerUp; bundle.fsm.LayerDown = bundle_LayerDown; bundle.fsm.LayerFinish = bundle_LayerFinish; bundle.fsm.object = &bundle; bundle.links = datalink_Create("Modem", &bundle, &bundle.fsm); if (bundle.links == NULL) { LogPrintf(LogERROR, "Cannot create data link: %s\n", strerror(errno)); close(bundle.tun_fd); bundle.ifname = NULL; return NULL; } ipcp_Init(&IpcpInfo, &bundle, &bundle.links->physical->link, &bundle.fsm); /* Clean out any leftover crud */ bundle_CleanInterface(&bundle); return &bundle; } static void bundle_DownInterface(struct bundle *bundle) { struct ifreq ifrq; int s; DeleteIfRoutes(bundle, 1); s = ID0socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { LogPrintf(LogERROR, "bundle_DownInterface: socket: %s\n", strerror(errno)); return; } memset(&ifrq, '\0', sizeof ifrq); strncpy(ifrq.ifr_name, bundle->ifname, sizeof ifrq.ifr_name - 1); ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { LogPrintf(LogERROR, "bundle_DownInterface: ioctl(SIOCGIFFLAGS): %s\n", strerror(errno)); close(s); return; } ifrq.ifr_flags &= ~IFF_UP; if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { LogPrintf(LogERROR, "bundle_DownInterface: ioctl(SIOCSIFFLAGS): %s\n", strerror(errno)); close(s); return; } close(s); } void bundle_Destroy(struct bundle *bundle) { struct datalink *dl; if (mode & MODE_AUTO) { IpcpCleanInterface(&IpcpInfo.fsm); bundle_DownInterface(bundle); } dl = bundle->links; while (dl) dl = datalink_Destroy(dl); bundle->ifname = NULL; } struct rtmsg { struct rt_msghdr m_rtm; char m_space[64]; }; void bundle_SetRoute(struct bundle *bundle, int cmd, struct in_addr dst, struct in_addr gateway, struct in_addr mask, int bang) { struct rtmsg rtmes; int s, nb, wb; char *cp; const char *cmdstr; struct sockaddr_in rtdata; if (bang) cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); else cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); s = ID0socket(PF_ROUTE, SOCK_RAW, 0); if (s < 0) { LogPrintf(LogERROR, "bundle_SetRoute: socket(): %s\n", strerror(errno)); return; } memset(&rtmes, '\0', sizeof rtmes); rtmes.m_rtm.rtm_version = RTM_VERSION; rtmes.m_rtm.rtm_type = cmd; rtmes.m_rtm.rtm_addrs = RTA_DST; rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; rtmes.m_rtm.rtm_pid = getpid(); rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; memset(&rtdata, '\0', sizeof rtdata); rtdata.sin_len = 16; rtdata.sin_family = AF_INET; rtdata.sin_port = 0; rtdata.sin_addr = dst; cp = rtmes.m_space; memcpy(cp, &rtdata, 16); cp += 16; if (cmd == RTM_ADD) if (gateway.s_addr == INADDR_ANY) { /* Add a route through the interface */ struct sockaddr_dl dl; const char *iname; int ilen; iname = Index2Nam(bundle->ifIndex); ilen = strlen(iname); dl.sdl_len = sizeof dl - sizeof dl.sdl_data + ilen; dl.sdl_family = AF_LINK; dl.sdl_index = bundle->ifIndex; dl.sdl_type = 0; dl.sdl_nlen = ilen; dl.sdl_alen = 0; dl.sdl_slen = 0; strncpy(dl.sdl_data, iname, sizeof dl.sdl_data); memcpy(cp, &dl, dl.sdl_len); cp += dl.sdl_len; rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; } else { rtdata.sin_addr = gateway; memcpy(cp, &rtdata, 16); cp += 16; rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; } if (dst.s_addr == INADDR_ANY) mask.s_addr = INADDR_ANY; if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) { rtdata.sin_addr = mask; memcpy(cp, &rtdata, 16); cp += 16; rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; } nb = cp - (char *) &rtmes; rtmes.m_rtm.rtm_msglen = nb; wb = ID0write(s, &rtmes, nb); if (wb < 0) { LogPrintf(LogTCPIP, "bundle_SetRoute failure:\n"); LogPrintf(LogTCPIP, "bundle_SetRoute: Cmd = %s\n", cmd); LogPrintf(LogTCPIP, "bundle_SetRoute: Dst = %s\n", inet_ntoa(dst)); LogPrintf(LogTCPIP, "bundle_SetRoute: Gateway = %s\n", inet_ntoa(gateway)); LogPrintf(LogTCPIP, "bundle_SetRoute: Mask = %s\n", inet_ntoa(mask)); failed: if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) if (!bang) LogPrintf(LogWARN, "Add route failed: %s already exists\n", inet_ntoa(dst)); else { rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; if ((wb = ID0write(s, &rtmes, nb)) < 0) goto failed; } else if (cmd == RTM_DELETE && (rtmes.m_rtm.rtm_errno == ESRCH || (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { if (!bang) LogPrintf(LogWARN, "Del route failed: %s: Non-existent\n", inet_ntoa(dst)); } else if (rtmes.m_rtm.rtm_errno == 0) LogPrintf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, inet_ntoa(dst), strerror(errno)); else LogPrintf(LogWARN, "%s route failed: %s: %s\n", cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); } LogPrintf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", wb, cmdstr, dst.s_addr, gateway.s_addr); close(s); } void bundle_LinkLost(struct bundle *bundle, struct link *link, int staydown) { /* * Locate the appropriate datalink, and Down it. * * The LayerFinish() called from the datalinks LCP will * potentially Down our NCPs (if it's the last link). * * The LinkClosed() called when the datalink is finally in * the CLOSED state MAY cause the entire datalink to be deleted * and MAY cause a program exit. */ if ((mode & MODE_DIRECT) || CleaningUp) staydown = 1; datalink_Down(bundle->links, staydown); } void bundle_LinkClosed(struct bundle *bundle, struct datalink *dl) { /* * Our datalink has closed. * If it's DIRECT or BACKGROUND, delete it. * If it's the last data link, */ if (mode & (MODE_BACKGROUND|MODE_DIRECT)) CleaningUp = 1; if (!(mode & MODE_AUTO)) bundle_DownInterface(bundle); if (mode & MODE_DDIAL) datalink_Up(dl, 1, 1); else bundle_NewPhase(bundle, NULL, PHASE_DEAD); if (mode & MODE_INTER) prompt_Display(&prompt, bundle); } void bundle_Open(struct bundle *bundle, const char *name) { /* * Please open the given datalink, or all if name == NULL */ struct datalink *dl; int runscripts; runscripts = (mode & (MODE_DIRECT|MODE_DEDICATED)) ? 0 : 1; for (dl = bundle->links; dl; dl = dl->next) if (name == NULL || !strcasecmp(dl->name, name)) { datalink_Up(dl, runscripts, 1); if (name != NULL) break; } bundle_NewPhase(bundle, NULL, PHASE_ESTABLISH); } struct datalink * bundle2datalink(struct bundle *bundle, const char *name) { struct datalink *dl; if (name != NULL) { for (dl = bundle->links; dl; dl = dl->next) if (!strcasecmp(dl->name, name)) return dl; } else if (bundle->links && !bundle->links->next) return bundle->links; return NULL; } struct physical * bundle2physical(struct bundle *bundle, const char *name) { struct datalink *dl = bundle2datalink(bundle, name); return dl ? dl->physical : NULL; } struct ccp * bundle2ccp(struct bundle *bundle, const char *name) { struct datalink *dl = bundle2datalink(bundle, name); if (dl) return &dl->ccp; + return NULL; +} + +struct authinfo * +bundle2pap(struct bundle *bundle, const char *name) +{ + struct datalink *dl = bundle2datalink(bundle, name); + if (dl) + return &dl->pap; + return NULL; +} + +struct chap * +bundle2chap(struct bundle *bundle, const char *name) +{ + struct datalink *dl = bundle2datalink(bundle, name); + if (dl) + return &dl->chap; return NULL; } struct link * bundle2link(struct bundle *bundle, const char *name) { struct physical *physical = bundle2physical(bundle, name); return physical ? &physical->link : NULL; } int bundle_UpdateSet(struct bundle *bundle, fd_set *r, fd_set *w, fd_set *e, int *n) { struct datalink *dl; int result; result = 0; for (dl = bundle->links; dl; dl = dl->next) result += descriptor_UpdateSet(&dl->desc, r, w, e, n); return result; } int bundle_FillQueues(struct bundle *bundle) { struct datalink *dl; int packets, total; total = 0; for (dl = bundle->links; dl; dl = dl->next) { packets = link_QueueLen(&dl->physical->link); if (packets == 0) { IpStartOutput(&dl->physical->link, bundle); packets = link_QueueLen(&dl->physical->link); } total += packets; } total += ip_QueueLen(); return total; } int bundle_ShowLinks(struct cmdargs const *arg) { if (arg->cx) datalink_Show(arg->cx); else { struct datalink *dl; for (dl = arg->bundle->links; dl; dl = dl->next) datalink_Show(dl); } return 0; } Index: cvs2svn/branches/MP/usr.sbin/ppp/bundle.h =================================================================== --- cvs2svn/branches/MP/usr.sbin/ppp/bundle.h (revision 33933) +++ cvs2svn/branches/MP/usr.sbin/ppp/bundle.h (revision 33934) @@ -1,73 +1,75 @@ /*- * Copyright (c) 1998 Brian Somers * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: bundle.h,v 1.1.2.10 1998/02/21 01:44:59 brian Exp $ + * $Id: bundle.h,v 1.1.2.11 1998/02/27 01:22:17 brian Exp $ */ #define PHASE_DEAD 0 /* Link is dead */ #define PHASE_ESTABLISH 1 /* Establishing link */ #define PHASE_AUTHENTICATE 2 /* Being authenticated */ #define PHASE_NETWORK 3 /* We're alive ! */ #define PHASE_TERMINATE 4 /* Terminating link */ struct datalink; struct physical; struct link; struct bundle { int unit; /* The tun number */ int ifIndex; /* The interface number */ int tun_fd; /* The /dev/tunX descriptor */ char dev[20]; /* The /dev/tunX name */ char *ifname; /* The interface name */ int routing_seq; /* The current routing sequence number */ u_int phase; /* Curent phase */ struct fsm_parent fsm; /* Our callback functions */ struct datalink *links; /* Our data links */ }; extern struct bundle *bundle_Create(const char *); extern void bundle_Destroy(struct bundle *); extern const char *bundle_PhaseName(struct bundle *); #define bundle_Phase(b) ((b)->phase) extern void bundle_NewPhase(struct bundle *, struct physical *, u_int); extern int bundle_LinkIsUp(const struct bundle *); extern void bundle_SetRoute(struct bundle *, int, struct in_addr, struct in_addr, struct in_addr, int); extern void bundle_LinkLost(struct bundle *, struct link *, int); extern void bundle_Close(struct bundle *, const char *, int); extern void bundle_Open(struct bundle *, const char *name); extern void bundle_LinkClosed(struct bundle *, struct datalink *); extern int bundle_UpdateSet(struct bundle *, fd_set *, fd_set *, fd_set *, int *); extern int bundle_FillQueues(struct bundle *); extern int bundle_ShowLinks(struct cmdargs const *); extern struct link *bundle2link(struct bundle *, const char *); extern struct physical *bundle2physical(struct bundle *, const char *); extern struct datalink *bundle2datalink(struct bundle *, const char *); +extern struct authinfo *bundle2pap(struct bundle *, const char *); +extern struct chap *bundle2chap(struct bundle *, const char *); extern struct ccp *bundle2ccp(struct bundle *, const char *); Index: cvs2svn/branches/MP/usr.sbin/ppp/ccp.c =================================================================== --- cvs2svn/branches/MP/usr.sbin/ppp/ccp.c (revision 33933) +++ cvs2svn/branches/MP/usr.sbin/ppp/ccp.c (revision 33934) @@ -1,452 +1,454 @@ /* * PPP Compression Control Protocol (CCP) Module * * Written by Toshiharu OHNO (tony-o@iij.ad.jp) * * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the Internet Initiative Japan, Inc. The name of the * IIJ may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: ccp.c,v 1.30.2.15 1998/02/27 01:22:18 brian Exp $ + * $Id: ccp.c,v 1.30.2.16 1998/02/27 21:46:20 brian Exp $ * * TODO: * o Support other compression protocols */ #include #include #include #include #include #include "command.h" #include "mbuf.h" #include "log.h" #include "defs.h" #include "timer.h" #include "fsm.h" #include "lcpproto.h" #include "lcp.h" #include "ccp.h" #include "loadalias.h" #include "vars.h" #include "pred.h" #include "deflate.h" #include "bundle.h" #include "descriptor.h" #include "prompt.h" #include "hdlc.h" #include "throughput.h" #include "link.h" #include "chat.h" +#include "auth.h" +#include "chap.h" #include "datalink.h" static void CcpSendConfigReq(struct fsm *); static void CcpSendTerminateReq(struct fsm *); static void CcpSendTerminateAck(struct fsm *); static void CcpDecodeConfig(struct fsm *, u_char *, int, int); static void CcpLayerStart(struct fsm *); static void CcpLayerFinish(struct fsm *); static void CcpLayerUp(struct fsm *); static void CcpLayerDown(struct fsm *); static void CcpInitRestartCounter(struct fsm *); static void CcpRecvResetReq(struct fsm *); static void CcpRecvResetAck(struct fsm *, u_char); static struct fsm_callbacks ccp_Callbacks = { CcpLayerUp, CcpLayerDown, CcpLayerStart, CcpLayerFinish, CcpInitRestartCounter, CcpSendConfigReq, CcpSendTerminateReq, CcpSendTerminateAck, CcpDecodeConfig, CcpRecvResetReq, CcpRecvResetAck }; static char const *cftypes[] = { /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */ "OUI", /* 0: OUI */ "PRED1", /* 1: Predictor type 1 */ "PRED2", /* 2: Predictor type 2 */ "PUDDLE", /* 3: Puddle Jumber */ "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "HWPPC", /* 16: Hewlett-Packard PPC */ "STAC", /* 17: Stac Electronics LZS (rfc1974) */ "MSPPC", /* 18: Microsoft PPC */ "GAND", /* 19: Gandalf FZA (rfc1993) */ "V42BIS", /* 20: ARG->DATA.42bis compression */ "BSD", /* 21: BSD LZW Compress */ "???", "LZS-DCP", /* 23: LZS-DCP Compression Protocol (rfc1967) */ "MAGNALINK/DEFLATE", /* 24: Magnalink Variable Resource (rfc1975) */ /* 24: Deflate (according to pppd-2.3.1) */ "DCE", /* 25: Data Circuit-Terminating Equip (rfc1976) */ "DEFLATE", /* 26: Deflate (rfc1979) */ }; #define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) static const char * protoname(int proto) { if (proto < 0 || proto > NCFTYPES) return "none"; return cftypes[proto]; } /* We support these algorithms, and Req them in the given order */ static const struct ccp_algorithm *algorithm[] = { &DeflateAlgorithm, &Pred1Algorithm, &PppdDeflateAlgorithm }; #define NALGORITHMS (sizeof algorithm/sizeof algorithm[0]) int ccp_ReportStatus(struct cmdargs const *arg) { struct ccp *ccp = bundle2ccp(arg->bundle, arg->cx ? arg->cx->name : NULL); prompt_Printf(&prompt, "%s [%s]\n", ccp->fsm.name, StateNames[ccp->fsm.state]); prompt_Printf(&prompt, "My protocol = %s, His protocol = %s\n", protoname(ccp->my_proto), protoname(ccp->his_proto)); prompt_Printf(&prompt, "Output: %ld --> %ld, Input: %ld --> %ld\n", ccp->uncompout, ccp->compout, ccp->compin, ccp->uncompin); return 0; } void ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l, const struct fsm_parent *parent) { /* Initialise ourselves */ fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, CCP_MAXCODE, 10, LogCCP, bundle, l, parent, &ccp_Callbacks); ccp_Setup(ccp); } void ccp_Setup(struct ccp *ccp) { /* Set ourselves up for a startup */ ccp->fsm.open_mode = 0; ccp->fsm.maxconfig = 10; ccp->his_proto = ccp->my_proto = -1; ccp->reset_sent = ccp->last_reset = -1; ccp->in_algorithm = ccp->out_algorithm = -1; ccp->his_reject = ccp->my_reject = 0; ccp->out_init = ccp->in_init = 0; ccp->uncompout = ccp->compout = 0; ccp->uncompin = ccp->compin = 0; } static void CcpInitRestartCounter(struct fsm *fp) { /* Set fsm timer load */ fp->FsmTimer.load = VarRetryTimeout * SECTICKS; fp->restart = 5; } static void CcpSendConfigReq(struct fsm *fp) { /* Send config REQ please */ struct ccp *ccp = fsm2ccp(fp); u_char *cp; int f; LogPrintf(LogCCP, "CcpSendConfigReq\n"); cp = ReqBuff; ccp->my_proto = -1; ccp->out_algorithm = -1; for (f = 0; f < NALGORITHMS; f++) if (Enabled(algorithm[f]->Conf) && !REJECTED(ccp, algorithm[f]->id)) { struct lcp_opt o; (*algorithm[f]->o.Get)(&o); cp += LcpPutConf(LogCCP, cp, &o, cftypes[o.id], (*algorithm[f]->Disp)(&o)); ccp->my_proto = o.id; ccp->out_algorithm = f; } FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff); } void CcpSendResetReq(struct fsm *fp) { /* We can't read our input - ask peer to reset */ struct ccp *ccp = fsm2ccp(fp); LogPrintf(LogCCP, "SendResetReq(%d)\n", fp->reqid); ccp->reset_sent = fp->reqid; ccp->last_reset = -1; FsmOutput(fp, CODE_RESETREQ, fp->reqid, NULL, 0); } static void CcpSendTerminateReq(struct fsm *fp) { /* Term REQ just sent by FSM */ } static void CcpSendTerminateAck(struct fsm *fp) { /* Send Term ACK please */ LogPrintf(LogCCP, "CcpSendTerminateAck\n"); FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0); } static void CcpRecvResetReq(struct fsm *fp) { /* Got a reset REQ, reset outgoing dictionary */ struct ccp *ccp = fsm2ccp(fp); if (ccp->out_init) (*algorithm[ccp->out_algorithm]->o.Reset)(); } static void CcpLayerStart(struct fsm *fp) { /* We're about to start up ! */ LogPrintf(LogCCP, "CcpLayerStart.\n"); } static void CcpLayerFinish(struct fsm *fp) { /* We're now down */ struct ccp *ccp = fsm2ccp(fp); LogPrintf(LogCCP, "CcpLayerFinish.\n"); if (ccp->in_init) { (*algorithm[ccp->in_algorithm]->i.Term)(); ccp->in_init = 0; } if (ccp->out_init) { (*algorithm[ccp->out_algorithm]->o.Term)(); ccp->out_init = 0; } } static void CcpLayerDown(struct fsm *fp) { /* About to come down */ LogPrintf(LogCCP, "CcpLayerDown.\n"); } /* * Called when CCP has reached the OPEN state */ static void CcpLayerUp(struct fsm *fp) { /* We're now up */ struct ccp *ccp = fsm2ccp(fp); LogPrintf(LogCCP, "CcpLayerUp.\n"); if (!ccp->in_init && ccp->in_algorithm >= 0 && ccp->in_algorithm < NALGORITHMS) if ((*algorithm[ccp->in_algorithm]->i.Init)()) ccp->in_init = 1; else { LogPrintf(LogERROR, "%s (in) initialisation failure\n", protoname(ccp->his_proto)); ccp->his_proto = ccp->my_proto = -1; FsmClose(fp); } if (!ccp->out_init && ccp->out_algorithm >= 0 && ccp->out_algorithm < NALGORITHMS) if ((*algorithm[ccp->out_algorithm]->o.Init)()) ccp->out_init = 1; else { LogPrintf(LogERROR, "%s (out) initialisation failure\n", protoname(ccp->my_proto)); ccp->his_proto = ccp->my_proto = -1; FsmClose(fp); } LogPrintf(LogCCP, "Out = %s[%d], In = %s[%d]\n", protoname(ccp->my_proto), ccp->my_proto, protoname(ccp->his_proto), ccp->his_proto); } static void CcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type) { /* Deal with incoming data */ struct ccp *ccp = fsm2ccp(fp); int type, length; int f; ackp = AckBuff; nakp = NakBuff; rejp = RejBuff; while (plen >= sizeof(struct fsmconfig)) { type = *cp; length = cp[1]; if (type < NCFTYPES) LogPrintf(LogCCP, " %s[%d]\n", cftypes[type], length); else LogPrintf(LogCCP, " ???[%d]\n", length); for (f = NALGORITHMS-1; f > -1; f--) if (algorithm[f]->id == type) break; if (f == -1) { /* Don't understand that :-( */ if (mode_type == MODE_REQ) { ccp->my_reject |= (1 << type); memcpy(rejp, cp, length); rejp += length; } } else { struct lcp_opt o; switch (mode_type) { case MODE_REQ: if (Acceptable(algorithm[f]->Conf) && ccp->in_algorithm == -1) { memcpy(&o, cp, length); switch ((*algorithm[f]->i.Set)(&o)) { case MODE_REJ: memcpy(rejp, &o, o.len); rejp += o.len; break; case MODE_NAK: memcpy(nakp, &o, o.len); nakp += o.len; break; case MODE_ACK: memcpy(ackp, cp, length); ackp += length; ccp->his_proto = type; ccp->in_algorithm = f; /* This one'll do ! */ break; } } else { memcpy(rejp, cp, length); rejp += length; } break; case MODE_NAK: memcpy(&o, cp, length); if ((*algorithm[f]->o.Set)(&o) == MODE_ACK) ccp->my_proto = algorithm[f]->id; else { ccp->his_reject |= (1 << type); ccp->my_proto = -1; } break; case MODE_REJ: ccp->his_reject |= (1 << type); ccp->my_proto = -1; break; } } plen -= length; cp += length; } if (rejp != RejBuff) { ackp = AckBuff; /* let's not send both ! */ if (!ccp->in_init) { ccp->his_proto = -1; ccp->in_algorithm = -1; } } } void CcpInput(struct ccp *ccp, struct bundle *bundle, struct mbuf *bp) { /* Got PROTO_CCP from link */ if (bundle_Phase(bundle) == PHASE_NETWORK) FsmInput(&ccp->fsm, bp); else if (bundle_Phase(bundle) < PHASE_NETWORK) { LogPrintf(LogCCP, "Error: Unexpected CCP in phase %s (ignored)\n", bundle_PhaseName(bundle)); pfree(bp); } } static void CcpRecvResetAck(struct fsm *fp, u_char id) { /* Got a reset ACK, reset incoming dictionary */ struct ccp *ccp = fsm2ccp(fp); if (ccp->reset_sent != -1) { if (id != ccp->reset_sent) { LogPrintf(LogWARN, "CCP: Incorrect ResetAck (id %d, not %d) ignored\n", id, ccp->reset_sent); return; } /* Whaddaya know - a correct reset ack */ } else if (id == ccp->last_reset) LogPrintf(LogCCP, "Duplicate ResetAck (resetting again)\n"); else { LogPrintf(LogWARN, "CCP: Unexpected ResetAck (id %d) ignored\n", id); return; } ccp->last_reset = ccp->reset_sent; ccp->reset_sent = -1; if (ccp->in_init) (*algorithm[ccp->in_algorithm]->i.Reset)(); } int ccp_Output(struct ccp *ccp, struct link *l, int pri, u_short proto, struct mbuf *m) { /* Compress outgoing Network Layer data */ if ((proto & 0xfff1) == 0x21 && ccp->fsm.state == ST_OPENED && ccp->out_init) return (*algorithm[ccp->out_algorithm]->o.Write)(ccp, l, pri, proto, m); return 0; } struct mbuf * ccp_Decompress(struct ccp *ccp, u_short *proto, struct mbuf *bp) { /* * If proto isn't PROTO_COMPD, we still want to pass it to the * decompression routines so that the dictionary's updated */ if (ccp->fsm.state == ST_OPENED) if (*proto == PROTO_COMPD) { /* Decompress incoming data */ if (ccp->reset_sent != -1) { /* Send another REQ and put the packet in the bit bucket */ LogPrintf(LogCCP, "ReSendResetReq(%d)\n", ccp->reset_sent); FsmOutput(&ccp->fsm, CODE_RESETREQ, ccp->reset_sent, NULL, 0); } else if (ccp->in_init) return (*algorithm[ccp->in_algorithm]->i.Read)(ccp, proto, bp); pfree(bp); bp = NULL; } else if ((*proto & 0xfff1) == 0x21 && ccp->in_init) /* Add incoming Network Layer traffic to our dictionary */ (*algorithm[ccp->in_algorithm]->i.DictSetup)(ccp, *proto, bp); return bp; } Index: cvs2svn/branches/MP/usr.sbin/ppp/chap.c =================================================================== --- cvs2svn/branches/MP/usr.sbin/ppp/chap.c (revision 33933) +++ cvs2svn/branches/MP/usr.sbin/ppp/chap.c (revision 33934) @@ -1,330 +1,331 @@ /* * PPP CHAP Module * * Written by Toshiharu OHNO (tony-o@iij.ad.jp) * * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the Internet Initiative Japan, Inc. The name of the * IIJ may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: chap.c,v 1.28.2.9 1998/02/15 23:59:43 brian Exp $ + * $Id: chap.c,v 1.28.2.10 1998/02/19 02:08:42 brian Exp $ * * TODO: */ #include #include #include #ifdef HAVE_DES #include #endif #include #include #include #include #include #include #include #ifdef __OpenBSD__ #include #else #include #endif #include #include "command.h" #include "mbuf.h" #include "log.h" #include "defs.h" #include "timer.h" #include "fsm.h" -#include "chap.h" #include "chap_ms.h" #include "lcpproto.h" #include "lcp.h" #include "hdlc.h" #include "loadalias.h" #include "vars.h" #include "auth.h" +#include "chap.h" #include "async.h" #include "throughput.h" #include "link.h" #include "descriptor.h" #include "physical.h" #include "bundle.h" #include "id.h" +#include "ccp.h" +#include "chat.h" +#include "datalink.h" static const char *chapcodes[] = { "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE" }; static void ChapOutput(struct physical *physical, u_int code, u_int id, const u_char * ptr, int count) { int plen; struct fsmheader lh; struct mbuf *bp; plen = sizeof(struct fsmheader) + count; lh.code = code; lh.id = id; lh.length = htons(plen); bp = mballoc(plen, MB_FSM); memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); if (count) memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); LogDumpBp(LogDEBUG, "ChapOutput", bp); LogPrintf(LogLCP, "ChapOutput: %s\n", chapcodes[code]); HdlcOutput(physical2link(physical), PRI_LINK, PROTO_CHAP, bp); } - -static char challenge_data[80]; -static int challenge_len; - -static void -SendChapChallenge(int chapid, struct physical *physical) +void +SendChapChallenge(struct authinfo *auth, int chapid, struct physical *physical) { + struct chap *chap = auth2chap(auth); int len, i; char *cp; randinit(); - cp = challenge_data; - *cp++ = challenge_len = random() % 32 + 16; - for (i = 0; i < challenge_len; i++) + cp = chap->challenge_data; + *cp++ = chap->challenge_len = random() % 32 + 16; + for (i = 0; i < chap->challenge_len; i++) *cp++ = random() & 0xff; len = strlen(VarAuthName); memcpy(cp, VarAuthName, len); cp += len; - ChapOutput(physical, CHAP_CHALLENGE, chapid, challenge_data, - cp - challenge_data); + ChapOutput(physical, CHAP_CHALLENGE, chapid, chap->challenge_data, + cp - chap->challenge_data); } -struct authinfo AuthChapInfo = { - SendChapChallenge, -}; - static void RecvChapTalk(struct bundle *bundle, struct fsmheader *chp, struct mbuf *bp, struct physical *physical) { + struct datalink *dl = bundle2datalink(bundle, physical->link.name); int valsize, len; int arglen, keylen, namelen; char *cp, *argp, *ap, *name, *digest; char *keyp; MD5_CTX MD5context; /* context for MD5 */ char answer[100]; char cdigest[16]; #ifdef HAVE_DES int ix; MD4_CTX MD4context; /* context for MD4 */ #endif len = ntohs(chp->length); LogPrintf(LogDEBUG, "RecvChapTalk: length: %d\n", len); arglen = len - sizeof(struct fsmheader); cp = (char *) MBUF_CTOP(bp); valsize = *cp++ & 255; name = cp + valsize; namelen = arglen - valsize - 1; name[namelen] = 0; LogPrintf(LogLCP, " Valsize = %d, Name = \"%s\"\n", valsize, name); switch (chp->code) { case CHAP_CHALLENGE: keyp = VarAuthKey; keylen = strlen(VarAuthKey); name = VarAuthName; namelen = strlen(VarAuthName); #ifdef HAVE_DES if (VarMSChap) argp = malloc(1 + namelen + MS_CHAP_RESPONSE_LEN); else #endif argp = malloc(1 + valsize + namelen + 16); if (argp == NULL) { ChapOutput(physical, CHAP_FAILURE, chp->id, "Out of memory!", 14); return; } #ifdef HAVE_DES if (VarMSChap) { digest = argp; /* this is the response */ *digest++ = MS_CHAP_RESPONSE_LEN; /* 49 */ memset(digest, '\0', 24); digest += 24; ap = answer; /* this is the challenge */ memcpy(ap, keyp, keylen); ap += 2 * keylen; memcpy(ap, cp, valsize); LogDumpBuff(LogDEBUG, "recv", ap, valsize); ap += valsize; for (ix = keylen; ix > 0 ; ix--) { answer[2*ix-2] = answer[ix-1]; answer[2*ix-1] = 0; } MD4Init(&MD4context); MD4Update(&MD4context, answer, 2 * keylen); MD4Final(digest, &MD4context); memcpy(digest + 25, name, namelen); ap += 2 * keylen; ChapMS(digest, answer + 2 * keylen, valsize); LogDumpBuff(LogDEBUG, "answer", digest, 24); ChapOutput(physical, CHAP_RESPONSE, chp->id, argp, namelen + MS_CHAP_RESPONSE_LEN + 1); } else { #endif digest = argp; *digest++ = 16; /* value size */ ap = answer; *ap++ = chp->id; memcpy(ap, keyp, keylen); ap += keylen; memcpy(ap, cp, valsize); LogDumpBuff(LogDEBUG, "recv", ap, valsize); ap += valsize; MD5Init(&MD5context); MD5Update(&MD5context, answer, ap - answer); MD5Final(digest, &MD5context); LogDumpBuff(LogDEBUG, "answer", digest, 16); memcpy(digest + 16, name, namelen); ap += namelen; /* Send answer to the peer */ ChapOutput(physical, CHAP_RESPONSE, chp->id, argp, namelen + 17); #ifdef HAVE_DES } #endif free(argp); break; case CHAP_RESPONSE: /* * Get a secret key corresponds to the peer */ keyp = AuthGetSecret(bundle, SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE, physical); if (keyp) { /* * Compute correct digest value */ keylen = strlen(keyp); ap = answer; *ap++ = chp->id; memcpy(ap, keyp, keylen); ap += keylen; MD5Init(&MD5context); MD5Update(&MD5context, answer, ap - answer); - MD5Update(&MD5context, challenge_data + 1, challenge_len); + MD5Update(&MD5context, dl->chap.challenge_data + 1, + dl->chap.challenge_len); MD5Final(cdigest, &MD5context); LogDumpBuff(LogDEBUG, "got", cp, 16); LogDumpBuff(LogDEBUG, "expect", cdigest, 16); /* * Compare with the response */ if (memcmp(cp, cdigest, 16) == 0) { ChapOutput(physical, CHAP_SUCCESS, chp->id, "Welcome!!", 10); if ((mode & MODE_DIRECT) && Physical_IsATTY(physical) && Enabled(ConfUtmp)) if (Utmp) LogPrintf(LogERROR, "Oops, already logged in on %s\n", VarBaseDevice); else { struct utmp ut; memset(&ut, 0, sizeof ut); time(&ut.ut_time); strncpy(ut.ut_name, name, sizeof ut.ut_name); strncpy(ut.ut_line, VarBaseDevice, sizeof ut.ut_line - 1); ID0login(&ut); Utmp = 1; } if (LcpInfo.auth_iwait == 0) /* * Either I didn't need to authenticate, or I've already been * told that I got the answer right. */ - bundle_NewPhase(bundle, physical, PHASE_NETWORK); + datalink_AuthOk(dl); break; } } /* * Peer is not registerd, or response digest is wrong. */ ChapOutput(physical, CHAP_FAILURE, chp->id, "Invalid!!", 9); - link_Close(&physical->link, bundle, 1, 1); + datalink_AuthNotOk(dl); break; } } static void RecvChapResult(struct bundle *bundle, struct fsmheader *chp, struct mbuf *bp, struct physical *physical) { + struct datalink *dl = bundle2datalink(bundle, physical->link.name); int len; len = ntohs(chp->length); LogPrintf(LogDEBUG, "RecvChapResult: length: %d\n", len); if (chp->code == CHAP_SUCCESS) { if (LcpInfo.auth_iwait == PROTO_CHAP) { LcpInfo.auth_iwait = 0; if (LcpInfo.auth_ineed == 0) /* * We've succeeded in our ``login'' * If we're not expecting the peer to authenticate (or he already * has), proceed to network phase. */ - bundle_NewPhase(bundle, physical, PHASE_NETWORK); + datalink_AuthOk(dl); } - } else + } else { /* CHAP failed - it's not going to get any better */ - link_Close(&physical->link, bundle, 1, 1); + LogPrintf(LogPHASE, "Received CHAP_FAILURE\n"); + datalink_AuthNotOk(dl); + } } void ChapInput(struct bundle *bundle, struct mbuf *bp, struct physical *physical) { int len = plength(bp); struct fsmheader *chp; if (len >= sizeof(struct fsmheader)) { chp = (struct fsmheader *) MBUF_CTOP(bp); if (len >= ntohs(chp->length)) { if (chp->code < 1 || chp->code > 4) chp->code = 0; LogPrintf(LogLCP, "ChapInput: %s\n", chapcodes[chp->code]); bp->offset += sizeof(struct fsmheader); bp->cnt -= sizeof(struct fsmheader); switch (chp->code) { case CHAP_RESPONSE: - StopAuthTimer(&AuthChapInfo); + StopAuthTimer(&bundle2datalink(bundle, physical->link.name)->chap.auth); /* Fall into.. */ case CHAP_CHALLENGE: RecvChapTalk(bundle, chp, bp, physical); break; case CHAP_SUCCESS: case CHAP_FAILURE: RecvChapResult(bundle, chp, bp, physical); break; } } } pfree(bp); } Index: cvs2svn/branches/MP/usr.sbin/ppp/chap.h =================================================================== --- cvs2svn/branches/MP/usr.sbin/ppp/chap.h (revision 33933) +++ cvs2svn/branches/MP/usr.sbin/ppp/chap.h (revision 33934) @@ -1,32 +1,39 @@ /* * Written by Toshiharu OHNO (tony-o@iij.ad.jp) * * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the Internet Initiative Japan. The name of the * IIJ may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: chap.h,v 1.9.2.1 1998/01/29 00:49:14 brian Exp $ + * $Id: chap.h,v 1.9.2.2 1998/02/02 19:32:03 brian Exp $ * * TODO: */ struct physical; #define CHAP_CHALLENGE 1 #define CHAP_RESPONSE 2 #define CHAP_SUCCESS 3 #define CHAP_FAILURE 4 -extern struct authinfo AuthChapInfo; +struct chap { + struct authinfo auth; + char challenge_data[80]; + int challenge_len; +}; +#define auth2chap(a) ((struct chap *)(a)) + extern void ChapInput(struct bundle *, struct mbuf *, struct physical *); +extern void SendChapChallenge(struct authinfo *, int, struct physical *); Index: cvs2svn/branches/MP/usr.sbin/ppp/command.c =================================================================== --- cvs2svn/branches/MP/usr.sbin/ppp/command.c (revision 33933) +++ cvs2svn/branches/MP/usr.sbin/ppp/command.c (revision 33934) @@ -1,1681 +1,1682 @@ /* * PPP User command processing module * * Written by Toshiharu OHNO (tony-o@iij.ad.jp) * * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the Internet Initiative Japan, Inc. The name of the * IIJ may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: command.c,v 1.131.2.28 1998/02/21 01:45:04 brian Exp $ + * $Id: command.c,v 1.131.2.29 1998/02/23 00:38:25 brian Exp $ * */ #include #include #include #include #include #include #include #include #ifndef NOALIAS #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "command.h" #include "mbuf.h" #include "log.h" #include "defs.h" #include "timer.h" #include "fsm.h" #include "lcp.h" #include "iplist.h" #include "throughput.h" #include "ipcp.h" #include "modem.h" #include "filter.h" #ifndef NOALIAS #include "alias_cmd.h" #endif #include "hdlc.h" #include "loadalias.h" #include "vars.h" #include "systems.h" #include "bundle.h" #include "main.h" #include "route.h" #include "ccp.h" #include "ip.h" #include "slcompress.h" #include "auth.h" #include "async.h" #include "link.h" #include "descriptor.h" #include "physical.h" #include "server.h" #include "prompt.h" #include "chat.h" +#include "chap.h" #include "datalink.h" struct in_addr ifnetmask; static const char *HIDDEN = "********"; static int ShowCommand(struct cmdargs const *); static int TerminalCommand(struct cmdargs const *); static int QuitCommand(struct cmdargs const *); static int CloseCommand(struct cmdargs const *); static int DialCommand(struct cmdargs const *); static int DownCommand(struct cmdargs const *); static int AllowCommand(struct cmdargs const *); static int SetCommand(struct cmdargs const *); static int LinkCommand(struct cmdargs const *); static int AddCommand(struct cmdargs const *); static int DeleteCommand(struct cmdargs const *); static int BgShellCommand(struct cmdargs const *); static int FgShellCommand(struct cmdargs const *); #ifndef NOALIAS static int AliasCommand(struct cmdargs const *); static int AliasEnable(struct cmdargs const *); static int AliasOption(struct cmdargs const *); #endif static int HelpCommand(struct cmdargs const *arg) { struct cmdtab const *cmd; int n, cmax, dmax, cols; if (arg->argc > 0) { for (cmd = arg->cmdtab; cmd->name; cmd++) if (strcasecmp(cmd->name, *arg->argv) == 0 && (cmd->lauth & VarLocalAuth)) { prompt_Printf(&prompt, "%s\n", cmd->syntax); return 0; } return -1; } cmax = dmax = 0; for (cmd = arg->cmdtab; cmd->func; cmd++) if (cmd->name && (cmd->lauth & VarLocalAuth)) { if ((n = strlen(cmd->name)) > cmax) cmax = n; if ((n = strlen(cmd->helpmes)) > dmax) dmax = n; } cols = 80 / (dmax + cmax + 3); n = 0; for (cmd = arg->cmdtab; cmd->func; cmd++) if (cmd->name && (cmd->lauth & VarLocalAuth)) { prompt_Printf(&prompt, " %-*.*s: %-*.*s", cmax, cmax, cmd->name, dmax, dmax, cmd->helpmes); if (++n % cols == 0) prompt_Printf(&prompt, "\n"); } if (n % cols != 0) prompt_Printf(&prompt, "\n"); return 0; } int IsInteractive(int Display) { const char *m = NULL; if (mode & MODE_DDIAL) m = "direct dial"; else if (mode & MODE_BACKGROUND) m = "background"; else if (mode & MODE_AUTO) m = "auto"; else if (mode & MODE_DIRECT) m = "direct"; else if (mode & MODE_DEDICATED) m = "dedicated"; else if (mode & MODE_INTER) m = "interactive"; if (m) { if (Display) prompt_Printf(&prompt, "Working in %s mode\n", m); } return mode & MODE_INTER; } static int DialCommand(struct cmdargs const *arg) { int res; if (LcpInfo.fsm.state > ST_CLOSED) { prompt_Printf(&prompt, "LCP state is [%s]\n", StateNames[LcpInfo.fsm.state]); return 0; } if ((mode & MODE_DAEMON) && !(mode & MODE_AUTO)) { LogPrintf(LogWARN, "Manual dial is only available in auto and interactive mode\n"); return 1; } if (arg->argc > 0 && (res = LoadCommand(arg)) != 0) return res; bundle_Open(arg->bundle, NULL); return 0; } static int SetLoopback(struct cmdargs const *arg) { if (arg->argc == 1) if (!strcasecmp(*arg->argv, "on")) { VarLoopback = 1; return 0; } else if (!strcasecmp(*arg->argv, "off")) { VarLoopback = 0; return 0; } return -1; } static int ShellCommand(struct cmdargs const *arg, int bg) { const char *shell; pid_t shpid; int argc; char *argv[MAXARGS]; #ifdef SHELL_ONLY_INTERACTIVELY /* we're only allowed to shell when we run ppp interactively */ if (mode != MODE_INTER) { LogPrintf(LogWARN, "Can only start a shell in interactive mode\n"); return 1; } #endif #ifdef NO_SHELL_IN_AUTO_INTERACTIVE /* * we want to stop shell commands when we've got a telnet connection to an * auto mode ppp */ if (prompt_Active(&prompt) && !(mode & MODE_INTER)) { LogPrintf(LogWARN, "Shell is not allowed interactively in auto mode\n"); return 1; } #endif if (arg->argc == 0) if (!(mode & MODE_INTER)) { if (prompt_Active(&prompt)) LogPrintf(LogWARN, "Can't start an interactive shell from" " a telnet session\n"); else LogPrintf(LogWARN, "Can only start an interactive shell in" " interactive mode\n"); return 1; } else if (bg) { LogPrintf(LogWARN, "Can only start an interactive shell in" " the foreground mode\n"); return 1; } if ((shell = getenv("SHELL")) == 0) shell = _PATH_BSHELL; if ((shpid = fork()) == 0) { int dtablesize, i, fd; TermTimerService(); signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGTERM, SIG_DFL); signal(SIGHUP, SIG_DFL); signal(SIGALRM, SIG_DFL); if (prompt_Active(&prompt)) fd = prompt.fd_out; else if ((fd = open("/dev/null", O_RDWR)) == -1) { LogPrintf(LogALERT, "Failed to open /dev/null: %s\n", strerror(errno)); exit(1); } for (i = 0; i < 3; i++) dup2(fd, i); for (dtablesize = getdtablesize(), i = 3; i < dtablesize; i++) close(i); prompt_TtyOldMode(&prompt); setuid(geteuid()); if (arg->argc > 0) { /* substitute pseudo args */ argv[0] = strdup(arg->argv[0]); for (argc = 1; argc < arg->argc; argc++) { if (strcasecmp(arg->argv[argc], "HISADDR") == 0) argv[argc] = strdup(inet_ntoa(IpcpInfo.peer_ip)); else if (strcasecmp(arg->argv[argc], "INTERFACE") == 0) argv[argc] = strdup(arg->bundle->ifname); else if (strcasecmp(arg->argv[argc], "MYADDR") == 0) argv[argc] = strdup(inet_ntoa(IpcpInfo.my_ip)); else argv[argc] = strdup(arg->argv[argc]); } argv[argc] = NULL; if (bg) { pid_t p; p = getpid(); if (daemon(1, 1) == -1) { LogPrintf(LogERROR, "%d: daemon: %s\n", p, strerror(errno)); exit(1); } } else if (prompt_Active(&prompt)) printf("ppp: Pausing until %s finishes\n", arg->argv[0]); execvp(argv[0], argv); } else { if (prompt_Active(&prompt)) printf("ppp: Pausing until %s finishes\n", shell); execl(shell, shell, NULL); } LogPrintf(LogWARN, "exec() of %s failed\n", arg->argc > 0 ? arg->argv[0] : shell); exit(255); } if (shpid == (pid_t) - 1) { LogPrintf(LogERROR, "Fork failed: %s\n", strerror(errno)); } else { int status; waitpid(shpid, &status, 0); } prompt_TtyCommandMode(&prompt); return (0); } static int BgShellCommand(struct cmdargs const *arg) { if (arg->argc == 0) return -1; return ShellCommand(arg, 1); } static int FgShellCommand(struct cmdargs const *arg) { return ShellCommand(arg, 0); } static struct cmdtab const Commands[] = { {"accept", NULL, AcceptCommand, LOCAL_AUTH, "accept option request", "accept option .."}, {"add", NULL, AddCommand, LOCAL_AUTH, "add route", "add dest mask gateway", NULL}, {"add!", NULL, AddCommand, LOCAL_AUTH, "add or change route", "add! dest mask gateway", (void *)1}, {"allow", "auth", AllowCommand, LOCAL_AUTH, "Allow ppp access", "allow users|modes ...."}, {"bg", "!bg", BgShellCommand, LOCAL_AUTH, "Run a background command", "[!]bg command"}, {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT, "Close connection", "close"}, {"delete", NULL, DeleteCommand, LOCAL_AUTH, "delete route", "delete dest", NULL}, {"delete!", NULL, DeleteCommand, LOCAL_AUTH, "delete a route if it exists", "delete! dest", (void *)1}, {"deny", NULL, DenyCommand, LOCAL_AUTH, "Deny option request", "deny option .."}, {"dial", "call", DialCommand, LOCAL_AUTH, "Dial and login", "dial|call [remote]"}, {"disable", NULL, DisableCommand, LOCAL_AUTH, "Disable option", "disable option .."}, {"display", NULL, DisplayCommand, LOCAL_AUTH, "Display option configs", "display"}, {"enable", NULL, EnableCommand, LOCAL_AUTH, "Enable option", "enable option .."}, {"passwd", NULL, LocalAuthCommand, LOCAL_NO_AUTH, "Password for manipulation", "passwd LocalPassword"}, {"link", NULL, LinkCommand, LOCAL_AUTH, "Link specific commands", "link name command ..."}, {"load", NULL, LoadCommand, LOCAL_AUTH, "Load settings", "load [remote]"}, {"save", NULL, SaveCommand, LOCAL_AUTH, "Save settings", "save"}, {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT, "Set parameters", "set[up] var value"}, {"shell", "!", FgShellCommand, LOCAL_AUTH, "Run a subshell", "shell|! [sh command]"}, {"show", NULL, ShowCommand, LOCAL_AUTH, "Show status and stats", "show var"}, {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX, "Enter terminal mode", "term"}, #ifndef NOALIAS {"alias", NULL, AliasCommand, LOCAL_AUTH, "alias control", "alias option [yes|no]"}, #endif {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH, "Quit PPP program", "quit|bye [all]"}, {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, "Display this message", "help|? [command]", Commands}, {NULL, "down", DownCommand, LOCAL_AUTH | LOCAL_CX, "Generate down event", "down"}, {NULL, NULL, NULL}, }; static int ShowLoopback(struct cmdargs const *arg) { prompt_Printf(&prompt, "Local loopback is %s\n", VarLoopback ? "on" : "off"); return 0; } static int ShowLogLevel(struct cmdargs const *arg) { int i; prompt_Printf(&prompt, "Log: "); for (i = LogMIN; i <= LogMAX; i++) if (LogIsKept(i) & LOG_KEPT_SYSLOG) prompt_Printf(&prompt, " %s", LogName(i)); prompt_Printf(&prompt, "\nLocal:"); for (i = LogMIN; i <= LogMAX; i++) if (LogIsKept(i) & LOG_KEPT_LOCAL) prompt_Printf(&prompt, " %s", LogName(i)); prompt_Printf(&prompt, "\n"); return 0; } static int ShowEscape(struct cmdargs const *arg) { if (arg->cx->physical->async.cfg.EscMap[32]) { int code, bit; char *sep = ""; for (code = 0; code < 32; code++) if (arg->cx->physical->async.cfg.EscMap[code]) for (bit = 0; bit < 8; bit++) if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) { prompt_Printf(&prompt, "%s0x%02x", sep, (code << 3) + bit); sep = ", "; } prompt_Printf(&prompt, "\n"); } return 0; } static int ShowTimeout(struct cmdargs const *arg) { int remaining; prompt_Printf(&prompt, " Idle Timer: %d secs LQR Timer: %d secs" " Retry Timer: %d secs\n", VarIdleTimeout, VarLqrTimeout, VarRetryTimeout); remaining = RemainingIdleTime(); if (remaining != -1) prompt_Printf(&prompt, " %d secs remaining\n", remaining); return 0; } static int ShowStopped(struct cmdargs const *arg) { prompt_Printf(&prompt, " Stopped Timer: LCP: "); if (!LcpInfo.fsm.StoppedTimer.load) prompt_Printf(&prompt, "Disabled"); else prompt_Printf(&prompt, "%ld secs", LcpInfo.fsm.StoppedTimer.load / SECTICKS); prompt_Printf(&prompt, ", CCP: "); if (!arg->cx->ccp.fsm.StoppedTimer.load) prompt_Printf(&prompt, "Disabled"); else prompt_Printf(&prompt, "%ld secs", arg->cx->ccp.fsm.StoppedTimer.load / SECTICKS); prompt_Printf(&prompt, "\n"); return 0; } static int ShowAuthKey(struct cmdargs const *arg) { prompt_Printf(&prompt, "AuthName = %s\n", VarAuthName); prompt_Printf(&prompt, "AuthKey = %s\n", HIDDEN); #ifdef HAVE_DES prompt_Printf(&prompt, "Encrypt = %s\n", VarMSChap ? "MSChap" : "MD5" ); #endif return 0; } static int ShowVersion(struct cmdargs const *arg) { prompt_Printf(&prompt, "%s - %s \n", VarVersion, VarLocalVersion); return 0; } static int ShowInitialMRU(struct cmdargs const *arg) { prompt_Printf(&prompt, " Initial MRU: %d\n", VarMRU); return 0; } static int ShowPreferredMTU(struct cmdargs const *arg) { if (VarPrefMTU) prompt_Printf(&prompt, " Preferred MTU: %d\n", VarPrefMTU); else prompt_Printf(&prompt, " Preferred MTU: unspecified\n"); return 0; } static int ShowReconnect(struct cmdargs const *arg) { prompt_Printf(&prompt, "%s: Reconnect Timer: %d, %d tries\n", arg->cx->name, arg->cx->cfg.reconnect_timeout, arg->cx->cfg.max_reconnect); return 0; } static int ShowRedial(struct cmdargs const *arg) { prompt_Printf(&prompt, " Redial Timer: "); if (arg->cx->cfg.dial_timeout >= 0) prompt_Printf(&prompt, " %d seconds, ", arg->cx->cfg.dial_timeout); else prompt_Printf(&prompt, " Random 0 - %d seconds, ", DIAL_TIMEOUT); prompt_Printf(&prompt, " Redial Next Timer: "); if (arg->cx->cfg.dial_next_timeout >= 0) prompt_Printf(&prompt, " %d seconds, ", arg->cx->cfg.dial_next_timeout); else prompt_Printf(&prompt, " Random 0 - %d seconds, ", DIAL_TIMEOUT); if (arg->cx->cfg.max_dial) prompt_Printf(&prompt, "%d dial tries", arg->cx->cfg.max_dial); prompt_Printf(&prompt, "\n"); return 0; } #ifndef NOMSEXT static int ShowMSExt(struct cmdargs const *arg) { prompt_Printf(&prompt, " MS PPP extention values \n"); prompt_Printf(&prompt, " Primary NS : %s\n", inet_ntoa(IpcpInfo.cfg.ns_entries[0])); prompt_Printf(&prompt, " Secondary NS : %s\n", inet_ntoa(IpcpInfo.cfg.ns_entries[1])); prompt_Printf(&prompt, " Primary NBNS : %s\n", inet_ntoa(IpcpInfo.cfg.nbns_entries[0])); prompt_Printf(&prompt, " Secondary NBNS : %s\n", inet_ntoa(IpcpInfo.cfg.nbns_entries[1])); return 0; } #endif static struct cmdtab const ShowCommands[] = { {"afilter", NULL, ShowAfilter, LOCAL_AUTH, "Show keep-alive filters", "show afilter option .."}, {"auth", NULL, ShowAuthKey, LOCAL_AUTH, "Show auth details", "show auth"}, {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT, "Show CCP status", "show cpp"}, {"compress", NULL, ReportCompress, LOCAL_AUTH, "Show compression stats", "show compress"}, {"dfilter", NULL, ShowDfilter, LOCAL_AUTH, "Show Demand filters", "show dfilteroption .."}, {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX, "Show escape characters", "show escape"}, {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX, "Show HDLC errors", "show hdlc"}, {"ifilter", NULL, ShowIfilter, LOCAL_AUTH, "Show Input filters", "show ifilter option .."}, {"ipcp", NULL, ReportIpcpStatus, LOCAL_AUTH, "Show IPCP status", "show ipcp"}, {"lcp", NULL, ReportLcpStatus, LOCAL_AUTH, "Show LCP status", "show lcp"}, {"links", "link", bundle_ShowLinks, LOCAL_AUTH, "Show available link names", "show links"}, {"loopback", NULL, ShowLoopback, LOCAL_AUTH, "Show loopback setting", "show loopback"}, {"log", NULL, ShowLogLevel, LOCAL_AUTH, "Show log levels", "show log"}, {"mem", NULL, ShowMemMap, LOCAL_AUTH, "Show memory map", "show mem"}, {"modem", NULL, modem_ShowStatus, LOCAL_AUTH | LOCAL_CX, "Show modem setups", "show modem"}, {"mru", NULL, ShowInitialMRU, LOCAL_AUTH, "Show Initial MRU", "show mru"}, #ifndef NOMSEXT {"msext", NULL, ShowMSExt, LOCAL_AUTH, "Show MS PPP extentions", "show msext"}, #endif {"mtu", NULL, ShowPreferredMTU, LOCAL_AUTH, "Show Preferred MTU", "show mtu"}, {"ofilter", NULL, ShowOfilter, LOCAL_AUTH, "Show Output filters", "show ofilter option .."}, {"proto", NULL, Physical_ReportProtocolStatus, LOCAL_AUTH, "Show protocol summary", "show proto"}, {"reconnect", NULL, ShowReconnect, LOCAL_AUTH | LOCAL_CX, "Show reconnect timer", "show reconnect"}, {"redial", NULL, ShowRedial, LOCAL_AUTH | LOCAL_CX, "Show Redial timeout", "show redial"}, {"route", NULL, ShowRoute, LOCAL_AUTH, "Show routing table", "show route"}, {"timeout", NULL, ShowTimeout, LOCAL_AUTH, "Show Idle timeout", "show timeout"}, {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX, "Show STOPPED timeout", "show stopped"}, {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH, "Show version string", "show version"}, {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH, "Display this message", "show help|? [command]", ShowCommands}, {NULL, NULL, NULL}, }; static struct cmdtab const * FindCommand(struct cmdtab const *cmds, const char *str, int *pmatch) { int nmatch; int len; struct cmdtab const *found; found = NULL; len = strlen(str); nmatch = 0; while (cmds->func) { if (cmds->name && strncasecmp(str, cmds->name, len) == 0) { if (cmds->name[len] == '\0') { *pmatch = 1; return cmds; } nmatch++; found = cmds; } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) { if (cmds->alias[len] == '\0') { *pmatch = 1; return cmds; } nmatch++; found = cmds; } cmds++; } *pmatch = nmatch; return found; } static int FindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, char const *const *argv, const char *prefix, struct datalink *cx) { struct cmdtab const *cmd; int val = 1; int nmatch; struct cmdargs arg; cmd = FindCommand(cmds, *argv, &nmatch); if (nmatch > 1) LogPrintf(LogWARN, "%s%s: Ambiguous command\n", prefix, *argv); else if (cmd && (cmd->lauth & VarLocalAuth)) { if ((cmd->lauth & LOCAL_CX) && !cx) /* We've got no context, but we require it */ cx = bundle2datalink(bundle, NULL); if ((cmd->lauth & LOCAL_CX) && !cx) LogPrintf(LogWARN, "%s%s: No context (use the `link' command)\n", prefix, *argv); else { if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) { LogPrintf(LogWARN, "%s%s: Redundant context (%s) ignored\n", prefix, *argv, cx->name); cx = NULL; } arg.cmdtab = cmds; arg.cmd = cmd; arg.argc = argc-1; arg.argv = argv+1; arg.bundle = bundle; arg.cx = cx; val = (cmd->func) (&arg); } } else LogPrintf(LogWARN, "%s%s: Invalid command\n", prefix, *argv); if (val == -1) LogPrintf(LogWARN, "Usage: %s\n", cmd->syntax); else if (val) LogPrintf(LogWARN, "%s%s: Failed %d\n", prefix, *argv, val); return val; } void InterpretCommand(char *buff, int nb, int *argc, char ***argv) { static char *vector[MAXARGS]; char *cp; if (nb > 0) { cp = buff + strcspn(buff, "\r\n"); if (cp) *cp = '\0'; *argc = MakeArgs(buff, vector, VECSIZE(vector)); *argv = vector; } else *argc = 0; } static int arghidden(int argc, char const *const *argv, int n) { /* Is arg n of the given command to be hidden from the log ? */ /* set authkey xxxxx */ /* set key xxxxx */ if (n == 2 && !strncasecmp(argv[0], "se", 2) && (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2))) return 1; /* passwd xxxxx */ if (n == 1 && !strncasecmp(argv[0], "p", 1)) return 1; return 0; } void RunCommand(struct bundle *bundle, int argc, char const *const *argv, const char *label) { if (argc > 0) { if (LogIsKept(LogCOMMAND)) { static char buf[LINE_LEN]; int f, n; *buf = '\0'; if (label) { strncpy(buf, label, sizeof buf - 3); buf[sizeof buf - 3] = '\0'; strcat(buf, ": "); } n = strlen(buf); for (f = 0; f < argc; f++) { if (n < sizeof buf - 1 && f) buf[n++] = ' '; if (arghidden(argc, argv, f)) strncpy(buf+n, HIDDEN, sizeof buf - n - 1); else strncpy(buf+n, argv[f], sizeof buf - n - 1); n += strlen(buf+n); } LogPrintf(LogCOMMAND, "%s\n", buf); } FindExec(bundle, Commands, argc, argv, "", NULL); } } void DecodeCommand(struct bundle *bundle, char *buff, int nb, const char *label) { int argc; char **argv; InterpretCommand(buff, nb, &argc, &argv); RunCommand(bundle, argc, (char const *const *)argv, label); } static int ShowCommand(struct cmdargs const *arg) { if (!prompt_Active(&prompt)) LogPrintf(LogWARN, "show: Cannot show without a prompt\n"); else if (arg->argc > 0) FindExec(arg->bundle, ShowCommands, arg->argc, arg->argv, "show ", arg->cx); else if (prompt_Active(&prompt)) prompt_Printf(&prompt, "Use ``show ?'' to get a list.\n"); else LogPrintf(LogWARN, "show command must have arguments\n"); return 0; } static int TerminalCommand(struct cmdargs const *arg) { if (LcpInfo.fsm.state > ST_CLOSED) { prompt_Printf(&prompt, "LCP state is [%s]\n", StateNames[LcpInfo.fsm.state]); return 1; } if (!IsInteractive(1)) return (1); datalink_Up(arg->cx, 0, 0); prompt_Printf(&prompt, "Entering terminal mode.\n"); prompt_Printf(&prompt, "Type `~?' for help.\n"); prompt_TtyTermMode(&prompt, arg->cx); return 0; } static int QuitCommand(struct cmdargs const *arg) { if (prompt_Active(&prompt)) { prompt_Drop(&prompt, 1); if ((mode & MODE_INTER) || (arg->argc > 0 && !strcasecmp(*arg->argv, "all") && (VarLocalAuth & LOCAL_AUTH))) Cleanup(EX_NORMAL); } return 0; } static int CloseCommand(struct cmdargs const *arg) { bundle_Close(LcpInfo.fsm.bundle, arg->cx ? arg->cx->name : NULL, 1); return 0; } static int DownCommand(struct cmdargs const *arg) { link_Close(&arg->cx->physical->link, arg->bundle, 0, 1); return 0; } static int SetModemSpeed(struct cmdargs const *arg) { long speed; char *end; if (arg->argc > 0 && **arg->argv) { if (arg->argc > 1) { LogPrintf(LogWARN, "SetModemSpeed: Too many arguments"); return -1; } if (strcasecmp(*arg->argv, "sync") == 0) { Physical_SetSync(arg->cx->physical); return 0; } end = NULL; speed = strtol(*arg->argv, &end, 10); if (*end) { LogPrintf(LogWARN, "SetModemSpeed: Bad argument \"%s\"", *arg->argv); return -1; } if (Physical_SetSpeed(arg->cx->physical, speed)) return 0; LogPrintf(LogWARN, "%s: Invalid speed\n", *arg->argv); } else LogPrintf(LogWARN, "SetModemSpeed: No speed specified\n"); return -1; } static int SetReconnect(struct cmdargs const *arg) { if (arg->argc == 2) { arg->cx->cfg.reconnect_timeout = atoi(arg->argv[0]); arg->cx->cfg.max_reconnect = (mode & MODE_DIRECT) ? 0 : atoi(arg->argv[1]); return 0; } return -1; } static int SetRedialTimeout(struct cmdargs const *arg) { int timeout; int tries; char *dot; if (arg->argc == 1 || arg->argc == 2) { if (strncasecmp(arg->argv[0], "random", 6) == 0 && (arg->argv[0][6] == '\0' || arg->argv[0][6] == '.')) { arg->cx->cfg.dial_timeout = -1; randinit(); } else { timeout = atoi(arg->argv[0]); if (timeout >= 0) arg->cx->cfg.dial_timeout = timeout; else { LogPrintf(LogWARN, "Invalid redial timeout\n"); return -1; } } dot = strchr(arg->argv[0], '.'); if (dot) { if (strcasecmp(++dot, "random") == 0) { arg->cx->cfg.dial_next_timeout = -1; randinit(); } else { timeout = atoi(dot); if (timeout >= 0) arg->cx->cfg.dial_next_timeout = timeout; else { LogPrintf(LogWARN, "Invalid next redial timeout\n"); return -1; } } } else /* Default next timeout */ arg->cx->cfg.dial_next_timeout = DIAL_NEXT_TIMEOUT; if (arg->argc == 2) { tries = atoi(arg->argv[1]); if (tries >= 0) { arg->cx->cfg.max_dial = tries; } else { LogPrintf(LogWARN, "Invalid retry value\n"); return 1; } } return 0; } return -1; } static int SetStoppedTimeout(struct cmdargs const *arg) { LcpInfo.fsm.StoppedTimer.load = 0; arg->cx->ccp.fsm.StoppedTimer.load = 0; if (arg->argc <= 2) { if (arg->argc > 0) { LcpInfo.fsm.StoppedTimer.load = atoi(arg->argv[0]) * SECTICKS; if (arg->argc > 1) arg->cx->ccp.fsm.StoppedTimer.load = atoi(arg->argv[1]) * SECTICKS; } return 0; } return -1; } #define ismask(x) \ (*x == '0' && strlen(x) == 4 && strspn(x+1, "0123456789.") == 3) static int SetServer(struct cmdargs const *arg) { int res = -1; if (arg->argc > 0 && arg->argc < 4) { const char *port, *passwd, *mask; /* What's what ? */ port = arg->argv[0]; if (arg->argc == 2) if (ismask(arg->argv[1])) { passwd = NULL; mask = arg->argv[1]; } else { passwd = arg->argv[1]; mask = NULL; } else if (arg->argc == 3) { passwd = arg->argv[1]; mask = arg->argv[2]; if (!ismask(mask)) return -1; } else passwd = mask = NULL; if (passwd == NULL) VarHaveLocalAuthKey = 0; else { strncpy(VarLocalAuthKey, passwd, sizeof VarLocalAuthKey - 1); VarLocalAuthKey[sizeof VarLocalAuthKey - 1] = '\0'; VarHaveLocalAuthKey = 1; } LocalAuthInit(); if (strcasecmp(port, "none") == 0) { if (mask != NULL || passwd != NULL) return -1; if (ServerClose()) LogPrintf(LogPHASE, "Disabled server port.\n"); res = 0; } else if (*port == '/') { mode_t imask; if (mask != NULL) { unsigned m; if (sscanf(mask, "%o", &m) == 1) imask = m; else return -1; } else imask = (mode_t)-1; res = ServerLocalOpen(port, imask); } else { int iport; if (mask != NULL) return -1; if (strspn(port, "0123456789") != strlen(port)) { struct servent *s; if ((s = getservbyname(port, "tcp")) == NULL) { iport = 0; LogPrintf(LogWARN, "%s: Invalid port or service\n", port); } else iport = ntohs(s->s_port); } else iport = atoi(port); res = iport ? ServerTcpOpen(iport) : -1; } } return res; } static int SetModemParity(struct cmdargs const *arg) { return arg->argc > 0 ? modem_SetParity(arg->cx->physical, *arg->argv) : -1; } static int SetLogLevel(struct cmdargs const *arg) { int i; int res; int argc; char const *const *argv, *argp; void (*Discard)(int), (*Keep)(int); void (*DiscardAll)(void); argc = arg->argc; argv = arg->argv; res = 0; if (argc == 0 || strcasecmp(argv[0], "local")) { Discard = LogDiscard; Keep = LogKeep; DiscardAll = LogDiscardAll; } else { argc--; argv++; Discard = LogDiscardLocal; Keep = LogKeepLocal; DiscardAll = LogDiscardAllLocal; } if (argc == 0 || (argv[0][0] != '+' && argv[0][0] != '-')) DiscardAll(); while (argc--) { argp = **argv == '+' || **argv == '-' ? *argv + 1 : *argv; for (i = LogMIN; i <= LogMAX; i++) if (strcasecmp(argp, LogName(i)) == 0) { if (**argv == '-') (*Discard)(i); else (*Keep)(i); break; } if (i > LogMAX) { LogPrintf(LogWARN, "%s: Invalid log value\n", argp); res = -1; } argv++; } return res; } static int SetEscape(struct cmdargs const *arg) { int code; int argc = arg->argc; char const *const *argv = arg->argv; for (code = 0; code < 33; code++) arg->cx->physical->async.cfg.EscMap[code] = 0; while (argc-- > 0) { sscanf(*argv++, "%x", &code); code &= 0xff; arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7)); arg->cx->physical->async.cfg.EscMap[32] = 1; } return 0; } static int SetInitialMRU(struct cmdargs const *arg) { long mru; const char *err; if (arg->argc > 0) { mru = atol(*arg->argv); if (mru < MIN_MRU) err = "Given MRU value (%ld) is too small.\n"; else if (mru > MAX_MRU) err = "Given MRU value (%ld) is too big.\n"; else { VarMRU = mru; return 0; } LogPrintf(LogWARN, err, mru); } return -1; } static int SetPreferredMTU(struct cmdargs const *arg) { long mtu; const char *err; if (arg->argc > 0) { mtu = atol(*arg->argv); if (mtu == 0) { VarPrefMTU = 0; return 0; } else if (mtu < MIN_MTU) err = "Given MTU value (%ld) is too small.\n"; else if (mtu > MAX_MTU) err = "Given MTU value (%ld) is too big.\n"; else { VarPrefMTU = mtu; return 0; } LogPrintf(LogWARN, err, mtu); } return -1; } static int SetIdleTimeout(struct cmdargs const *arg) { if (arg->argc > 0) { VarIdleTimeout = atoi(arg->argv[0]); /* If we're connected, restart the idle timer */ UpdateIdleTimer(arg->bundle); if (arg->argc > 1) { VarLqrTimeout = atoi(arg->argv[1]); if (VarLqrTimeout < 1) VarLqrTimeout = 30; if (arg->argc > 2) { VarRetryTimeout = atoi(arg->argv[2]); if (VarRetryTimeout < 1 || VarRetryTimeout > 10) VarRetryTimeout = 3; } } return 0; } return -1; } static struct in_addr GetIpAddr(const char *cp) { struct hostent *hp; struct in_addr ipaddr; if (inet_aton(cp, &ipaddr) == 0) { hp = gethostbyname(cp); if (hp && hp->h_addrtype == AF_INET) memcpy(&ipaddr, hp->h_addr, hp->h_length); else ipaddr.s_addr = 0; } return (ipaddr); } static int SetInterfaceAddr(struct cmdargs const *arg) { const char *hisaddr; hisaddr = NULL; IpcpInfo.cfg.my_range.ipaddr.s_addr = INADDR_ANY; IpcpInfo.cfg.peer_range.ipaddr.s_addr = INADDR_ANY; if (arg->argc > 4) return -1; IpcpInfo.cfg.HaveTriggerAddress = 0; ifnetmask.s_addr = 0; iplist_reset(&IpcpInfo.cfg.peer_list); if (arg->argc > 0) { if (!ParseAddr(arg->argc, arg->argv, &IpcpInfo.cfg.my_range.ipaddr, &IpcpInfo.cfg.my_range.mask, &IpcpInfo.cfg.my_range.width)) return 1; if (arg->argc > 1) { hisaddr = arg->argv[1]; if (arg->argc > 2) { ifnetmask = GetIpAddr(arg->argv[2]); if (arg->argc > 3) { IpcpInfo.cfg.TriggerAddress = GetIpAddr(arg->argv[3]); IpcpInfo.cfg.HaveTriggerAddress = 1; } } } } /* * For backwards compatibility, 0.0.0.0 means any address. */ if (IpcpInfo.cfg.my_range.ipaddr.s_addr == INADDR_ANY) { IpcpInfo.cfg.my_range.mask.s_addr = INADDR_ANY; IpcpInfo.cfg.my_range.width = 0; } IpcpInfo.my_ip.s_addr = IpcpInfo.cfg.my_range.ipaddr.s_addr; if (IpcpInfo.cfg.peer_range.ipaddr.s_addr == INADDR_ANY) { IpcpInfo.cfg.peer_range.mask.s_addr = INADDR_ANY; IpcpInfo.cfg.peer_range.width = 0; } if (hisaddr && !UseHisaddr(arg->bundle, hisaddr, mode & MODE_AUTO)) return 4; return 0; } #ifndef NOMSEXT static void SetMSEXT(struct in_addr * pri_addr, struct in_addr * sec_addr, int argc, char const *const *argv) { int dummyint; struct in_addr dummyaddr; pri_addr->s_addr = sec_addr->s_addr = 0L; if (argc > 0) { ParseAddr(argc, argv++, pri_addr, &dummyaddr, &dummyint); if (--argc > 0) ParseAddr(argc, argv++, sec_addr, &dummyaddr, &dummyint); else sec_addr->s_addr = pri_addr->s_addr; } /* * if the primary/secondary ns entries are 0.0.0.0 we should set them to * either the localhost's ip, or the values in /etc/resolv.conf ?? * * up to you if you want to implement this... */ } static int SetNS(struct cmdargs const *arg) { SetMSEXT(&IpcpInfo.cfg.ns_entries[0], &IpcpInfo.cfg.ns_entries[1], arg->argc, arg->argv); return 0; } static int SetNBNS(struct cmdargs const *arg) { SetMSEXT(&IpcpInfo.cfg.nbns_entries[0], &IpcpInfo.cfg.nbns_entries[1], arg->argc, arg->argv); return 0; } #endif /* MS_EXT */ static int SetVariable(struct cmdargs const *arg) { u_long map; const char *argp; int param = (int)arg->cmd->args; struct datalink *cx = arg->cx; if (arg->argc > 0) argp = *arg->argv; else argp = ""; if ((arg->cmd->lauth & LOCAL_CX) && !cx) { LogPrintf(LogWARN, "set %s: No context (use the `link' command)\n", arg->cmd->name); return 1; } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) { LogPrintf(LogWARN, "set %s: Redundant context (%s) ignored\n", arg->cmd->name, cx->name); cx = NULL; } switch (param) { case VAR_AUTHKEY: strncpy(VarAuthKey, argp, sizeof VarAuthKey - 1); VarAuthKey[sizeof VarAuthKey - 1] = '\0'; break; case VAR_AUTHNAME: strncpy(VarAuthName, argp, sizeof VarAuthName - 1); VarAuthName[sizeof VarAuthName - 1] = '\0'; break; case VAR_DIAL: if (!(mode & (MODE_DIRECT|MODE_DEDICATED))) { strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1); cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0'; } break; case VAR_LOGIN: if (!(mode & (MODE_DIRECT|MODE_DEDICATED))) { strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1); cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0'; } break; case VAR_DEVICE: modem_SetDeviceName(cx->physical, argp); break; case VAR_ACCMAP: sscanf(argp, "%lx", &map); VarAccmap = map; break; case VAR_PHONE: strncpy(VarPhoneList, argp, sizeof VarPhoneList - 1); VarPhoneList[sizeof VarPhoneList - 1] = '\0'; strncpy(VarPhoneCopy, VarPhoneList, sizeof VarPhoneCopy - 1); VarPhoneCopy[sizeof VarPhoneCopy - 1] = '\0'; VarNextPhone = VarPhoneCopy; VarAltPhone = NULL; break; case VAR_HANGUP: if (!(mode & (MODE_DIRECT|MODE_DEDICATED))) { strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1); cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0'; } break; #ifdef HAVE_DES case VAR_ENC: VarMSChap = !strcasecmp(argp, "mschap"); break; #endif } return 0; } static int SetCtsRts(struct cmdargs const *arg) { if (arg->argc > 0) { if (arg->argc > 1) { LogPrintf(LogWARN, "SetCtsRts: Too many arguments\n"); return -1; } if (strcmp(*arg->argv, "on") == 0) Physical_SetRtsCts(bundle2physical(arg->bundle, NULL), 1); else if (strcmp(*arg->argv, "off") == 0) Physical_SetRtsCts(bundle2physical(arg->bundle, NULL), 0); else return -1; return 0; } return -1; } static int SetOpenMode(struct cmdargs const *arg) { if (arg->argc > 0) { if (strcasecmp(*arg->argv, "active") == 0) VarOpenMode = arg->argc > 1 ? atoi(arg->argv[1]) : 1; else if (strcasecmp(*arg->argv, "passive") == 0) VarOpenMode = OPEN_PASSIVE; else return -1; return 0; } return -1; } static struct cmdtab const SetCommands[] = { {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "Set accmap value", "set accmap hex-value", (const void *) VAR_ACCMAP}, {"afilter", NULL, SetAfilter, LOCAL_AUTH, "Set keep Alive filter", "set afilter ..."}, {"authkey", "key", SetVariable, LOCAL_AUTH, "Set authentication key", "set authkey|key key", (const void *) VAR_AUTHKEY}, {"authname", NULL, SetVariable, LOCAL_AUTH, "Set authentication name", "set authname name", (const void *) VAR_AUTHNAME}, {"ctsrts", NULL, SetCtsRts, LOCAL_AUTH | LOCAL_CX, "Use CTS/RTS modem signalling", "set ctsrts [on|off]"}, {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX, "Set modem device name", "set device|line device-name[,device-name]", (const void *) VAR_DEVICE}, {"dfilter", NULL, SetDfilter, LOCAL_AUTH, "Set demand filter", "set dfilter ..."}, {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "Set dialing script", "set dial chat-script", (const void *) VAR_DIAL}, #ifdef HAVE_DES {"encrypt", NULL, SetVariable, LOCAL_AUTH, "Set CHAP encryption algorithm", "set encrypt MSChap|MD5", (const void *) VAR_ENC}, #endif {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX, "Set escape characters", "set escape hex-digit ..."}, {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "Set hangup script", "set hangup chat-script", (const void *) VAR_HANGUP}, {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "Set destination address", "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"}, {"ifilter", NULL, SetIfilter, LOCAL_AUTH, "Set input filter", "set ifilter ..."}, {"loopback", NULL, SetLoopback, LOCAL_AUTH, "Set loopback facility", "set loopback on|off"}, {"log", NULL, SetLogLevel, LOCAL_AUTH, "Set log level", "set log [local] [+|-]value..."}, {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "Set login script", "set login chat-script", (const void *) VAR_LOGIN}, {"mru", NULL, SetInitialMRU, LOCAL_AUTH, "Set Initial MRU value", "set mru value"}, {"mtu", NULL, SetPreferredMTU, LOCAL_AUTH, "Set Preferred MTU value", "set mtu value"}, #ifndef NOMSEXT {"nbns", NULL, SetNBNS, LOCAL_AUTH, "Set NetBIOS NameServer", "set nbns pri-addr [sec-addr]"}, {"ns", NULL, SetNS, LOCAL_AUTH, "Set NameServer", "set ns pri-addr [sec-addr]"}, #endif {"ofilter", NULL, SetOfilter, LOCAL_AUTH, "Set output filter", "set ofilter ..."}, {"openmode", NULL, SetOpenMode, LOCAL_AUTH | LOCAL_CX, "Set open mode", "set openmode [active|passive]"}, {"parity", NULL, SetModemParity, LOCAL_AUTH | LOCAL_CX, "Set modem parity", "set parity [odd|even|none]"}, {"phone", NULL, SetVariable, LOCAL_AUTH, "Set telephone number(s)", "set phone phone1[:phone2[...]]", (const void *) VAR_PHONE}, {"reconnect", NULL, SetReconnect, LOCAL_AUTH | LOCAL_CX, "Set Reconnect timeout", "set reconnect value ntries"}, {"redial", NULL, SetRedialTimeout, LOCAL_AUTH | LOCAL_CX, "Set Redial timeout", "set redial value|random[.value|random] [attempts]"}, {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX, "Set STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"}, {"server", "socket", SetServer, LOCAL_AUTH, "Set server port", "set server|socket TcpPort|LocalName|none [mask]"}, {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX, "Set modem speed", "set speed value"}, {"timeout", NULL, SetIdleTimeout, LOCAL_AUTH, "Set Idle timeout", "set timeout value"}, {"vj", NULL, SetInitVJ, LOCAL_AUTH, "Set vj values", "set vj slots|slotcomp"}, {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, "Display this message", "set help|? [command]", SetCommands}, {NULL, NULL, NULL}, }; static int SetCommand(struct cmdargs const *arg) { if (arg->argc > 0) FindExec(arg->bundle, SetCommands, arg->argc, arg->argv, "set ", arg->cx); else if (prompt_Active(&prompt)) prompt_Printf(&prompt, "Use `set ?' to get a list or `set ? ' for" " syntax help.\n"); else LogPrintf(LogWARN, "set command must have arguments\n"); return 0; } static int AddCommand(struct cmdargs const *arg) { struct in_addr dest, gateway, netmask; int gw; if (arg->argc != 3 && arg->argc != 2) return -1; if (arg->argc == 2) if (strcasecmp(arg->argv[0], "default")) return -1; else { dest.s_addr = netmask.s_addr = INADDR_ANY; gw = 1; } else { if (strcasecmp(arg->argv[0], "MYADDR") == 0) dest = IpcpInfo.my_ip; else if (strcasecmp(arg->argv[0], "HISADDR") == 0) dest = IpcpInfo.peer_ip; else dest = GetIpAddr(arg->argv[0]); netmask = GetIpAddr(arg->argv[1]); gw = 2; } if (strcasecmp(arg->argv[gw], "HISADDR") == 0) gateway = IpcpInfo.peer_ip; else if (strcasecmp(arg->argv[gw], "INTERFACE") == 0) gateway.s_addr = INADDR_ANY; else gateway = GetIpAddr(arg->argv[gw]); bundle_SetRoute(arg->bundle, RTM_ADD, dest, gateway, netmask, arg->cmd->args ? 1 : 0); return 0; } static int DeleteCommand(struct cmdargs const *arg) { struct in_addr dest, none; if (arg->argc == 1) if(strcasecmp(arg->argv[0], "all") == 0) DeleteIfRoutes(arg->bundle, 0); else { if (strcasecmp(arg->argv[0], "MYADDR") == 0) dest = IpcpInfo.my_ip; else if (strcasecmp(arg->argv[0], "default") == 0) dest.s_addr = INADDR_ANY; else dest = GetIpAddr(arg->argv[0]); none.s_addr = INADDR_ANY; bundle_SetRoute(arg->bundle, RTM_DELETE, dest, none, none, arg->cmd->args ? 1 : 0); } else return -1; return 0; } #ifndef NOALIAS static struct cmdtab const AliasCommands[] = { {"enable", NULL, AliasEnable, LOCAL_AUTH, "enable IP aliasing", "alias enable [yes|no]"}, {"port", NULL, AliasRedirectPort, LOCAL_AUTH, "port redirection", "alias port [proto addr_local:port_local port_alias]"}, {"addr", NULL, AliasRedirectAddr, LOCAL_AUTH, "static address translation", "alias addr [addr_local addr_alias]"}, {"deny_incoming", NULL, AliasOption, LOCAL_AUTH, "stop incoming connections", "alias deny_incoming [yes|no]", (const void *) PKT_ALIAS_DENY_INCOMING}, {"log", NULL, AliasOption, LOCAL_AUTH, "log aliasing link creation", "alias log [yes|no]", (const void *) PKT_ALIAS_LOG}, {"same_ports", NULL, AliasOption, LOCAL_AUTH, "try to leave port numbers unchanged", "alias same_ports [yes|no]", (const void *) PKT_ALIAS_SAME_PORTS}, {"use_sockets", NULL, AliasOption, LOCAL_AUTH, "allocate host sockets", "alias use_sockets [yes|no]", (const void *) PKT_ALIAS_USE_SOCKETS}, {"unregistered_only", NULL, AliasOption, LOCAL_AUTH, "alias unregistered (private) IP address space only", "alias unregistered_only [yes|no]", (const void *) PKT_ALIAS_UNREGISTERED_ONLY}, {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, "Display this message", "alias help|? [command]", AliasCommands}, {NULL, NULL, NULL}, }; static int AliasCommand(struct cmdargs const *arg) { if (arg->argc > 0) FindExec(arg->bundle, AliasCommands, arg->argc, arg->argv, "alias ", arg->cx); else if (prompt_Active(&prompt)) prompt_Printf(&prompt, "Use `alias help' to get a list or `alias help" "