Index: head/usr.sbin/ppp/Makefile =================================================================== --- head/usr.sbin/ppp/Makefile (revision 134788) +++ head/usr.sbin/ppp/Makefile (revision 134789) @@ -1,115 +1,116 @@ # $FreeBSD$ PROG= ppp MAN= ppp.8 SRCS= acf.c arp.c async.c auth.c bundle.c cbcp.c ccp.c chap.c chat.c \ command.c datalink.c deflate.c defs.c exec.c filter.c fsm.c hdlc.c \ iface.c ip.c ipcp.c ipv6cp.c iplist.c lcp.c link.c log.c lqr.c main.c \ mbuf.c mp.c ncp.c ncpaddr.c pap.c physical.c pred.c probe.c prompt.c \ proto.c route.c server.c sig.c slcompress.c sync.c systems.c tcp.c \ tcpmss.c throughput.c timer.c tty.c tun.c udp.c vjcomp.c +WARNS?= 5 .if defined(RELEASE_CRUNCH) CFLAGS+=-DRELEASE_CRUNCH NOATM= true NODES= true NOI4B= true NONAT= true NOKLDLOAD= true NOPAM= true NORADIUS= true NOSUID= true .endif .if defined(NOSUID) || defined(PPP_NOSUID) BINMODE=550 .else BINMODE=4550 BINOWN= root .endif BINGRP= network M4FLAGS= LDADD= -lcrypt -lmd -lutil -lz DPADD= ${LIBCRYPT} ${LIBMD} ${LIBUTIL} ${LIBZ} .SUFFIXES: .8 .8.m4 .8.m4.8: m4 ${M4FLAGS} ${.IMPSRC} >${.TARGET} CLEANFILES= ppp.8 .if defined(PPP_CONFDIR) && !empty(PPP_CONFDIR) CFLAGS+=-DPPP_CONFDIR=\"${PPP_CONFDIR}\" .endif .if defined(NOKLDLOAD) CFLAGS+=-DNOKLDLOAD .endif .if defined(NOINET6) CFLAGS+=-DNOINET6 .endif .if defined(NOALIAS) || defined(NONAT) CFLAGS+=-DNONAT .else SRCS+= nat_cmd.c LDADD+= -lalias DPADD+= ${LIBALIAS} .endif .if defined(NOATM) CFLAGS+=-DNOATM .else SRCS+= atm.c .endif .if defined(NOSUID) || defined(PPP_NOSUID) CFLAGS+=-DNOSUID .else SRCS+= id.c .endif .if defined(RELEASE_CRUNCH) || defined(NOCRYPT) || defined(NO_OPENSSL) CFLAGS+=-DNODES .else SRCS+= chap_ms.c mppe.c LDADD+= -lcrypto DPADD+= ${LIBCRYPTO} .endif .if defined(NORADIUS) CFLAGS+=-DNORADIUS .else SRCS+= radius.c LDADD+= -lradius DPADD+= ${LIBRADIUS} .endif .if defined(NOI4B) || ${MACHINE_ARCH} != "i386" CFLAGS+=-DNOI4B .else SRCS+= i4b.c .endif .if defined(NONETGRAPH) CFLAGS+=-DNONETGRAPH .else SRCS+= ether.c LDADD+= -lnetgraph DPADD+= ${LIBNETGRAPH} .if defined(EXPERIMENTAL_NETGRAPH) CFLAGS+=-DEXPERIMENTAL_NETGRAPH SRCS+= netgraph.c .endif .endif .if defined(NOPAM) CFLAGS+=-DNOPAM .else LDADD+= ${MINUSLPAM} DPADD+= ${LIBPAM} .endif .include Index: head/usr.sbin/ppp/acf.c =================================================================== --- head/usr.sbin/ppp/acf.c (revision 134788) +++ head/usr.sbin/ppp/acf.c (revision 134789) @@ -1,115 +1,116 @@ /*- * Copyright (c) 1999 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. * * $FreeBSD$ */ #include #include #include #include "defs.h" #include "layer.h" #include "timer.h" #include "fsm.h" #include "log.h" #include "mbuf.h" #include "acf.h" #include "proto.h" #include "throughput.h" #include "lqr.h" #include "hdlc.h" #include "lcp.h" #include "ccp.h" #include "link.h" #include "descriptor.h" #include "async.h" #include "physical.h" int acf_WrapperOctets(struct lcp *lcp, u_short proto) { return (proto == PROTO_LCP || lcp->his_acfcomp == 0) ? 2 : 0; } static struct mbuf * -acf_LayerPush(struct bundle *b, struct link *l, struct mbuf *bp, - int pri, u_short *proto) +acf_LayerPush(struct bundle *b __unused, struct link *l, struct mbuf *bp, + int pri __unused, u_short *proto) { const u_char cp[2] = { HDLC_ADDR, HDLC_UI }; if (*proto == PROTO_LCP || l->lcp.his_acfcomp == 0) { bp = m_prepend(bp, cp, 2, 0); m_settype(bp, MB_ACFOUT); } return bp; } static struct mbuf * -acf_LayerPull(struct bundle *b, struct link *l, struct mbuf *bp, u_short *proto) +acf_LayerPull(struct bundle *b __unused, struct link *l, struct mbuf *bp, + u_short *proto __unused) { struct physical *p = link2physical(l); u_char cp[2]; if (!p) { log_Printf(LogERROR, "Can't Pull an acf packet from a logical link\n"); return bp; } if (mbuf_View(bp, cp, 2) == 2) { if (!p->link.lcp.want_acfcomp) { /* We expect the packet not to be compressed */ bp = mbuf_Read(bp, cp, 2); if (cp[0] != HDLC_ADDR) { p->hdlc.lqm.ifInErrors++; p->hdlc.stats.badaddr++; log_Printf(LogDEBUG, "acf_LayerPull: addr 0x%02x\n", cp[0]); m_freem(bp); return NULL; } if (cp[1] != HDLC_UI) { p->hdlc.lqm.ifInErrors++; p->hdlc.stats.badcommand++; log_Printf(LogDEBUG, "acf_LayerPull: control 0x%02x\n", cp[1]); m_freem(bp); return NULL; } m_settype(bp, MB_ACFIN); } else if (cp[0] == HDLC_ADDR && cp[1] == HDLC_UI) { /* * We can receive compressed packets, but the peer still sends * uncompressed packets (or maybe this is a PROTO_LCP packet) ! */ bp = mbuf_Read(bp, cp, 2); m_settype(bp, MB_ACFIN); } } return bp; } struct layer acflayer = { LAYER_ACF, "acf", acf_LayerPush, acf_LayerPull }; Index: head/usr.sbin/ppp/arp.c =================================================================== --- head/usr.sbin/ppp/arp.c (revision 134788) +++ head/usr.sbin/ppp/arp.c (revision 134789) @@ -1,317 +1,317 @@ /* * sys-bsd.c - System-dependent procedures for setting up * PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, etc.) * * Copyright (c) 1989 Carnegie Mellon University. * All rights reserved. * * 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 Carnegie Mellon University. The name of the * University 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. * * $FreeBSD$ * */ /* * TODO: */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "layer.h" #include "mbuf.h" #include "log.h" #include "id.h" #include "timer.h" #include "fsm.h" #include "defs.h" #include "iplist.h" #include "throughput.h" #include "slcompress.h" #include "lqr.h" #include "hdlc.h" #include "ncpaddr.h" #include "ipcp.h" #include "ipv6cp.h" #include "descriptor.h" #include "lcp.h" #include "ccp.h" #include "link.h" #include "mp.h" #include "ncp.h" #include "filter.h" #ifndef NORADIUS #include "radius.h" #endif #include "bundle.h" #include "iface.h" #include "arp.h" /* * SET_SA_FAMILY - set the sa_family field of a struct sockaddr, * if it exists. */ #define SET_SA_FAMILY(addr, family) \ memset((char *) &(addr), '\0', sizeof(addr)); \ addr.sa_family = (family); \ addr.sa_len = sizeof(addr); #if RTM_VERSION >= 3 /* * arp_SetProxy - Make a proxy ARP entry for the peer. */ static struct { struct rt_msghdr hdr; struct sockaddr_inarp dst; struct sockaddr_dl hwa; char extra[128]; } arpmsg; static int -arp_ProxySub(struct bundle *bundle, struct in_addr addr, int add, int s) +arp_ProxySub(struct bundle *bundle, struct in_addr addr, int add) { int routes; /* * Get the hardware address of an interface on the same subnet as our local * address. */ memset(&arpmsg, 0, sizeof arpmsg); - if (!arp_EtherAddr(s, addr, &arpmsg.hwa, 0)) { + if (!arp_EtherAddr(addr, &arpmsg.hwa, 0)) { log_Printf(LogWARN, "%s: Cannot determine ethernet address for proxy ARP\n", inet_ntoa(addr)); return 0; } routes = ID0socket(PF_ROUTE, SOCK_RAW, AF_INET); if (routes < 0) { log_Printf(LogERROR, "arp_SetProxy: opening routing socket: %s\n", strerror(errno)); return 0; } arpmsg.hdr.rtm_type = add ? RTM_ADD : RTM_DELETE; arpmsg.hdr.rtm_flags = RTF_ANNOUNCE | RTF_HOST | RTF_STATIC; arpmsg.hdr.rtm_version = RTM_VERSION; arpmsg.hdr.rtm_seq = ++bundle->routing_seq; arpmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY; arpmsg.hdr.rtm_inits = RTV_EXPIRE; arpmsg.dst.sin_len = sizeof(struct sockaddr_inarp); arpmsg.dst.sin_family = AF_INET; arpmsg.dst.sin_addr.s_addr = addr.s_addr; arpmsg.dst.sin_other = SIN_PROXY; arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg + arpmsg.hwa.sdl_len; if (ID0write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0 && !(!add && errno == ESRCH)) { log_Printf(LogERROR, "%s proxy arp entry %s: %s\n", add ? "Add" : "Delete", inet_ntoa(addr), strerror(errno)); close(routes); return 0; } close(routes); return 1; } int -arp_SetProxy(struct bundle *bundle, struct in_addr addr, int s) +arp_SetProxy(struct bundle *bundle, struct in_addr addr) { - return (arp_ProxySub(bundle, addr, 1, s)); + return (arp_ProxySub(bundle, addr, 1)); } /* * arp_ClearProxy - Delete the proxy ARP entry for the peer. */ int -arp_ClearProxy(struct bundle *bundle, struct in_addr addr, int s) +arp_ClearProxy(struct bundle *bundle, struct in_addr addr) { - return (arp_ProxySub(bundle, addr, 0, s)); + return (arp_ProxySub(bundle, addr, 0)); } #else /* RTM_VERSION */ /* * arp_SetProxy - Make a proxy ARP entry for the peer. */ int arp_SetProxy(struct bundle *bundle, struct in_addr addr, int s) { struct arpreq arpreq; struct { struct sockaddr_dl sdl; char space[128]; } dls; memset(&arpreq, '\0', sizeof arpreq); /* * Get the hardware address of an interface on the same subnet as our local * address. */ - if (!arp_EtherAddr(s, addr, &dls.sdl, 1)) { + if (!arp_EtherAddr(addr, &dls.sdl, 1)) { log_Printf(LOG_PHASE_BIT, "Cannot determine ethernet address for " "proxy ARP\n"); return 0; } arpreq.arp_ha.sa_len = sizeof(struct sockaddr); arpreq.arp_ha.sa_family = AF_UNSPEC; memcpy(arpreq.arp_ha.sa_data, LLADDR(&dls.sdl), dls.sdl.sdl_alen); SET_SA_FAMILY(arpreq.arp_pa, AF_INET); ((struct sockaddr_in *)&arpreq.arp_pa)->sin_addr.s_addr = addr.s_addr; arpreq.arp_flags = ATF_PERM | ATF_PUBL; if (ID0ioctl(s, SIOCSARP, (caddr_t) & arpreq) < 0) { log_Printf(LogERROR, "arp_SetProxy: ioctl(SIOCSARP): %s\n", strerror(errno)); return 0; } return 1; } /* * arp_ClearProxy - Delete the proxy ARP entry for the peer. */ int arp_ClearProxy(struct bundle *bundle, struct in_addr addr, int s) { struct arpreq arpreq; memset(&arpreq, '\0', sizeof arpreq); SET_SA_FAMILY(arpreq.arp_pa, AF_INET); ((struct sockaddr_in *)&arpreq.arp_pa)->sin_addr.s_addr = addr.s_addr; if (ID0ioctl(s, SIOCDARP, (caddr_t) & arpreq) < 0) { log_Printf(LogERROR, "arp_ClearProxy: ioctl(SIOCDARP): %s\n", strerror(errno)); return 0; } return 1; } #endif /* RTM_VERSION */ /* * arp_EtherAddr - get the hardware address of an interface on the * the same subnet as ipaddr. */ int -arp_EtherAddr(int s, struct in_addr ipaddr, struct sockaddr_dl *hwaddr, +arp_EtherAddr(struct in_addr ipaddr, struct sockaddr_dl *hwaddr, int verbose) { int mib[6], skip; size_t needed; char *buf, *ptr, *end; struct if_msghdr *ifm; struct ifa_msghdr *ifam; struct sockaddr_dl *dl; struct sockaddr *sa[RTAX_MAX]; mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = 0; mib[4] = NET_RT_IFLIST; mib[5] = 0; if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { log_Printf(LogERROR, "arp_EtherAddr: sysctl: estimate: %s\n", strerror(errno)); return 0; } if ((buf = malloc(needed)) == NULL) return 0; if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { free(buf); return 0; } end = buf + needed; ptr = buf; while (ptr < end) { ifm = (struct if_msghdr *)ptr; /* On if_msghdr */ if (ifm->ifm_type != RTM_IFINFO) break; dl = (struct sockaddr_dl *)(ifm + 1); /* Single _dl at end */ skip = (ifm->ifm_flags & (IFF_UP | IFF_BROADCAST | IFF_POINTOPOINT | IFF_NOARP | IFF_LOOPBACK)) != (IFF_UP | IFF_BROADCAST); ptr += ifm->ifm_msglen; /* First ifa_msghdr */ while (ptr < end) { ifam = (struct ifa_msghdr *)ptr; /* Next ifa_msghdr (alias) */ if (ifam->ifam_type != RTM_NEWADDR) /* finished ? */ break; ptr += ifam->ifam_msglen; if (skip || (ifam->ifam_addrs & (RTA_NETMASK|RTA_IFA)) != (RTA_NETMASK|RTA_IFA)) continue; /* Found a candidate. Do the addresses match ? */ if (log_IsKept(LogDEBUG) && ptr == (char *)ifm + ifm->ifm_msglen + ifam->ifam_msglen) log_Printf(LogDEBUG, "%.*s interface is a candidate for proxy\n", dl->sdl_nlen, dl->sdl_data); iface_ParseHdr(ifam, sa); if (sa[RTAX_IFA]->sa_family == AF_INET) { struct sockaddr_in *ifa, *netmask; ifa = (struct sockaddr_in *)sa[RTAX_IFA]; netmask = (struct sockaddr_in *)sa[RTAX_NETMASK]; if (log_IsKept(LogDEBUG)) { char a[16]; strncpy(a, inet_ntoa(netmask->sin_addr), sizeof a - 1); a[sizeof a - 1] = '\0'; log_Printf(LogDEBUG, "Check addr %s, mask %s\n", inet_ntoa(ifa->sin_addr), a); } if ((ifa->sin_addr.s_addr & netmask->sin_addr.s_addr) == (ipaddr.s_addr & netmask->sin_addr.s_addr)) { log_Printf(verbose ? LogPHASE : LogDEBUG, "Found interface %.*s for %s\n", dl->sdl_nlen, dl->sdl_data, inet_ntoa(ipaddr)); memcpy(hwaddr, dl, dl->sdl_len); free(buf); return 1; } } } } free(buf); return 0; } Index: head/usr.sbin/ppp/arp.h =================================================================== --- head/usr.sbin/ppp/arp.h (revision 134788) +++ head/usr.sbin/ppp/arp.h (revision 134789) @@ -1,36 +1,36 @@ /*- * Copyright (c) 1996 - 2001 Brian Somers * based on work by Toshiharu OHNO * Internet Initiative Japan, Inc (IIJ) * 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. * * $FreeBSD$ */ struct sockaddr_dl; struct bundle; -extern int arp_ClearProxy(struct bundle *, struct in_addr, int); -extern int arp_SetProxy(struct bundle *, struct in_addr, int); -extern int arp_EtherAddr(int, struct in_addr, struct sockaddr_dl *, int); +extern int arp_ClearProxy(struct bundle *, struct in_addr); +extern int arp_SetProxy(struct bundle *, struct in_addr); +extern int arp_EtherAddr(struct in_addr, struct sockaddr_dl *, int); Index: head/usr.sbin/ppp/async.c =================================================================== --- head/usr.sbin/ppp/async.c (revision 134788) +++ head/usr.sbin/ppp/async.c (revision 134789) @@ -1,220 +1,220 @@ /*- * Copyright (c) 1996 - 2001 Brian Somers * based on work by Toshiharu OHNO * Internet Initiative Japan, Inc (IIJ) * 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. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include "layer.h" #include "mbuf.h" #include "log.h" #include "defs.h" #include "timer.h" #include "fsm.h" #include "lqr.h" #include "hdlc.h" #include "lcp.h" #include "proto.h" #include "async.h" #include "throughput.h" #include "ccp.h" #include "link.h" #include "descriptor.h" #include "physical.h" #define MODE_HUNT 0x01 #define MODE_ESC 0x02 void async_Init(struct async *async) { async_Setup(async); memset(async->cfg.EscMap, '\0', sizeof async->cfg.EscMap); } void async_Setup(struct async *async) { async->mode = MODE_HUNT; async->length = 0; async->my_accmap = async->his_accmap = 0xffffffff; } void async_SetLinkParams(struct async *async, u_int32_t mymap, u_int32_t hismap) { async->my_accmap = mymap; async->his_accmap = hismap | mymap; } /* * Encode into async HDLC byte code */ static void async_Encode(struct async *async, u_char **cp, u_char c, int proto) { u_char *wp; wp = *cp; if ((c < 0x20 && (proto == PROTO_LCP || (async->his_accmap & (1 << c)))) || (c == HDLC_ESC) || (c == HDLC_SYN)) { *wp++ = HDLC_ESC; c ^= HDLC_XOR; } if (async->cfg.EscMap[32] && async->cfg.EscMap[c >> 3] & (1 << (c & 7))) { *wp++ = HDLC_ESC; c ^= HDLC_XOR; } *wp++ = c; *cp = wp; } static struct mbuf * -async_LayerPush(struct bundle *bundle, struct link *l, struct mbuf *bp, - int pri, u_short *proto) +async_LayerPush(struct bundle *b __unused, struct link *l, struct mbuf *bp, + int pri __unused, u_short *proto) { struct physical *p = link2physical(l); u_char *cp, *sp, *ep; struct mbuf *wp; size_t oldcnt; - int cnt; + size_t cnt; if (!p || m_length(bp) > HDLCSIZE) { m_freem(bp); return NULL; } oldcnt = m_length(bp); cp = p->async.xbuff; ep = cp + HDLCSIZE - 10; wp = bp; *cp++ = HDLC_SYN; while (wp) { sp = MBUF_CTOP(wp); for (cnt = wp->m_len; cnt > 0; cnt--) { async_Encode(&p->async, &cp, *sp++, *proto); if (cp >= ep) { m_freem(bp); return NULL; } } wp = wp->m_next; } *cp++ = HDLC_SYN; cnt = cp - p->async.xbuff; m_freem(bp); bp = m_get(cnt, MB_ASYNCOUT); memcpy(MBUF_CTOP(bp), p->async.xbuff, cnt); bp->priv = cnt - oldcnt; log_DumpBp(LogASYNC, "Write", bp); return bp; } static struct mbuf * async_Decode(struct async *async, u_char c) { struct mbuf *bp; if ((async->mode & MODE_HUNT) && c != HDLC_SYN) return NULL; switch (c) { case HDLC_SYN: async->mode &= ~MODE_HUNT; if (async->length) { /* packet is ready. */ bp = m_get(async->length, MB_ASYNCIN); mbuf_Write(bp, async->hbuff, async->length); async->length = 0; return bp; } break; case HDLC_ESC: if (!(async->mode & MODE_ESC)) { async->mode |= MODE_ESC; break; } /* FALLTHROUGH */ default: if (async->length >= HDLCSIZE) { /* packet is too large, discard it */ log_Printf(LogWARN, "Packet too large (%d), discarding.\n", async->length); async->length = 0; async->mode = MODE_HUNT; break; } if (async->mode & MODE_ESC) { c ^= HDLC_XOR; async->mode &= ~MODE_ESC; } async->hbuff[async->length++] = c; break; } return NULL; } static struct mbuf * -async_LayerPull(struct bundle *b, struct link *l, struct mbuf *bp, - u_short *proto) +async_LayerPull(struct bundle *b __unused, struct link *l, struct mbuf *bp, + u_short *proto __unused) { struct mbuf *nbp, **last; struct physical *p = link2physical(l); u_char *ch; size_t cnt; if (!p) { log_Printf(LogERROR, "Can't Pull an async packet from a logical link\n"); return bp; } last = &nbp; log_DumpBp(LogASYNC, "Read", bp); while (bp) { ch = MBUF_CTOP(bp); for (cnt = bp->m_len; cnt; cnt--) { *last = async_Decode(&p->async, *ch++); if (*last != NULL) last = &(*last)->m_nextpkt; } bp = m_free(bp); } return nbp; } struct layer asynclayer = { LAYER_ASYNC, "async", async_LayerPush, async_LayerPull }; Index: head/usr.sbin/ppp/atm.c =================================================================== --- head/usr.sbin/ppp/atm.c (revision 134788) +++ head/usr.sbin/ppp/atm.c (revision 134789) @@ -1,237 +1,237 @@ /*- * Copyright (c) 2000 Jakob Stoklund Olesen * 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. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include "layer.h" #include "defs.h" #include "mbuf.h" #include "log.h" #include "timer.h" #include "lqr.h" #include "hdlc.h" #include "throughput.h" #include "fsm.h" #include "lcp.h" #include "ccp.h" #include "link.h" #include "async.h" #include "descriptor.h" #include "physical.h" #include "main.h" #include "atm.h" /* String identifying PPPoA */ #define PPPOA "PPPoA" #define PPPOA_LEN (sizeof(PPPOA) - 1) struct atmdevice { struct device dev; /* What struct physical knows about */ }; #define device2atm(d) ((d)->type == ATM_DEVICE ? (struct atmdevice *)d : NULL) -int +unsigned atm_DeviceSize(void) { return sizeof(struct atmdevice); } static ssize_t atm_Sendto(struct physical *p, const void *v, size_t n) { ssize_t ret = write(p->fd, v, n); if (ret < 0) { log_Printf(LogDEBUG, "atm_Sendto(%ld): %s\n", (long)n, strerror(errno)); return ret; } return ret; } static ssize_t atm_Recvfrom(struct physical *p, void *v, size_t n) { ssize_t ret = read(p->fd, (char*)v, n); if (ret < 0) { log_Printf(LogDEBUG, "atm_Recvfrom(%ld): %s\n", (long)n, strerror(errno)); return ret; } return ret; } static void atm_Free(struct physical *p) { struct atmdevice *dev = device2atm(p->handler); free(dev); } static void atm_device2iov(struct device *d, struct iovec *iov, int *niov, - int maxiov, int *auxfd, int *nauxfd) + int maxiov __unused, int *auxfd __unused, int *nauxfd __unused) { int sz = physical_MaxDeviceSize(); iov[*niov].iov_base = realloc(d, sz); if (iov[*niov].iov_base == NULL) { log_Printf(LogALERT, "Failed to allocate memory: %d\n", sz); AbortProgram(EX_OSERR); } iov[*niov].iov_len = sz; (*niov)++; } static const struct device baseatmdevice = { ATM_DEVICE, "atm", 0, { CD_NOTREQUIRED, 0 }, NULL, NULL, NULL, NULL, NULL, NULL, NULL, atm_Free, atm_Recvfrom, atm_Sendto, atm_device2iov, NULL, NULL, NULL }; struct device * atm_iov2device(int type, struct physical *p, struct iovec *iov, int *niov, - int maxiov, int *auxfd, int *nauxfd) + int maxiov __unused, int *auxfd __unused, int *nauxfd __unused) { if (type == ATM_DEVICE) { struct atmdevice *dev = (struct atmdevice *)iov[(*niov)++].iov_base; dev = realloc(dev, sizeof *dev); /* Reduce to the correct size */ if (dev == NULL) { log_Printf(LogALERT, "Failed to allocate memory: %d\n", (int)(sizeof *dev)); AbortProgram(EX_OSERR); } /* Refresh function pointers etc */ memcpy(&dev->dev, &baseatmdevice, sizeof dev->dev); physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNCNOACF); return &dev->dev; } return NULL; } static struct atmdevice * atm_CreateDevice(struct physical *p, const char *iface, unsigned vpi, unsigned vci) { struct atmdevice *dev; struct sockaddr_natm sock; if ((dev = calloc(1, sizeof *dev)) == NULL) { log_Printf(LogWARN, "%s: Cannot allocate an atm device: %s\n", p->link.name, strerror(errno)); return NULL; } sock.snatm_len = sizeof sock; sock.snatm_family = AF_NATM; strncpy(sock.snatm_if, iface, IFNAMSIZ); sock.snatm_vpi = vpi; sock.snatm_vci = vci; log_Printf(LogPHASE, "%s: Connecting to %s:%u.%u\n", p->link.name, iface, vpi, vci); p->fd = socket(PF_NATM, SOCK_DGRAM, PROTO_NATMAAL5); if (p->fd >= 0) { log_Printf(LogDEBUG, "%s: Opened atm socket %s\n", p->link.name, p->name.full); if (connect(p->fd, (struct sockaddr *)&sock, sizeof sock) == 0) return dev; else log_Printf(LogWARN, "%s: connect: %s\n", p->name.full, strerror(errno)); } else log_Printf(LogWARN, "%s: socket: %s\n", p->name.full, strerror(errno)); close(p->fd); p->fd = -1; free(dev); return NULL; } struct device * atm_Create(struct physical *p) { struct atmdevice *dev; dev = NULL; if (p->fd < 0 && !strncasecmp(p->name.full, PPPOA, PPPOA_LEN) && p->name.full[PPPOA_LEN] == ':') { char iface[25]; unsigned vci, vpi; if (sscanf(p->name.full + PPPOA_LEN + 1, "%25[A-Za-z0-9]:%u.%u", iface, &vpi, &vci) != 3) { log_Printf(LogWARN, "Malformed ATM device name \'%s\', " "PPPoA:if:vpi.vci expected\n", p->name.full); return NULL; } dev = atm_CreateDevice(p, iface, vpi, vci); } if (dev) { memcpy(&dev->dev, &baseatmdevice, sizeof dev->dev); physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNCNOACF); if (p->cfg.cd.necessity != CD_DEFAULT) log_Printf(LogWARN, "Carrier settings ignored\n"); return &dev->dev; } return NULL; } Index: head/usr.sbin/ppp/atm.h =================================================================== --- head/usr.sbin/ppp/atm.h (revision 134788) +++ head/usr.sbin/ppp/atm.h (revision 134789) @@ -1,35 +1,35 @@ /*- * Copyright (c) 2000 Jakob Stoklund Olesen * 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. * * $FreeBSD$ */ struct physical; struct device; extern struct device *atm_Create(struct physical *); extern struct device *atm_iov2device(int, struct physical *, struct iovec *, int *, int, int *, int *); -extern int atm_DeviceSize(void); +extern unsigned atm_DeviceSize(void); Index: head/usr.sbin/ppp/auth.c =================================================================== --- head/usr.sbin/ppp/auth.c (revision 134788) +++ head/usr.sbin/ppp/auth.c (revision 134789) @@ -1,481 +1,479 @@ /*- * Copyright (c) 1996 - 2001 Brian Somers * based on work by Toshiharu OHNO * Internet Initiative Japan, Inc (IIJ) * 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. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #ifndef NOPAM #include #ifdef _OPENPAM #include #endif #endif /* !NOPAM */ #include "layer.h" #include "mbuf.h" #include "defs.h" #include "log.h" #include "timer.h" #include "fsm.h" #include "iplist.h" #include "throughput.h" #include "slcompress.h" #include "lqr.h" #include "hdlc.h" #include "ncpaddr.h" #include "ipcp.h" #include "auth.h" #include "systems.h" #include "lcp.h" #include "ccp.h" #include "link.h" #include "descriptor.h" #include "chat.h" #include "proto.h" #include "filter.h" #include "mp.h" #ifndef NORADIUS #include "radius.h" #endif #include "cbcp.h" #include "chap.h" #include "async.h" #include "physical.h" #include "datalink.h" #include "ipv6cp.h" #include "ncp.h" #include "bundle.h" const char * Auth2Nam(u_short auth, u_char type) { static char chap[10]; switch (auth) { case PROTO_PAP: return "PAP"; case PROTO_CHAP: snprintf(chap, sizeof chap, "CHAP 0x%02x", type); return chap; case 0: return "none"; } return "unknown"; } #if !defined(NOPAM) && !defined(_OPENPAM) static int pam_conv(int n, const struct pam_message **msg, struct pam_response **resp, void *data) { if (n != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF) return (PAM_CONV_ERR); if ((*resp = malloc(sizeof(struct pam_response))) == NULL) return (PAM_CONV_ERR); (*resp)[0].resp = strdup((const char *)data); (*resp)[0].resp_retcode = 0; return ((*resp)[0].resp != NULL ? PAM_SUCCESS : PAM_CONV_ERR); } #endif /* !defined(NOPAM) && !defined(_OPENPAM) */ static int auth_CheckPasswd(const char *name, const char *data, const char *key) { if (!strcmp(data, "*")) { #ifdef NOPAM /* Then look up the real password database */ struct passwd *pw; int result; result = (pw = getpwnam(name)) && !strcmp(crypt(key, pw->pw_passwd), pw->pw_passwd); endpwent(); return result; #else /* !NOPAM */ /* Then consult with PAM. */ pam_handle_t *pamh; int status; struct pam_conv pamc = { #ifdef _OPENPAM &openpam_nullconv, NULL #else &pam_conv, key #endif }; if (pam_start("ppp", name, &pamc, &pamh) != PAM_SUCCESS) return (0); #ifdef _OPENPAM if ((status = pam_set_item(pamh, PAM_AUTHTOK, key)) == PAM_SUCCESS) #endif status = pam_authenticate(pamh, 0); pam_end(pamh, status); return (status == PAM_SUCCESS); #endif /* !NOPAM */ } return !strcmp(data, key); } int auth_SetPhoneList(const char *name, char *phone, int phonelen) { FILE *fp; int n, lineno; char *vector[6], buff[LINE_LEN]; const char *slash; fp = OpenSecret(SECRETFILE); if (fp != NULL) { again: lineno = 0; while (fgets(buff, sizeof buff, fp)) { lineno++; if (buff[0] == '#') continue; buff[strlen(buff) - 1] = '\0'; memset(vector, '\0', sizeof vector); if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0) log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno); if (n < 5) continue; if (strcmp(vector[0], name) == 0) { CloseSecret(fp); if (*vector[4] == '\0') return 0; strncpy(phone, vector[4], phonelen - 1); phone[phonelen - 1] = '\0'; return 1; /* Valid */ } } if ((slash = strrchr(name, '\\')) != NULL && slash[1]) { /* Look for the name without the leading domain */ name = slash + 1; rewind(fp); goto again; } CloseSecret(fp); } *phone = '\0'; return 0; } int auth_Select(struct bundle *bundle, const char *name) { FILE *fp; int n, lineno; char *vector[5], buff[LINE_LEN]; const char *slash; if (*name == '\0') { ipcp_Setup(&bundle->ncp.ipcp, INADDR_NONE); return 1; } #ifndef NORADIUS if (bundle->radius.valid && bundle->radius.ip.s_addr != INADDR_NONE && bundle->radius.ip.s_addr != RADIUS_INADDR_POOL) { /* We've got a radius IP - it overrides everything */ if (!ipcp_UseHisIPaddr(bundle, bundle->radius.ip)) return 0; ipcp_Setup(&bundle->ncp.ipcp, bundle->radius.mask.s_addr); /* Continue with ppp.secret in case we've got a new label */ } #endif fp = OpenSecret(SECRETFILE); if (fp != NULL) { again: lineno = 0; while (fgets(buff, sizeof buff, fp)) { lineno++; if (buff[0] == '#') continue; buff[strlen(buff) - 1] = '\0'; memset(vector, '\0', sizeof vector); if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0) log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno); if (n < 2) continue; if (strcmp(vector[0], name) == 0) { CloseSecret(fp); #ifndef NORADIUS if (!bundle->radius.valid || bundle->radius.ip.s_addr == INADDR_NONE) { #endif if (n > 2 && *vector[2] && strcmp(vector[2], "*") && !ipcp_UseHisaddr(bundle, vector[2], 1)) return 0; ipcp_Setup(&bundle->ncp.ipcp, INADDR_NONE); #ifndef NORADIUS } #endif if (n > 3 && *vector[3] && strcmp(vector[3], "*")) bundle_SetLabel(bundle, vector[3]); return 1; /* Valid */ } } if ((slash = strrchr(name, '\\')) != NULL && slash[1]) { /* Look for the name without the leading domain */ name = slash + 1; rewind(fp); goto again; } CloseSecret(fp); } #ifndef NOPASSWDAUTH /* Let 'em in anyway - they must have been in the passwd file */ ipcp_Setup(&bundle->ncp.ipcp, INADDR_NONE); return 1; #else #ifndef NORADIUS if (bundle->radius.valid) return 1; #endif /* Disappeared from ppp.secret ??? */ return 0; #endif } int -auth_Validate(struct bundle *bundle, const char *name, - const char *key, struct physical *physical) +auth_Validate(struct bundle *bundle, const char *name, const char *key) { /* Used by PAP routines */ FILE *fp; int n, lineno; char *vector[5], buff[LINE_LEN]; const char *slash; fp = OpenSecret(SECRETFILE); again: lineno = 0; if (fp != NULL) { while (fgets(buff, sizeof buff, fp)) { lineno++; if (buff[0] == '#') continue; buff[strlen(buff) - 1] = 0; memset(vector, '\0', sizeof vector); if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0) log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno); if (n < 2) continue; if (strcmp(vector[0], name) == 0) { CloseSecret(fp); return auth_CheckPasswd(name, vector[1], key); } } } if ((slash = strrchr(name, '\\')) != NULL && slash[1]) { /* Look for the name without the leading domain */ name = slash + 1; if (fp != NULL) { rewind(fp); goto again; } } if (fp != NULL) CloseSecret(fp); #ifndef NOPASSWDAUTH if (Enabled(bundle, OPT_PASSWDAUTH)) return auth_CheckPasswd(name, "*", key); #endif return 0; /* Invalid */ } char * -auth_GetSecret(struct bundle *bundle, const char *name, int len, - struct physical *physical) +auth_GetSecret(const char *name, size_t len) { /* Used by CHAP routines */ FILE *fp; int n, lineno; char *vector[5]; const char *slash; static char buff[LINE_LEN]; /* vector[] will point here when returned */ fp = OpenSecret(SECRETFILE); if (fp == NULL) return (NULL); again: lineno = 0; while (fgets(buff, sizeof buff, fp)) { lineno++; if (buff[0] == '#') continue; n = strlen(buff) - 1; if (buff[n] == '\n') buff[n] = '\0'; /* Trim the '\n' */ memset(vector, '\0', sizeof vector); if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0) log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno); if (n < 2) continue; if (strlen(vector[0]) == len && strncmp(vector[0], name, len) == 0) { CloseSecret(fp); return vector[1]; } } if ((slash = strrchr(name, '\\')) != NULL && slash[1]) { /* Go back and look for the name without the leading domain */ len -= slash - name + 1; name = slash + 1; rewind(fp); goto again; } CloseSecret(fp); return (NULL); /* Invalid */ } static void AuthTimeout(void *vauthp) { struct authinfo *authp = (struct authinfo *)vauthp; timer_Stop(&authp->authtimer); if (--authp->retry > 0) { authp->id++; (*authp->fn.req)(authp); timer_Start(&authp->authtimer); } else { log_Printf(LogPHASE, "Auth: No response from server\n"); datalink_AuthNotOk(authp->physical->dl); } } void auth_Init(struct authinfo *authp, struct physical *p, auth_func req, auth_func success, auth_func failure) { memset(authp, '\0', sizeof(struct authinfo)); authp->cfg.fsm.timeout = DEF_FSMRETRY; authp->cfg.fsm.maxreq = DEF_FSMAUTHTRIES; authp->cfg.fsm.maxtrm = 0; /* not used */ authp->fn.req = req; authp->fn.success = success; authp->fn.failure = failure; authp->physical = p; } void auth_StartReq(struct authinfo *authp) { timer_Stop(&authp->authtimer); authp->authtimer.func = AuthTimeout; authp->authtimer.name = "auth"; authp->authtimer.load = authp->cfg.fsm.timeout * SECTICKS; authp->authtimer.arg = (void *)authp; authp->retry = authp->cfg.fsm.maxreq; authp->id = 1; (*authp->fn.req)(authp); timer_Start(&authp->authtimer); } void auth_StopTimer(struct authinfo *authp) { timer_Stop(&authp->authtimer); } struct mbuf * auth_ReadHeader(struct authinfo *authp, struct mbuf *bp) { - int len; + size_t len; len = m_length(bp); if (len >= sizeof authp->in.hdr) { bp = mbuf_Read(bp, (u_char *)&authp->in.hdr, sizeof authp->in.hdr); if (len >= ntohs(authp->in.hdr.length)) return bp; authp->in.hdr.length = htons(0); - log_Printf(LogWARN, "auth_ReadHeader: Short packet (%d > %d) !\n", + log_Printf(LogWARN, "auth_ReadHeader: Short packet (%u > %u) !\n", ntohs(authp->in.hdr.length), len); } else { authp->in.hdr.length = htons(0); - log_Printf(LogWARN, "auth_ReadHeader: Short packet header (%d > %d) !\n", + log_Printf(LogWARN, "auth_ReadHeader: Short packet header (%u > %u) !\n", (int)(sizeof authp->in.hdr), len); } m_freem(bp); return NULL; } struct mbuf * -auth_ReadName(struct authinfo *authp, struct mbuf *bp, int len) +auth_ReadName(struct authinfo *authp, struct mbuf *bp, size_t len) { if (len > sizeof authp->in.name - 1) - log_Printf(LogWARN, "auth_ReadName: Name too long (%d) !\n", len); + log_Printf(LogWARN, "auth_ReadName: Name too long (%u) !\n", len); else { - int mlen = m_length(bp); + size_t mlen = m_length(bp); if (len > mlen) - log_Printf(LogWARN, "auth_ReadName: Short packet (%d > %d) !\n", + log_Printf(LogWARN, "auth_ReadName: Short packet (%u > %u) !\n", len, mlen); else { bp = mbuf_Read(bp, (u_char *)authp->in.name, len); authp->in.name[len] = '\0'; return bp; } } *authp->in.name = '\0'; m_freem(bp); return NULL; } Index: head/usr.sbin/ppp/auth.h =================================================================== --- head/usr.sbin/ppp/auth.h (revision 134788) +++ head/usr.sbin/ppp/auth.h (revision 134789) @@ -1,70 +1,68 @@ /*- * Copyright (c) 1996 - 2001 Brian Somers * based on work by Toshiharu OHNO * Internet Initiative Japan, Inc (IIJ) * 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. * * $FreeBSD$ */ struct physical; struct bundle; struct authinfo; typedef void (*auth_func)(struct authinfo *); struct authinfo { struct { auth_func req; auth_func success; auth_func failure; } fn; struct { struct fsmheader hdr; char name[AUTHLEN]; } in; struct pppTimer authtimer; int retry; int id; struct physical *physical; struct { struct fsm_retry fsm; /* How often/frequently to resend requests */ } cfg; }; #define auth_Failure(a) (*(a)->fn.failure)(a) #define auth_Success(a) (*(a)->fn.success)(a) extern const char *Auth2Nam(u_short, u_char); extern void auth_Init(struct authinfo *, struct physical *, auth_func, auth_func, auth_func); extern void auth_StopTimer(struct authinfo *); extern void auth_StartReq(struct authinfo *); -extern int auth_Validate(struct bundle *, const char *, const char *, - struct physical *); -extern char *auth_GetSecret(struct bundle *, const char *, int, - struct physical *); +extern int auth_Validate(struct bundle *, const char *, const char *); +extern char *auth_GetSecret(const char *, size_t); extern int auth_SetPhoneList(const char *, char *, int); extern int auth_Select(struct bundle *, const char *); extern struct mbuf *auth_ReadHeader(struct authinfo *, struct mbuf *); -extern struct mbuf *auth_ReadName(struct authinfo *, struct mbuf *, int); +extern struct mbuf *auth_ReadName(struct authinfo *, struct mbuf *, size_t); Index: head/usr.sbin/ppp/bundle.c =================================================================== --- head/usr.sbin/ppp/bundle.c (revision 134788) +++ head/usr.sbin/ppp/bundle.c (revision 134789) @@ -1,2009 +1,2012 @@ /*- * 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. * * $FreeBSD$ */ #include #include #include #include #include /* For TUNS* ioctls */ #include #include #include #include #include #include #ifdef __OpenBSD__ #include #else #include #endif #include #include #include #include #include #include #include #include #include #include "layer.h" #include "defs.h" #include "command.h" #include "mbuf.h" #include "log.h" #include "id.h" #include "timer.h" #include "fsm.h" #include "iplist.h" #include "lqr.h" #include "hdlc.h" #include "throughput.h" #include "slcompress.h" #include "ncpaddr.h" #include "ip.h" #include "ipcp.h" #include "filter.h" #include "descriptor.h" #include "route.h" #include "lcp.h" #include "ccp.h" #include "link.h" #include "mp.h" #ifndef NORADIUS #include "radius.h" #endif #include "ipv6cp.h" #include "ncp.h" #include "bundle.h" #include "async.h" #include "physical.h" #include "auth.h" #include "proto.h" #include "chap.h" #include "tun.h" #include "prompt.h" #include "chat.h" #include "cbcp.h" #include "datalink.h" #include "iface.h" #include "server.h" #include "probe.h" #ifndef NODES #include "mppe.h" #endif #define SCATTER_SEGMENTS 7 /* version, datalink, name, physical, throughput, throughput, device */ #define SEND_MAXFD 3 /* Max file descriptors passed through the local domain socket */ static int bundle_RemainingIdleTime(struct bundle *); static const char * const 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, u_int new) { if (new == bundle->phase) return; if (new <= PHASE_TERMINATE) log_Printf(LogPHASE, "bundle: %s\n", PhaseNames[new]); switch (new) { case PHASE_DEAD: bundle->phase = new; #ifndef NODES MPPE_MasterKeyValid = 0; #endif log_DisplayPrompts(); break; case PHASE_ESTABLISH: bundle->phase = new; break; case PHASE_AUTHENTICATE: bundle->phase = new; log_DisplayPrompts(); break; case PHASE_NETWORK: if (ncp_fsmStart(&bundle->ncp, bundle)) { bundle->phase = new; log_DisplayPrompts(); } else { log_Printf(LogPHASE, "bundle: All NCPs are disabled\n"); bundle_Close(bundle, NULL, CLOSE_STAYDOWN); } break; case PHASE_TERMINATE: bundle->phase = new; mp_Down(&bundle->ncp.mp); log_DisplayPrompts(); break; } } static void -bundle_LayerStart(void *v, struct fsm *fp) +bundle_LayerStart(void *v __unused, struct fsm *fp __unused) { /* The given FSM is about to start up ! */ } void bundle_Notify(struct bundle *bundle, char c) { if (bundle->notify.fd != -1) { int ret; ret = write(bundle->notify.fd, &c, 1); if (c != EX_REDIAL && c != EX_RECONNECT) { if (ret == 1) log_Printf(LogCHAT, "Parent notified of %s\n", c == EX_NORMAL ? "success" : "failure"); else log_Printf(LogERROR, "Failed to notify parent of success\n"); close(bundle->notify.fd); bundle->notify.fd = -1; } else if (ret == 1) log_Printf(LogCHAT, "Parent notified of %s\n", ex_desc(c)); else log_Printf(LogERROR, "Failed to notify parent of %s\n", ex_desc(c)); } } static void bundle_ClearQueues(void *v) { struct bundle *bundle = (struct bundle *)v; struct datalink *dl; log_Printf(LogPHASE, "Clearing choked output queue\n"); timer_Stop(&bundle->choked.timer); /* * Emergency time: * * We've had a full queue for PACKET_DEL_SECS seconds without being * able to get rid of any of the packets. We've probably given up * on the redials at this point, and the queued data has almost * definitely been timed out by the layer above. As this is preventing * us from reading the TUN_NAME device (we don't want to buffer stuff * indefinitely), we may as well nuke this data and start with a clean * slate ! * * Unfortunately, this has the side effect of shafting any compression * dictionaries in use (causing the relevant RESET_REQ/RESET_ACK). */ ncp_DeleteQueues(&bundle->ncp); for (dl = bundle->links; dl; dl = dl->next) physical_DeleteQueue(dl->physical); } static void bundle_LinkAdded(struct bundle *bundle, struct datalink *dl) { bundle->phys_type.all |= dl->physical->type; if (dl->state == DATALINK_OPEN) bundle->phys_type.open |= dl->physical->type; #ifndef NORADIUS if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) != bundle->phys_type.open && bundle->session.timer.state == TIMER_STOPPED) if (bundle->radius.sessiontime) bundle_StartSessionTimer(bundle, 0); #endif if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) != bundle->phys_type.open && bundle->idle.timer.state == TIMER_STOPPED) /* We may need to start our idle timer */ bundle_StartIdleTimer(bundle, 0); } void bundle_LinksRemoved(struct bundle *bundle) { struct datalink *dl; bundle->phys_type.all = bundle->phys_type.open = 0; for (dl = bundle->links; dl; dl = dl->next) bundle_LinkAdded(bundle, dl); bundle_CalculateBandwidth(bundle); mp_CheckAutoloadTimer(&bundle->ncp.mp); if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) == bundle->phys_type.open) { #ifndef NORADIUS if (bundle->radius.sessiontime) bundle_StopSessionTimer(bundle); #endif bundle_StopIdleTimer(bundle); } } static void bundle_LayerUp(void *v, struct fsm *fp) { /* * The given fsm is now up * If it's an LCP, adjust our phys_mode.open value and check the * autoload timer. * If it's the first NCP, calculate our bandwidth * If it's the first NCP, set our ``upat'' time * If it's the first NCP, start the idle timer. * If it's an NCP, tell our -background parent to go away. * If it's the first NCP, start the autoload timer */ struct bundle *bundle = (struct bundle *)v; if (fp->proto == PROTO_LCP) { struct physical *p = link2physical(fp->link); bundle_LinkAdded(bundle, p->dl); mp_CheckAutoloadTimer(&bundle->ncp.mp); } else if (isncp(fp->proto)) { if (ncp_LayersOpen(&fp->bundle->ncp) == 1) { bundle_CalculateBandwidth(fp->bundle); time(&bundle->upat); #ifndef NORADIUS if (bundle->radius.sessiontime) bundle_StartSessionTimer(bundle, 0); #endif bundle_StartIdleTimer(bundle, 0); mp_CheckAutoloadTimer(&fp->bundle->ncp.mp); } bundle_Notify(bundle, EX_NORMAL); } else if (fp->proto == PROTO_CCP) bundle_CalculateBandwidth(fp->bundle); /* Against ccp_MTUOverhead */ } static void bundle_LayerDown(void *v, struct fsm *fp) { /* * The given FSM has been told to come down. * If it's our last NCP, stop the idle timer. * If it's our last NCP, clear our ``upat'' value. * If it's our last NCP, stop the autoload timer * If it's an LCP, adjust our phys_type.open value and any timers. * If it's an LCP and we're in multilink mode, adjust our tun * If it's the last LCP, down all NCPs * speed and make sure our minimum sequence number is adjusted. */ struct bundle *bundle = (struct bundle *)v; if (isncp(fp->proto)) { if (ncp_LayersOpen(&fp->bundle->ncp) == 0) { #ifndef NORADIUS if (bundle->radius.sessiontime) bundle_StopSessionTimer(bundle); #endif bundle_StopIdleTimer(bundle); bundle->upat = 0; mp_StopAutoloadTimer(&bundle->ncp.mp); } } else if (fp->proto == PROTO_LCP) { struct datalink *dl; struct datalink *lost; int others_active; bundle_LinksRemoved(bundle); /* adjust timers & phys_type values */ lost = NULL; others_active = 0; for (dl = bundle->links; dl; dl = dl->next) { if (fp == &dl->physical->link.lcp.fsm) lost = dl; else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) others_active++; } if (bundle->ncp.mp.active) { bundle_CalculateBandwidth(bundle); if (lost) mp_LinkLost(&bundle->ncp.mp, lost); else log_Printf(LogALERT, "Oops, lost an unrecognised datalink (%s) !\n", fp->link->name); } if (!others_active) { /* Down the NCPs. We don't expect to get fsm_Close()d ourself ! */ ncp2initial(&bundle->ncp); mp_Down(&bundle->ncp.mp); } } } static void bundle_LayerFinish(void *v, struct fsm *fp) { /* The given fsm is now down (fp cannot be NULL) * * If it's the last NCP, fsm_Close all LCPs * If it's the last NCP, bring any MP layer down */ struct bundle *bundle = (struct bundle *)v; struct datalink *dl; if (isncp(fp->proto) && !ncp_LayersUnfinished(&bundle->ncp)) { if (bundle_Phase(bundle) != PHASE_DEAD) bundle_NewPhase(bundle, PHASE_TERMINATE); for (dl = bundle->links; dl; dl = dl->next) if (dl->state == DATALINK_OPEN) datalink_Close(dl, CLOSE_STAYDOWN); fsm2initial(fp); mp_Down(&bundle->ncp.mp); } } void bundle_Close(struct bundle *bundle, const char *name, int how) { /* * Please close the given datalink. * If name == NULL or name is the last datalink, fsm_Close all NCPs * (except our MP) * If it isn't the last datalink, just Close that datalink. */ struct datalink *dl, *this_dl; int others_active; others_active = 0; this_dl = NULL; for (dl = bundle->links; dl; dl = dl->next) { if (name && !strcasecmp(name, dl->name)) this_dl = dl; if (name == NULL || this_dl == dl) { switch (how) { case CLOSE_LCP: datalink_DontHangup(dl); break; case CLOSE_STAYDOWN: datalink_StayDown(dl); break; } } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) others_active++; } if (name && this_dl == NULL) { log_Printf(LogWARN, "%s: Invalid datalink name\n", name); return; } if (!others_active) { #ifndef NORADIUS if (bundle->radius.sessiontime) bundle_StopSessionTimer(bundle); #endif bundle_StopIdleTimer(bundle); if (ncp_LayersUnfinished(&bundle->ncp)) ncp_Close(&bundle->ncp); else { ncp2initial(&bundle->ncp); mp_Down(&bundle->ncp.mp); for (dl = bundle->links; dl; dl = dl->next) datalink_Close(dl, how); } } else if (this_dl && this_dl->state != DATALINK_CLOSED && this_dl->state != DATALINK_HANGUP) datalink_Close(this_dl, how); } void bundle_Down(struct bundle *bundle, int how) { struct datalink *dl; for (dl = bundle->links; dl; dl = dl->next) datalink_Down(dl, how); } static int bundle_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) { struct bundle *bundle = descriptor2bundle(d); struct datalink *dl; int result, nlinks; u_short ifqueue; size_t queued; result = 0; /* If there are aren't many packets queued, look for some more. */ for (nlinks = 0, dl = bundle->links; dl; dl = dl->next) nlinks++; if (nlinks) { queued = r ? ncp_FillPhysicalQueues(&bundle->ncp, bundle) : ncp_QueueLen(&bundle->ncp); if (r && (bundle->phase == PHASE_NETWORK || bundle->phys_type.all & PHYS_AUTO)) { /* enough surplus so that we can tell if we're getting swamped */ ifqueue = nlinks > bundle->cfg.ifqueue ? nlinks : bundle->cfg.ifqueue; if (queued < ifqueue) { /* Not enough - select() for more */ if (bundle->choked.timer.state == TIMER_RUNNING) timer_Stop(&bundle->choked.timer); /* Not needed any more */ FD_SET(bundle->dev.fd, r); if (*n < bundle->dev.fd + 1) *n = bundle->dev.fd + 1; log_Printf(LogTIMER, "%s: fdset(r) %d\n", TUN_NAME, bundle->dev.fd); result++; } else if (bundle->choked.timer.state == TIMER_STOPPED) { bundle->choked.timer.func = bundle_ClearQueues; bundle->choked.timer.name = "output choke"; bundle->choked.timer.load = bundle->cfg.choked.timeout * SECTICKS; bundle->choked.timer.arg = bundle; timer_Start(&bundle->choked.timer); } } } #ifndef NORADIUS result += descriptor_UpdateSet(&bundle->radius.desc, r, w, e, n); #endif /* Which links need a select() ? */ for (dl = bundle->links; dl; dl = dl->next) result += descriptor_UpdateSet(&dl->desc, r, w, e, n); /* * This *MUST* be called after the datalink UpdateSet()s as it * might be ``holding'' one of the datalinks (death-row) and * wants to be able to de-select() it from the descriptor set. */ result += descriptor_UpdateSet(&bundle->ncp.mp.server.desc, r, w, e, n); return result; } static int bundle_IsSet(struct fdescriptor *d, const fd_set *fdset) { struct bundle *bundle = descriptor2bundle(d); struct datalink *dl; for (dl = bundle->links; dl; dl = dl->next) if (descriptor_IsSet(&dl->desc, fdset)) return 1; #ifndef NORADIUS if (descriptor_IsSet(&bundle->radius.desc, fdset)) return 1; #endif if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) return 1; return FD_ISSET(bundle->dev.fd, fdset); } static void -bundle_DescriptorRead(struct fdescriptor *d, struct bundle *bundle, +bundle_DescriptorRead(struct fdescriptor *d __unused, struct bundle *bundle, const fd_set *fdset) { struct datalink *dl; unsigned secs; u_int32_t af; if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) descriptor_Read(&bundle->ncp.mp.server.desc, bundle, fdset); for (dl = bundle->links; dl; dl = dl->next) if (descriptor_IsSet(&dl->desc, fdset)) descriptor_Read(&dl->desc, bundle, fdset); #ifndef NORADIUS if (descriptor_IsSet(&bundle->radius.desc, fdset)) descriptor_Read(&bundle->radius.desc, bundle, fdset); #endif if (FD_ISSET(bundle->dev.fd, fdset)) { struct tun_data tun; int n, pri; u_char *data; size_t sz; if (bundle->dev.header) { data = (u_char *)&tun; sz = sizeof tun; } else { data = tun.data; sz = sizeof tun.data; } /* something to read from tun */ n = read(bundle->dev.fd, data, sz); if (n < 0) { log_Printf(LogWARN, "%s: read: %s\n", bundle->dev.Name, strerror(errno)); return; } if (bundle->dev.header) { n -= sz - sizeof tun.data; if (n <= 0) { log_Printf(LogERROR, "%s: read: Got only %d bytes of data !\n", bundle->dev.Name, n); return; } af = ntohl(tun.header.family); #ifndef NOINET6 if (af != AF_INET && af != AF_INET6) #else if (af != AF_INET) #endif /* XXX: Should be maintaining drop/family counts ! */ return; } else af = AF_INET; if (af == AF_INET && ((struct ip *)tun.data)->ip_dst.s_addr == bundle->ncp.ipcp.my_ip.s_addr) { /* we've been asked to send something addressed *to* us :( */ if (Enabled(bundle, OPT_LOOPBACK)) { pri = PacketCheck(bundle, af, tun.data, n, &bundle->filter.in, NULL, NULL); if (pri >= 0) { n += sz - sizeof tun.data; write(bundle->dev.fd, data, n); log_Printf(LogDEBUG, "Looped back packet addressed to myself\n"); } return; } else log_Printf(LogDEBUG, "Oops - forwarding packet addressed to myself\n"); } /* * Process on-demand dialup. Output packets are queued within the tunnel * device until the appropriate NCP is opened. */ if (bundle_Phase(bundle) == PHASE_DEAD) { /* * Note, we must be in AUTO mode :-/ otherwise our interface should * *not* be UP and we can't receive data */ pri = PacketCheck(bundle, af, tun.data, n, &bundle->filter.dial, NULL, NULL); if (pri >= 0) bundle_Open(bundle, NULL, PHYS_AUTO, 0); else /* * Drop the packet. If we were to queue it, we'd just end up with * a pile of timed-out data in our output queue by the time we get * around to actually dialing. We'd also prematurely reach the * threshold at which we stop select()ing to read() the tun * device - breaking auto-dial. */ return; } secs = 0; pri = PacketCheck(bundle, af, tun.data, n, &bundle->filter.out, NULL, &secs); if (pri >= 0) { /* Prepend the number of seconds timeout given in the filter */ tun.header.timeout = secs; ncp_Enqueue(&bundle->ncp, af, pri, (char *)&tun, n + sizeof tun.header); } } } static int -bundle_DescriptorWrite(struct fdescriptor *d, struct bundle *bundle, +bundle_DescriptorWrite(struct fdescriptor *d __unused, struct bundle *bundle, const fd_set *fdset) { struct datalink *dl; int result = 0; /* This is not actually necessary as struct mpserver doesn't Write() */ if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) if (descriptor_Write(&bundle->ncp.mp.server.desc, bundle, fdset) == 1) result++; for (dl = bundle->links; dl; dl = dl->next) if (descriptor_IsSet(&dl->desc, fdset)) switch (descriptor_Write(&dl->desc, bundle, fdset)) { case -1: datalink_ComeDown(dl, CLOSE_NORMAL); break; case 1: result++; } return result; } void bundle_LockTun(struct bundle *bundle) { FILE *lockfile; char pidfile[PATH_MAX]; snprintf(pidfile, sizeof pidfile, "%stun%d.pid", _PATH_VARRUN, bundle->unit); lockfile = ID0fopen(pidfile, "w"); if (lockfile != NULL) { fprintf(lockfile, "%d\n", (int)getpid()); fclose(lockfile); } #ifndef RELEASE_CRUNCH else log_Printf(LogERROR, "Warning: Can't create %s: %s\n", pidfile, strerror(errno)); #endif } static void bundle_UnlockTun(struct bundle *bundle) { char pidfile[PATH_MAX]; snprintf(pidfile, sizeof pidfile, "%stun%d.pid", _PATH_VARRUN, bundle->unit); ID0unlink(pidfile); } struct bundle * bundle_Create(const char *prefix, int type, int unit) { static struct bundle bundle; /* there can be only one */ int enoentcount, err, minunit, maxunit; const char *ifname; #if defined(__FreeBSD__) && !defined(NOKLDLOAD) int kldtried; #endif #if defined(TUNSIFMODE) || defined(TUNSLMODE) || defined(TUNSIFHEAD) int iff; #endif if (bundle.iface != NULL) { /* Already allocated ! */ log_Printf(LogALERT, "bundle_Create: There's only one BUNDLE !\n"); return NULL; } if (unit == -1) { minunit = 0; maxunit = -1; } else { minunit = unit; maxunit = unit + 1; } err = ENOENT; enoentcount = 0; #if defined(__FreeBSD__) && !defined(NOKLDLOAD) kldtried = 0; #endif for (bundle.unit = minunit; bundle.unit != maxunit; bundle.unit++) { snprintf(bundle.dev.Name, sizeof bundle.dev.Name, "%s%d", prefix, bundle.unit); bundle.dev.fd = ID0open(bundle.dev.Name, O_RDWR); if (bundle.dev.fd >= 0) break; else if (errno == ENXIO || errno == ENOENT) { #if defined(__FreeBSD__) && !defined(NOKLDLOAD) if (bundle.unit == minunit && !kldtried++) { /* * Attempt to load the tunnel interface KLD if it isn't loaded * already. */ if (loadmodules(LOAD_VERBOSLY, "if_tun", NULL)) bundle.unit--; continue; } #endif if (errno != ENOENT || ++enoentcount > 2) { err = errno; break; } } else err = errno; } if (bundle.dev.fd < 0) { if (unit == -1) log_Printf(LogWARN, "No available tunnel devices found (%s)\n", strerror(err)); else log_Printf(LogWARN, "%s%d: %s\n", prefix, unit, strerror(err)); return NULL; } log_SetTun(bundle.unit); ifname = strrchr(bundle.dev.Name, '/'); if (ifname == NULL) ifname = bundle.dev.Name; else ifname++; bundle.iface = iface_Create(ifname); if (bundle.iface == NULL) { close(bundle.dev.fd); return NULL; } #ifdef TUNSIFMODE /* Make sure we're POINTOPOINT & IFF_MULTICAST */ iff = IFF_POINTOPOINT | IFF_MULTICAST; if (ID0ioctl(bundle.dev.fd, TUNSIFMODE, &iff) < 0) log_Printf(LogERROR, "bundle_Create: ioctl(TUNSIFMODE): %s\n", strerror(errno)); #endif #ifdef TUNSLMODE /* Make sure we're not prepending sockaddrs */ iff = 0; if (ID0ioctl(bundle.dev.fd, TUNSLMODE, &iff) < 0) log_Printf(LogERROR, "bundle_Create: ioctl(TUNSLMODE): %s\n", strerror(errno)); #endif #ifdef TUNSIFHEAD /* We want the address family please ! */ iff = 1; if (ID0ioctl(bundle.dev.fd, TUNSIFHEAD, &iff) < 0) { log_Printf(LogERROR, "bundle_Create: ioctl(TUNSIFHEAD): %s\n", strerror(errno)); bundle.dev.header = 0; } else bundle.dev.header = 1; #else #ifdef __OpenBSD__ /* Always present for OpenBSD */ bundle.dev.header = 1; #else /* * If TUNSIFHEAD isn't available and we're not OpenBSD, assume * everything's AF_INET (hopefully the tun device won't pass us * anything else !). */ bundle.dev.header = 0; #endif #endif log_Printf(LogPHASE, "Using interface: %s\n", ifname); bundle.bandwidth = 0; bundle.routing_seq = 0; bundle.phase = PHASE_DEAD; bundle.CleaningUp = 0; bundle.NatEnabled = 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.cfg.idle.timeout = NCP_IDLE_TIMEOUT; bundle.cfg.idle.min_timeout = 0; *bundle.cfg.auth.name = '\0'; *bundle.cfg.auth.key = '\0'; bundle.cfg.opt = OPT_IDCHECK | OPT_LOOPBACK | OPT_SROUTES | OPT_TCPMSSFIXUP | OPT_THROUGHPUT | OPT_UTMP; #ifndef NOINET6 bundle.cfg.opt |= OPT_IPCP; if (probe.ipv6_available) bundle.cfg.opt |= OPT_IPV6CP; #endif *bundle.cfg.label = '\0'; bundle.cfg.ifqueue = DEF_IFQUEUE; bundle.cfg.choked.timeout = CHOKED_TIMEOUT; bundle.phys_type.all = type; bundle.phys_type.open = 0; bundle.upat = 0; bundle.links = datalink_Create("deflink", &bundle, type); if (bundle.links == NULL) { log_Printf(LogALERT, "Cannot create data link: %s\n", strerror(errno)); iface_Destroy(bundle.iface); bundle.iface = NULL; close(bundle.dev.fd); return NULL; } bundle.desc.type = BUNDLE_DESCRIPTOR; bundle.desc.UpdateSet = bundle_UpdateSet; bundle.desc.IsSet = bundle_IsSet; bundle.desc.Read = bundle_DescriptorRead; bundle.desc.Write = bundle_DescriptorWrite; ncp_Init(&bundle.ncp, &bundle); memset(&bundle.filter, '\0', sizeof bundle.filter); bundle.filter.in.fragok = bundle.filter.in.logok = 1; bundle.filter.in.name = "IN"; bundle.filter.out.fragok = bundle.filter.out.logok = 1; bundle.filter.out.name = "OUT"; bundle.filter.dial.name = "DIAL"; bundle.filter.dial.logok = 1; bundle.filter.alive.name = "ALIVE"; bundle.filter.alive.logok = 1; { int i; for (i = 0; i < MAXFILTERS; i++) { bundle.filter.in.rule[i].f_action = A_NONE; bundle.filter.out.rule[i].f_action = A_NONE; bundle.filter.dial.rule[i].f_action = A_NONE; bundle.filter.alive.rule[i].f_action = A_NONE; } } memset(&bundle.idle.timer, '\0', sizeof bundle.idle.timer); bundle.idle.done = 0; bundle.notify.fd = -1; memset(&bundle.choked.timer, '\0', sizeof bundle.choked.timer); #ifndef NORADIUS radius_Init(&bundle.radius); #endif /* Clean out any leftover crud */ iface_Clear(bundle.iface, &bundle.ncp, 0, IFACE_CLEAR_ALL); bundle_LockTun(&bundle); return &bundle; } static void bundle_DownInterface(struct bundle *bundle) { route_IfDelete(bundle, 1); iface_ClearFlags(bundle->iface->name, IFF_UP); } void bundle_Destroy(struct bundle *bundle) { struct datalink *dl; /* * Clean up the interface. We don't really need to do the timer_Stop()s, * mp_Down(), iface_Clear() and bundle_DownInterface() unless we're getting * out under exceptional conditions such as a descriptor exception. */ timer_Stop(&bundle->idle.timer); timer_Stop(&bundle->choked.timer); mp_Down(&bundle->ncp.mp); iface_Clear(bundle->iface, &bundle->ncp, 0, IFACE_CLEAR_ALL); bundle_DownInterface(bundle); #ifndef NORADIUS /* Tell the radius server the bad news */ radius_Destroy(&bundle->radius); #endif /* Again, these are all DATALINK_CLOSED unless we're abending */ dl = bundle->links; while (dl) dl = datalink_Destroy(dl); ncp_Destroy(&bundle->ncp); close(bundle->dev.fd); bundle_UnlockTun(bundle); /* In case we never made PHASE_NETWORK */ bundle_Notify(bundle, EX_ERRDEAD); iface_Destroy(bundle->iface); bundle->iface = NULL; } void bundle_LinkClosed(struct bundle *bundle, struct datalink *dl) { /* * Our datalink has closed. * CleanDatalinks() (called from DoLoop()) will remove closed * BACKGROUND, FOREGROUND and DIRECT links. * If it's the last data link, enter phase DEAD. * * NOTE: dl may not be in our list (bundle_SendDatalink()) ! */ struct datalink *odl; int other_links; log_SetTtyCommandMode(dl); other_links = 0; for (odl = bundle->links; odl; odl = odl->next) if (odl != dl && odl->state != DATALINK_CLOSED) other_links++; if (!other_links) { if (dl->physical->type != PHYS_AUTO) /* Not in -auto mode */ bundle_DownInterface(bundle); ncp2initial(&bundle->ncp); mp_Down(&bundle->ncp.mp); bundle_NewPhase(bundle, PHASE_DEAD); #ifndef NORADIUS if (bundle->radius.sessiontime) bundle_StopSessionTimer(bundle); #endif bundle_StopIdleTimer(bundle); } } void bundle_Open(struct bundle *bundle, const char *name, int mask, int force) { /* * Please open the given datalink, or all if name == NULL */ struct datalink *dl; for (dl = bundle->links; dl; dl = dl->next) if (name == NULL || !strcasecmp(dl->name, name)) { if ((mask & dl->physical->type) && (dl->state == DATALINK_CLOSED || (force && dl->state == DATALINK_OPENING && dl->dial.timer.state == TIMER_RUNNING) || dl->state == DATALINK_READY)) { timer_Stop(&dl->dial.timer); /* We're finished with this */ datalink_Up(dl, 1, 1); if (mask & PHYS_AUTO) break; /* Only one AUTO link at a time */ } if (name != NULL) break; } } 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; } int bundle_ShowLinks(struct cmdargs const *arg) { struct datalink *dl; struct pppThroughput *t; unsigned long long octets; int secs; for (dl = arg->bundle->links; dl; dl = dl->next) { octets = MAX(dl->physical->link.stats.total.in.OctetsPerSecond, dl->physical->link.stats.total.out.OctetsPerSecond); prompt_Printf(arg->prompt, "Name: %s [%s, %s]", dl->name, mode2Nam(dl->physical->type), datalink_State(dl)); if (dl->physical->link.stats.total.rolling && dl->state == DATALINK_OPEN) prompt_Printf(arg->prompt, " bandwidth %d, %llu bps (%llu bytes/sec)", dl->mp.bandwidth ? dl->mp.bandwidth : physical_GetSpeed(dl->physical), octets * 8, octets); prompt_Printf(arg->prompt, "\n"); } t = &arg->bundle->ncp.mp.link.stats.total; octets = MAX(t->in.OctetsPerSecond, t->out.OctetsPerSecond); secs = t->downtime ? 0 : throughput_uptime(t); if (secs > t->SamplePeriod) secs = t->SamplePeriod; if (secs) prompt_Printf(arg->prompt, "Currently averaging %llu bps (%llu bytes/sec)" " over the last %d secs\n", octets * 8, octets, secs); return 0; } static const char * optval(struct bundle *bundle, int bit) { return (bundle->cfg.opt & bit) ? "enabled" : "disabled"; } int bundle_ShowStatus(struct cmdargs const *arg) { int remaining; prompt_Printf(arg->prompt, "Phase %s\n", bundle_PhaseName(arg->bundle)); prompt_Printf(arg->prompt, " Device: %s\n", arg->bundle->dev.Name); prompt_Printf(arg->prompt, " Interface: %s @ %lubps", arg->bundle->iface->name, arg->bundle->bandwidth); if (arg->bundle->upat) { int secs = bundle_Uptime(arg->bundle); prompt_Printf(arg->prompt, ", up time %d:%02d:%02d", secs / 3600, (secs / 60) % 60, secs % 60); } prompt_Printf(arg->prompt, "\n Queued: %lu of %u\n", (unsigned long)ncp_QueueLen(&arg->bundle->ncp), arg->bundle->cfg.ifqueue); prompt_Printf(arg->prompt, "\nDefaults:\n"); prompt_Printf(arg->prompt, " Label: %s\n", arg->bundle->cfg.label); prompt_Printf(arg->prompt, " Auth name: %s\n", arg->bundle->cfg.auth.name); prompt_Printf(arg->prompt, " Diagnostic socket: "); if (*server.cfg.sockname != '\0') { prompt_Printf(arg->prompt, "%s", server.cfg.sockname); if (server.cfg.mask != (mode_t)-1) prompt_Printf(arg->prompt, ", mask 0%03o", (int)server.cfg.mask); prompt_Printf(arg->prompt, "%s\n", server.fd == -1 ? " (not open)" : ""); } else if (server.cfg.port != 0) prompt_Printf(arg->prompt, "TCP port %d%s\n", server.cfg.port, server.fd == -1 ? " (not open)" : ""); else prompt_Printf(arg->prompt, "none\n"); - prompt_Printf(arg->prompt, " Choked Timer: %ds\n", + prompt_Printf(arg->prompt, " Choked Timer: %us\n", arg->bundle->cfg.choked.timeout); #ifndef NORADIUS radius_Show(&arg->bundle->radius, arg->prompt); #endif prompt_Printf(arg->prompt, " Idle Timer: "); if (arg->bundle->cfg.idle.timeout) { - prompt_Printf(arg->prompt, "%ds", arg->bundle->cfg.idle.timeout); + prompt_Printf(arg->prompt, "%us", arg->bundle->cfg.idle.timeout); if (arg->bundle->cfg.idle.min_timeout) - prompt_Printf(arg->prompt, ", min %ds", + prompt_Printf(arg->prompt, ", min %us", arg->bundle->cfg.idle.min_timeout); remaining = bundle_RemainingIdleTime(arg->bundle); if (remaining != -1) prompt_Printf(arg->prompt, " (%ds remaining)", remaining); prompt_Printf(arg->prompt, "\n"); } else prompt_Printf(arg->prompt, "disabled\n"); prompt_Printf(arg->prompt, " Filter Decap: %-20.20s", optval(arg->bundle, OPT_FILTERDECAP)); prompt_Printf(arg->prompt, " ID check: %s\n", optval(arg->bundle, OPT_IDCHECK)); prompt_Printf(arg->prompt, " Iface-Alias: %-20.20s", optval(arg->bundle, OPT_IFACEALIAS)); #ifndef NOINET6 prompt_Printf(arg->prompt, " IPCP: %s\n", optval(arg->bundle, OPT_IPCP)); prompt_Printf(arg->prompt, " IPV6CP: %-20.20s", optval(arg->bundle, OPT_IPV6CP)); #endif prompt_Printf(arg->prompt, " Keep-Session: %s\n", optval(arg->bundle, OPT_KEEPSESSION)); prompt_Printf(arg->prompt, " Loopback: %-20.20s", optval(arg->bundle, OPT_LOOPBACK)); prompt_Printf(arg->prompt, " PasswdAuth: %s\n", optval(arg->bundle, OPT_PASSWDAUTH)); prompt_Printf(arg->prompt, " Proxy: %-20.20s", optval(arg->bundle, OPT_PROXY)); prompt_Printf(arg->prompt, " Proxyall: %s\n", optval(arg->bundle, OPT_PROXYALL)); prompt_Printf(arg->prompt, " Sticky Routes: %-20.20s", optval(arg->bundle, OPT_SROUTES)); prompt_Printf(arg->prompt, " TCPMSS Fixup: %s\n", optval(arg->bundle, OPT_TCPMSSFIXUP)); prompt_Printf(arg->prompt, " Throughput: %-20.20s", optval(arg->bundle, OPT_THROUGHPUT)); prompt_Printf(arg->prompt, " Utmp Logging: %s\n", optval(arg->bundle, OPT_UTMP)); return 0; } static void bundle_IdleTimeout(void *v) { struct bundle *bundle = (struct bundle *)v; log_Printf(LogPHASE, "Idle timer expired\n"); bundle_StopIdleTimer(bundle); bundle_Close(bundle, NULL, CLOSE_STAYDOWN); } /* * Start Idle timer. If timeout is reached, we call bundle_Close() to * close LCP and link. */ void bundle_StartIdleTimer(struct bundle *bundle, unsigned secs) { timer_Stop(&bundle->idle.timer); if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) != bundle->phys_type.open && bundle->cfg.idle.timeout) { time_t now = time(NULL); if (secs == 0) secs = bundle->cfg.idle.timeout; /* We want at least `secs' */ if (bundle->cfg.idle.min_timeout > secs && bundle->upat) { - int up = now - bundle->upat; + unsigned up = now - bundle->upat; - if ((long long)bundle->cfg.idle.min_timeout - up > (long long)secs) + if (bundle->cfg.idle.min_timeout > up && + bundle->cfg.idle.min_timeout - up > (long long)secs) /* Only increase from the current `remaining' value */ secs = bundle->cfg.idle.min_timeout - up; } bundle->idle.timer.func = bundle_IdleTimeout; bundle->idle.timer.name = "idle"; bundle->idle.timer.load = secs * SECTICKS; bundle->idle.timer.arg = bundle; timer_Start(&bundle->idle.timer); bundle->idle.done = now + secs; } } void -bundle_SetIdleTimer(struct bundle *bundle, int timeout, int min_timeout) +bundle_SetIdleTimer(struct bundle *bundle, unsigned timeout, + unsigned min_timeout) { bundle->cfg.idle.timeout = timeout; - if (min_timeout >= 0) - bundle->cfg.idle.min_timeout = min_timeout; + bundle->cfg.idle.min_timeout = min_timeout; if (ncp_LayersOpen(&bundle->ncp)) bundle_StartIdleTimer(bundle, 0); } void bundle_StopIdleTimer(struct bundle *bundle) { timer_Stop(&bundle->idle.timer); bundle->idle.done = 0; } static int bundle_RemainingIdleTime(struct bundle *bundle) { if (bundle->idle.done) return bundle->idle.done - time(NULL); return -1; } #ifndef NORADIUS static void bundle_SessionTimeout(void *v) { struct bundle *bundle = (struct bundle *)v; log_Printf(LogPHASE, "Session-Timeout timer expired\n"); bundle_StopSessionTimer(bundle); bundle_Close(bundle, NULL, CLOSE_STAYDOWN); } void bundle_StartSessionTimer(struct bundle *bundle, unsigned secs) { timer_Stop(&bundle->session.timer); if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) != bundle->phys_type.open && bundle->radius.sessiontime) { time_t now = time(NULL); if (secs == 0) secs = bundle->radius.sessiontime; bundle->session.timer.func = bundle_SessionTimeout; bundle->session.timer.name = "session"; bundle->session.timer.load = secs * SECTICKS; bundle->session.timer.arg = bundle; timer_Start(&bundle->session.timer); bundle->session.done = now + secs; } } void bundle_StopSessionTimer(struct bundle *bundle) { timer_Stop(&bundle->session.timer); bundle->session.done = 0; } #endif int bundle_IsDead(struct bundle *bundle) { return !bundle->links || (bundle->phase == PHASE_DEAD && bundle->CleaningUp); } static struct datalink * bundle_DatalinkLinkout(struct bundle *bundle, struct datalink *dl) { struct datalink **dlp; for (dlp = &bundle->links; *dlp; dlp = &(*dlp)->next) if (*dlp == dl) { *dlp = dl->next; dl->next = NULL; bundle_LinksRemoved(bundle); return dl; } return NULL; } static void bundle_DatalinkLinkin(struct bundle *bundle, struct datalink *dl) { struct datalink **dlp = &bundle->links; while (*dlp) dlp = &(*dlp)->next; *dlp = dl; dl->next = NULL; bundle_LinkAdded(bundle, dl); mp_CheckAutoloadTimer(&bundle->ncp.mp); } void bundle_CleanDatalinks(struct bundle *bundle) { struct datalink **dlp = &bundle->links; int found = 0; while (*dlp) if ((*dlp)->state == DATALINK_CLOSED && (*dlp)->physical->type & (PHYS_DIRECT|PHYS_BACKGROUND|PHYS_FOREGROUND)) { *dlp = datalink_Destroy(*dlp); found++; } else dlp = &(*dlp)->next; if (found) bundle_LinksRemoved(bundle); } int bundle_DatalinkClone(struct bundle *bundle, struct datalink *dl, const char *name) { if (bundle2datalink(bundle, name)) { log_Printf(LogWARN, "Clone: %s: name already exists\n", name); return 0; } bundle_DatalinkLinkin(bundle, datalink_Clone(dl, name)); return 1; } void bundle_DatalinkRemove(struct bundle *bundle, struct datalink *dl) { dl = bundle_DatalinkLinkout(bundle, dl); if (dl) datalink_Destroy(dl); } void bundle_SetLabel(struct bundle *bundle, const char *label) { if (label) strncpy(bundle->cfg.label, label, sizeof bundle->cfg.label - 1); else *bundle->cfg.label = '\0'; } const char * bundle_GetLabel(struct bundle *bundle) { return *bundle->cfg.label ? bundle->cfg.label : NULL; } int bundle_LinkSize() { struct iovec iov[SCATTER_SEGMENTS]; int niov, expect, f; iov[0].iov_len = strlen(Version) + 1; iov[0].iov_base = NULL; niov = 1; if (datalink2iov(NULL, iov, &niov, SCATTER_SEGMENTS, NULL, NULL) == -1) { log_Printf(LogERROR, "Cannot determine space required for link\n"); return 0; } for (f = expect = 0; f < niov; f++) expect += iov[f].iov_len; return expect; } void bundle_ReceiveDatalink(struct bundle *bundle, int s) { char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int) * SEND_MAXFD]; - int niov, expect, f, *fd, nfd, onfd, got; + int niov, expect, f, *fd, nfd, onfd; + ssize_t got; struct iovec iov[SCATTER_SEGMENTS]; struct cmsghdr *cmsg; struct msghdr msg; struct datalink *dl; pid_t pid; log_Printf(LogPHASE, "Receiving datalink\n"); /* * Create our scatter/gather array - passing NULL gets the space * allocation requirement rather than actually flattening the * structures. */ iov[0].iov_len = strlen(Version) + 1; iov[0].iov_base = NULL; niov = 1; if (datalink2iov(NULL, iov, &niov, SCATTER_SEGMENTS, NULL, NULL) == -1) { log_Printf(LogERROR, "Cannot determine space required for link\n"); return; } /* Allocate the scatter/gather array for recvmsg() */ for (f = expect = 0; f < niov; f++) { if ((iov[f].iov_base = malloc(iov[f].iov_len)) == NULL) { log_Printf(LogERROR, "Cannot allocate space to receive link\n"); return; } if (f) expect += iov[f].iov_len; } /* Set up our message */ cmsg = (struct cmsghdr *)cmsgbuf; cmsg->cmsg_len = sizeof cmsgbuf; cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = 0; memset(&msg, '\0', sizeof msg); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = 1; /* Only send the version at the first pass */ msg.msg_control = cmsgbuf; msg.msg_controllen = sizeof cmsgbuf; log_Printf(LogDEBUG, "Expecting %u scatter/gather bytes\n", (unsigned)iov[0].iov_len); - if ((got = recvmsg(s, &msg, MSG_WAITALL)) != iov[0].iov_len) { + if ((got = recvmsg(s, &msg, MSG_WAITALL)) != (ssize_t)iov[0].iov_len) { if (got == -1) log_Printf(LogERROR, "Failed recvmsg: %s\n", strerror(errno)); else log_Printf(LogERROR, "Failed recvmsg: Got %d, not %u\n", got, (unsigned)iov[0].iov_len); while (niov--) free(iov[niov].iov_base); return; } if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { log_Printf(LogERROR, "Recvmsg: no descriptors received !\n"); while (niov--) free(iov[niov].iov_base); return; } fd = (int *)CMSG_DATA(cmsg); nfd = ((caddr_t)cmsg + cmsg->cmsg_len - (caddr_t)fd) / sizeof(int); if (nfd < 2) { log_Printf(LogERROR, "Recvmsg: %d descriptor%s received (too few) !\n", nfd, nfd == 1 ? "" : "s"); while (nfd--) close(fd[nfd]); while (niov--) free(iov[niov].iov_base); return; } /* * We've successfully received two or more open file descriptors * through our socket, plus a version string. Make sure it's the * correct version, and drop the connection if it's not. */ if (strncmp(Version, iov[0].iov_base, iov[0].iov_len)) { log_Printf(LogWARN, "Cannot receive datalink, incorrect version" " (\"%.*s\", not \"%s\")\n", (int)iov[0].iov_len, (char *)iov[0].iov_base, Version); while (nfd--) close(fd[nfd]); while (niov--) free(iov[niov].iov_base); return; } /* * Everything looks good. Send the other side our process id so that * they can transfer lock ownership, and wait for them to send the * actual link data. */ pid = getpid(); if ((got = write(fd[1], &pid, sizeof pid)) != sizeof pid) { if (got == -1) log_Printf(LogERROR, "Failed write: %s\n", strerror(errno)); else log_Printf(LogERROR, "Failed write: Got %d, not %d\n", got, (int)(sizeof pid)); while (nfd--) close(fd[nfd]); while (niov--) free(iov[niov].iov_base); return; } if ((got = readv(fd[1], iov + 1, niov - 1)) != expect) { if (got == -1) log_Printf(LogERROR, "Failed write: %s\n", strerror(errno)); else log_Printf(LogERROR, "Failed write: Got %d, not %d\n", got, expect); while (nfd--) close(fd[nfd]); while (niov--) free(iov[niov].iov_base); return; } close(fd[1]); onfd = nfd; /* We've got this many in our array */ nfd -= 2; /* Don't include p->fd and our reply descriptor */ niov = 1; /* Skip the version id */ dl = iov2datalink(bundle, iov, &niov, sizeof iov / sizeof *iov, fd[0], fd + 2, &nfd); if (dl) { if (nfd) { log_Printf(LogERROR, "bundle_ReceiveDatalink: Failed to handle %d " "auxiliary file descriptors (%d remain)\n", onfd, nfd); datalink_Destroy(dl); while (nfd--) close(fd[onfd--]); close(fd[0]); } else { bundle_DatalinkLinkin(bundle, dl); datalink_AuthOk(dl); bundle_CalculateBandwidth(dl->bundle); } } else { while (nfd--) close(fd[onfd--]); close(fd[0]); close(fd[1]); } free(iov[0].iov_base); } void bundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun) { char cmsgbuf[CMSG_SPACE(sizeof(int) * SEND_MAXFD)]; const char *constlock; char *lock; struct cmsghdr *cmsg; struct msghdr msg; struct iovec iov[SCATTER_SEGMENTS]; - int niov, f, expect, newsid, fd[SEND_MAXFD], nfd, reply[2], got; + int niov, f, expect, newsid, fd[SEND_MAXFD], nfd, reply[2]; + ssize_t got; pid_t newpid; log_Printf(LogPHASE, "Transmitting datalink %s\n", dl->name); /* Record the base device name for a lock transfer later */ constlock = physical_LockedDevice(dl->physical); if (constlock) { lock = alloca(strlen(constlock) + 1); strcpy(lock, constlock); } else lock = NULL; bundle_LinkClosed(dl->bundle, dl); bundle_DatalinkLinkout(dl->bundle, dl); /* Build our scatter/gather array */ iov[0].iov_len = strlen(Version) + 1; iov[0].iov_base = strdup(Version); niov = 1; nfd = 0; fd[0] = datalink2iov(dl, iov, &niov, SCATTER_SEGMENTS, fd + 2, &nfd); if (fd[0] != -1 && socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, reply) != -1) { /* * fd[1] is used to get the peer process id back, then to confirm that * we've transferred any device locks to that process id. */ fd[1] = reply[1]; nfd += 2; /* Include fd[0] and fd[1] */ memset(&msg, '\0', sizeof msg); msg.msg_name = NULL; msg.msg_namelen = 0; /* * Only send the version to start... We used to send the whole lot, but * this caused problems with our RECVBUF size as a single link is about * 22k ! This way, we should bump into no limits. */ msg.msg_iovlen = 1; msg.msg_iov = iov; msg.msg_control = cmsgbuf; msg.msg_controllen = CMSG_SPACE(sizeof(int) * nfd); msg.msg_flags = 0; cmsg = (struct cmsghdr *)cmsgbuf; cmsg->cmsg_len = msg.msg_controllen; cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; for (f = 0; f < nfd; f++) *((int *)CMSG_DATA(cmsg) + f) = fd[f]; for (f = 1, expect = 0; f < niov; f++) expect += iov[f].iov_len; if (setsockopt(reply[0], SOL_SOCKET, SO_SNDBUF, &expect, sizeof(int)) == -1) log_Printf(LogERROR, "setsockopt(SO_RCVBUF, %d): %s\n", expect, strerror(errno)); if (setsockopt(reply[1], SOL_SOCKET, SO_RCVBUF, &expect, sizeof(int)) == -1) log_Printf(LogERROR, "setsockopt(SO_RCVBUF, %d): %s\n", expect, strerror(errno)); log_Printf(LogDEBUG, "Sending %d descriptor%s and %u bytes in scatter" "/gather array\n", nfd, nfd == 1 ? "" : "s", (unsigned)iov[0].iov_len); if ((got = sendmsg(s, &msg, 0)) == -1) log_Printf(LogERROR, "Failed sendmsg: %s: %s\n", sun->sun_path, strerror(errno)); - else if (got != iov[0].iov_len) + else if (got != (ssize_t)iov[0].iov_len) log_Printf(LogERROR, "%s: Failed initial sendmsg: Only sent %d of %u\n", sun->sun_path, got, (unsigned)iov[0].iov_len); else { /* We must get the ACK before closing the descriptor ! */ int res; if ((got = read(reply[0], &newpid, sizeof newpid)) == sizeof newpid) { log_Printf(LogDEBUG, "Received confirmation from pid %ld\n", (long)newpid); if (lock && (res = ID0uu_lock_txfr(lock, newpid)) != UU_LOCK_OK) log_Printf(LogERROR, "uu_lock_txfr: %s\n", uu_lockerr(res)); log_Printf(LogDEBUG, "Transmitting link (%d bytes)\n", expect); if ((got = writev(reply[0], iov + 1, niov - 1)) != expect) { if (got == -1) log_Printf(LogERROR, "%s: Failed writev: %s\n", sun->sun_path, strerror(errno)); else log_Printf(LogERROR, "%s: Failed writev: Wrote %d of %d\n", sun->sun_path, got, expect); } } else if (got == -1) log_Printf(LogERROR, "%s: Failed socketpair read: %s\n", sun->sun_path, strerror(errno)); else log_Printf(LogERROR, "%s: Failed socketpair read: Got %d of %d\n", sun->sun_path, got, (int)(sizeof newpid)); } close(reply[0]); close(reply[1]); newsid = Enabled(dl->bundle, OPT_KEEPSESSION) || tcgetpgrp(fd[0]) == getpgrp(); while (nfd) close(fd[--nfd]); if (newsid) bundle_setsid(dl->bundle, got != -1); } close(s); while (niov--) free(iov[niov].iov_base); } int bundle_RenameDatalink(struct bundle *bundle, struct datalink *ndl, const char *name) { struct datalink *dl; if (!strcasecmp(ndl->name, name)) return 1; for (dl = bundle->links; dl; dl = dl->next) if (!strcasecmp(dl->name, name)) return 0; datalink_Rename(ndl, name); return 1; } int bundle_SetMode(struct bundle *bundle, struct datalink *dl, int mode) { int omode; omode = dl->physical->type; if (omode == mode) return 1; if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO)) /* First auto link */ if (bundle->ncp.ipcp.peer_ip.s_addr == INADDR_ANY) { log_Printf(LogWARN, "You must `set ifaddr' or `open' before" " changing mode to %s\n", mode2Nam(mode)); return 0; } if (!datalink_SetMode(dl, mode)) return 0; if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO) && bundle->phase != PHASE_NETWORK) /* First auto link, we need an interface */ ipcp_InterfaceUp(&bundle->ncp.ipcp); /* Regenerate phys_type and adjust idle timer */ bundle_LinksRemoved(bundle); return 1; } void bundle_setsid(struct bundle *bundle, int holdsession) { /* * Lose the current session. This means getting rid of our pid * too so that the tty device will really go away, and any getty * etc will be allowed to restart. */ pid_t pid, orig; int fds[2]; char done; struct datalink *dl; if (!holdsession && bundle_IsDead(bundle)) { /* * No need to lose our session after all... we're going away anyway * * We should really stop the timer and pause if holdsession is set and * the bundle's dead, but that leaves other resources lying about :-( */ return; } orig = getpid(); if (pipe(fds) == -1) { log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); return; } switch ((pid = fork())) { case -1: log_Printf(LogERROR, "fork: %s\n", strerror(errno)); close(fds[0]); close(fds[1]); return; case 0: close(fds[1]); read(fds[0], &done, 1); /* uu_locks are mine ! */ close(fds[0]); if (pipe(fds) == -1) { log_Printf(LogERROR, "pipe(2): %s\n", strerror(errno)); return; } switch ((pid = fork())) { case -1: log_Printf(LogERROR, "fork(2): %s\n", strerror(errno)); close(fds[0]); close(fds[1]); return; case 0: close(fds[1]); bundle_LockTun(bundle); /* update pid */ read(fds[0], &done, 1); /* uu_locks are mine ! */ close(fds[0]); setsid(); bundle_ChangedPID(bundle); log_Printf(LogDEBUG, "%ld -> %ld: %s session control\n", (long)orig, (long)getpid(), holdsession ? "Passed" : "Dropped"); timer_InitService(0); /* Start the Timer Service */ break; default: close(fds[0]); /* Give away all our physical locks (to the final process) */ for (dl = bundle->links; dl; dl = dl->next) if (dl->state != DATALINK_CLOSED) physical_ChangedPid(dl->physical, pid); write(fds[1], "!", 1); /* done */ close(fds[1]); _exit(0); break; } break; default: close(fds[0]); /* Give away all our physical locks (to the intermediate process) */ for (dl = bundle->links; dl; dl = dl->next) if (dl->state != DATALINK_CLOSED) physical_ChangedPid(dl->physical, pid); write(fds[1], "!", 1); /* done */ close(fds[1]); if (holdsession) { int fd, status; timer_TermService(); signal(SIGPIPE, SIG_DFL); signal(SIGALRM, SIG_DFL); signal(SIGHUP, SIG_DFL); signal(SIGTERM, SIG_DFL); signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); for (fd = getdtablesize(); fd >= 0; fd--) close(fd); /* * Reap the intermediate process. As we're not exiting but the * intermediate is, we don't want it to become defunct. */ waitpid(pid, &status, 0); /* Tweak our process arguments.... */ SetTitle("session owner"); #ifndef NOSUID setuid(ID0realuid()); #endif /* * Hang around for a HUP. This should happen as soon as the * ppp that we passed our ctty descriptor to closes it. * NOTE: If this process dies, the passed descriptor becomes * invalid and will give a select() error by setting one * of the error fds, aborting the other ppp. We don't * want that to happen ! */ pause(); } _exit(0); break; } } -int +unsigned bundle_HighestState(struct bundle *bundle) { struct datalink *dl; - int result = DATALINK_CLOSED; + unsigned result = DATALINK_CLOSED; for (dl = bundle->links; dl; dl = dl->next) if (result < dl->state) result = dl->state; return result; } int bundle_Exception(struct bundle *bundle, int fd) { struct datalink *dl; for (dl = bundle->links; dl; dl = dl->next) if (dl->physical->fd == fd) { datalink_Down(dl, CLOSE_NORMAL); return 1; } return 0; } void bundle_AdjustFilters(struct bundle *bundle, struct ncpaddr *local, struct ncpaddr *remote) { filter_AdjustAddr(&bundle->filter.in, local, remote, NULL); filter_AdjustAddr(&bundle->filter.out, local, remote, NULL); filter_AdjustAddr(&bundle->filter.dial, local, remote, NULL); filter_AdjustAddr(&bundle->filter.alive, local, remote, NULL); } void bundle_AdjustDNS(struct bundle *bundle) { struct in_addr *dns = bundle->ncp.ipcp.ns.dns; filter_AdjustAddr(&bundle->filter.in, NULL, NULL, dns); filter_AdjustAddr(&bundle->filter.out, NULL, NULL, dns); filter_AdjustAddr(&bundle->filter.dial, NULL, NULL, dns); filter_AdjustAddr(&bundle->filter.alive, NULL, NULL, dns); } void bundle_CalculateBandwidth(struct bundle *bundle) { struct datalink *dl; int sp, overhead, maxoverhead; bundle->bandwidth = 0; bundle->iface->mtu = 0; maxoverhead = 0; for (dl = bundle->links; dl; dl = dl->next) { overhead = ccp_MTUOverhead(&dl->physical->link.ccp); if (maxoverhead < overhead) maxoverhead = overhead; if (dl->state == DATALINK_OPEN) { if ((sp = dl->mp.bandwidth) == 0 && (sp = physical_GetSpeed(dl->physical)) == 0) log_Printf(LogDEBUG, "%s: %s: Cannot determine bandwidth\n", dl->name, dl->physical->name.full); else bundle->bandwidth += sp; if (!bundle->ncp.mp.active) { bundle->iface->mtu = dl->physical->link.lcp.his_mru; break; } } } if (bundle->bandwidth == 0) bundle->bandwidth = 115200; /* Shrug */ if (bundle->ncp.mp.active) { bundle->iface->mtu = bundle->ncp.mp.peer_mrru; overhead = ccp_MTUOverhead(&bundle->ncp.mp.link.ccp); if (maxoverhead < overhead) maxoverhead = overhead; } else if (!bundle->iface->mtu) bundle->iface->mtu = DEF_MRU; #ifndef NORADIUS if (bundle->radius.valid && bundle->radius.mtu && bundle->radius.mtu < bundle->iface->mtu) { log_Printf(LogLCP, "Reducing MTU to radius value %lu\n", bundle->radius.mtu); bundle->iface->mtu = bundle->radius.mtu; } #endif if (maxoverhead) { - log_Printf(LogLCP, "Reducing MTU from %d to %d (CCP requirement)\n", + log_Printf(LogLCP, "Reducing MTU from %lu to %lu (CCP requirement)\n", bundle->iface->mtu, bundle->iface->mtu - maxoverhead); bundle->iface->mtu -= maxoverhead; } tun_configure(bundle); route_UpdateMTU(bundle); } void bundle_AutoAdjust(struct bundle *bundle, int percent, int what) { struct datalink *dl, *choice, *otherlinkup; choice = otherlinkup = NULL; for (dl = bundle->links; dl; dl = dl->next) if (dl->physical->type == PHYS_AUTO) { if (dl->state == DATALINK_OPEN) { if (what == AUTO_DOWN) { if (choice) otherlinkup = choice; choice = dl; } } else if (dl->state == DATALINK_CLOSED) { if (what == AUTO_UP) { choice = dl; break; } } else { /* An auto link in an intermediate state - forget it for the moment */ choice = NULL; break; } } else if (dl->state == DATALINK_OPEN && what == AUTO_DOWN) otherlinkup = dl; if (choice) { if (what == AUTO_UP) { log_Printf(LogPHASE, "%d%% saturation -> Opening link ``%s''\n", percent, choice->name); datalink_Up(choice, 1, 1); mp_CheckAutoloadTimer(&bundle->ncp.mp); } else if (otherlinkup) { /* Only bring the second-last link down */ log_Printf(LogPHASE, "%d%% saturation -> Closing link ``%s''\n", percent, choice->name); datalink_Close(choice, CLOSE_STAYDOWN); mp_CheckAutoloadTimer(&bundle->ncp.mp); } } } int bundle_WantAutoloadTimer(struct bundle *bundle) { struct datalink *dl; int autolink, opened; if (bundle->phase == PHASE_NETWORK) { for (autolink = opened = 0, dl = bundle->links; dl; dl = dl->next) if (dl->physical->type == PHYS_AUTO) { if (++autolink == 2 || (autolink == 1 && opened)) /* Two auto links or one auto and one open in NETWORK phase */ return 1; } else if (dl->state == DATALINK_OPEN) { opened++; if (autolink) /* One auto and one open link in NETWORK phase */ return 1; } } return 0; } void bundle_ChangedPID(struct bundle *bundle) { #ifdef TUNSIFPID ioctl(bundle->dev.fd, TUNSIFPID, 0); #endif } int bundle_Uptime(struct bundle *bundle) { if (bundle->upat) return time(NULL) - bundle->upat; return 0; } Index: head/usr.sbin/ppp/bundle.h =================================================================== --- head/usr.sbin/ppp/bundle.h (revision 134788) +++ head/usr.sbin/ppp/bundle.h (revision 134789) @@ -1,211 +1,211 @@ /*- * 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. * * $FreeBSD$ */ #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 */ /* cfg.opt bit settings */ #define OPT_FILTERDECAP 0x0001 #define OPT_FORCE_SCRIPTS 0x0002 /* force chat scripts */ #define OPT_IDCHECK 0x0004 #define OPT_IFACEALIAS 0x0008 #ifndef NOINET6 #define OPT_IPCP 0x0010 #define OPT_IPV6CP 0x0020 #endif #define OPT_KEEPSESSION 0x0040 #define OPT_LOOPBACK 0x0080 #define OPT_PASSWDAUTH 0x0100 #define OPT_PROXY 0x0200 #define OPT_PROXYALL 0x0400 #define OPT_SROUTES 0x0800 #define OPT_TCPMSSFIXUP 0x1000 #define OPT_THROUGHPUT 0x2000 #define OPT_UTMP 0x4000 #define MAX_ENDDISC_CLASS 5 #define Enabled(b, o) ((b)->cfg.opt & (o)) /* AutoAdjust() values */ #define AUTO_UP 1 #define AUTO_DOWN 2 struct sockaddr_un; struct datalink; struct physical; struct link; struct server; struct prompt; struct iface; struct bundle { struct fdescriptor desc; /* really all our datalinks */ int unit; /* The device/interface unit number */ struct { char Name[20]; /* The /dev/XXXX name */ int fd; /* The /dev/XXXX descriptor */ unsigned header : 1; /* Family header sent & received ? */ } dev; u_long bandwidth; /* struct tuninfo speed */ struct iface *iface; /* Interface information */ int routing_seq; /* The current routing sequence number */ u_int phase; /* Curent phase */ struct { int all; /* Union of all physical::type's */ int open; /* Union of all open physical::type's */ } phys_type; unsigned CleaningUp : 1; /* Going to exit.... */ unsigned NatEnabled : 1; /* Are we using libalias ? */ struct fsm_parent fsm; /* Our callback functions */ struct datalink *links; /* Our data links */ time_t upat; /* When the link came up */ struct { struct { - int timeout; /* NCP Idle timeout value */ - int min_timeout; /* Don't idle out before this */ + unsigned timeout; /* NCP Idle timeout value */ + unsigned min_timeout; /* Don't idle out before this */ } idle; struct { char name[AUTHLEN]; /* PAP/CHAP system name */ char key[AUTHLEN]; /* PAP/CHAP key */ } auth; unsigned opt; /* Uses OPT_ bits from above */ char label[50]; /* last thing `load'ed */ u_short ifqueue; /* Interface queue size */ struct { - int timeout; /* How long to leave the output queue choked */ + unsigned timeout; /* How long to leave the output queue choked */ } choked; } cfg; struct ncp ncp; struct { struct filter in; /* incoming packet filter */ struct filter out; /* outgoing packet filter */ struct filter dial; /* dial-out packet filter */ struct filter alive; /* keep-alive packet filter */ } filter; struct { struct pppTimer timer; /* timeout after cfg.idle_timeout */ time_t done; } idle; #ifndef NORADIUS struct { struct pppTimer timer; time_t done; } session; #endif struct { int fd; /* write status here */ } notify; struct { struct pppTimer timer; /* choked output queue timer */ } choked; #ifndef NORADIUS struct radius radius; /* Info retrieved from radius server */ struct radacct radacct; #ifndef NOINET6 struct radacct radacct6; #endif #endif }; #define descriptor2bundle(d) \ ((d)->type == BUNDLE_DESCRIPTOR ? (struct bundle *)(d) : NULL) extern struct bundle *bundle_Create(const char *, int, int); 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 *, u_int); extern void bundle_LinksRemoved(struct bundle *); extern void bundle_Close(struct bundle *, const char *, int); extern void bundle_Down(struct bundle *, int); extern void bundle_Open(struct bundle *, const char *, int, int); extern void bundle_LinkClosed(struct bundle *, struct datalink *); extern int bundle_ShowLinks(struct cmdargs const *); extern int bundle_ShowStatus(struct cmdargs const *); extern void bundle_StartIdleTimer(struct bundle *, unsigned secs); -extern void bundle_SetIdleTimer(struct bundle *, int, int); +extern void bundle_SetIdleTimer(struct bundle *, unsigned, unsigned); extern void bundle_StopIdleTimer(struct bundle *); extern int bundle_IsDead(struct bundle *); extern struct datalink *bundle2datalink(struct bundle *, const char *); #ifndef NORADIUS extern void bundle_StartSessionTimer(struct bundle *, unsigned secs); extern void bundle_StopSessionTimer(struct bundle *); #endif extern void bundle_RegisterDescriptor(struct bundle *, struct fdescriptor *); extern void bundle_UnRegisterDescriptor(struct bundle *, struct fdescriptor *); extern void bundle_SetTtyCommandMode(struct bundle *, struct datalink *); extern int bundle_DatalinkClone(struct bundle *, struct datalink *, const char *); extern void bundle_DatalinkRemove(struct bundle *, struct datalink *); extern void bundle_CleanDatalinks(struct bundle *); extern void bundle_SetLabel(struct bundle *, const char *); extern const char *bundle_GetLabel(struct bundle *); extern void bundle_SendDatalink(struct datalink *, int, struct sockaddr_un *); extern int bundle_LinkSize(void); extern void bundle_ReceiveDatalink(struct bundle *, int); extern int bundle_SetMode(struct bundle *, struct datalink *, int); extern int bundle_RenameDatalink(struct bundle *, struct datalink *, const char *); extern void bundle_setsid(struct bundle *, int); extern void bundle_LockTun(struct bundle *); -extern int bundle_HighestState(struct bundle *); +extern unsigned bundle_HighestState(struct bundle *); extern int bundle_Exception(struct bundle *, int); extern void bundle_AdjustFilters(struct bundle *, struct ncpaddr *, struct ncpaddr *); extern void bundle_AdjustDNS(struct bundle *); extern void bundle_CalculateBandwidth(struct bundle *); extern void bundle_AutoAdjust(struct bundle *, int, int); extern int bundle_WantAutoloadTimer(struct bundle *); extern void bundle_ChangedPID(struct bundle *); extern void bundle_Notify(struct bundle *, char); extern int bundle_Uptime(struct bundle *); Index: head/usr.sbin/ppp/cbcp.c =================================================================== --- head/usr.sbin/ppp/cbcp.c (revision 134788) +++ head/usr.sbin/ppp/cbcp.c (revision 134789) @@ -1,759 +1,759 @@ /*- * 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. * * $FreeBSD$ */ #include #ifdef __FreeBSD__ #include #endif #include #include #include #include "layer.h" #include "defs.h" #include "log.h" #include "timer.h" #include "descriptor.h" #include "lqr.h" #include "mbuf.h" #include "fsm.h" #include "throughput.h" #include "hdlc.h" #include "lcp.h" #include "ccp.h" #include "link.h" #include "async.h" #include "physical.h" #include "proto.h" #include "cbcp.h" #include "mp.h" #include "chat.h" #include "auth.h" #include "chap.h" #include "datalink.h" void cbcp_Init(struct cbcp *cbcp, struct physical *p) { cbcp->required = 0; cbcp->fsm.state = CBCP_CLOSED; cbcp->fsm.id = 0; cbcp->fsm.delay = 0; *cbcp->fsm.phone = '\0'; memset(&cbcp->fsm.timer, '\0', sizeof cbcp->fsm.timer); cbcp->p = p; } static void cbcp_SendReq(struct cbcp *); static void cbcp_SendResponse(struct cbcp *); static void cbcp_SendAck(struct cbcp *); static void cbcp_Timeout(void *v) { struct cbcp *cbcp = (struct cbcp *)v; timer_Stop(&cbcp->fsm.timer); if (cbcp->fsm.restart) { switch (cbcp->fsm.state) { case CBCP_CLOSED: case CBCP_STOPPED: log_Printf(LogCBCP, "%s: Urk - unexpected CBCP timeout !\n", cbcp->p->dl->name); break; case CBCP_REQSENT: cbcp_SendReq(cbcp); break; case CBCP_RESPSENT: cbcp_SendResponse(cbcp); break; case CBCP_ACKSENT: cbcp_SendAck(cbcp); break; } } else { const char *missed; switch (cbcp->fsm.state) { case CBCP_STOPPED: missed = "REQ"; break; case CBCP_REQSENT: missed = "RESPONSE"; break; case CBCP_RESPSENT: missed = "ACK"; break; case CBCP_ACKSENT: missed = "Terminate REQ"; break; default: log_Printf(LogCBCP, "%s: Urk - unexpected CBCP timeout !\n", cbcp->p->dl->name); missed = NULL; break; } if (missed) log_Printf(LogCBCP, "%s: Timeout waiting for peer %s\n", cbcp->p->dl->name, missed); datalink_CBCPFailed(cbcp->p->dl); } } static void cbcp_StartTimer(struct cbcp *cbcp, int timeout) { timer_Stop(&cbcp->fsm.timer); cbcp->fsm.timer.func = cbcp_Timeout; cbcp->fsm.timer.name = "cbcp"; cbcp->fsm.timer.load = timeout * SECTICKS; cbcp->fsm.timer.arg = cbcp; timer_Start(&cbcp->fsm.timer); } #define CBCP_CLOSED (0) /* Not in use */ #define CBCP_STOPPED (1) /* Waiting for a REQ */ #define CBCP_REQSENT (2) /* Waiting for a RESP */ #define CBCP_RESPSENT (3) /* Waiting for an ACK */ #define CBCP_ACKSENT (4) /* Waiting for an LCP Term REQ */ static const char * const cbcpname[] = { "closed", "stopped", "req-sent", "resp-sent", "ack-sent" }; static const char * -cbcpstate(int s) +cbcpstate(unsigned s) { if (s < sizeof cbcpname / sizeof cbcpname[0]) return cbcpname[s]; return HexStr(s, NULL, 0); } static void cbcp_NewPhase(struct cbcp *cbcp, int new) { if (cbcp->fsm.state != new) { log_Printf(LogCBCP, "%s: State change %s --> %s\n", cbcp->p->dl->name, cbcpstate(cbcp->fsm.state), cbcpstate(new)); cbcp->fsm.state = new; } } struct cbcp_header { u_char code; u_char id; u_int16_t length; /* Network byte order */ }; /* cbcp_header::code values */ #define CBCP_REQ (1) #define CBCP_RESPONSE (2) #define CBCP_ACK (3) struct cbcp_data { u_char type; u_char length; u_char delay; char addr_start[253]; /* max cbcp_data length 255 + 1 for NULL */ }; /* cbcp_data::type values */ #define CBCP_NONUM (1) #define CBCP_CLIENTNUM (2) #define CBCP_SERVERNUM (3) #define CBCP_LISTNUM (4) static void cbcp_Output(struct cbcp *cbcp, u_char code, struct cbcp_data *data) { struct cbcp_header *head; struct mbuf *bp; bp = m_get(sizeof *head + data->length, MB_CBCPOUT); head = (struct cbcp_header *)MBUF_CTOP(bp); head->code = code; head->id = cbcp->fsm.id; head->length = htons(sizeof *head + data->length); memcpy(MBUF_CTOP(bp) + sizeof *head, data, data->length); log_DumpBp(LogDEBUG, "cbcp_Output", bp); link_PushPacket(&cbcp->p->link, bp, cbcp->p->dl->bundle, LINK_QUEUES(&cbcp->p->link) - 1, PROTO_CBCP); } static const char * -cbcp_data_Type(int type) +cbcp_data_Type(unsigned type) { static const char * const types[] = { "No callback", "User-spec", "Server-spec", "list" }; if (type < 1 || type > sizeof types / sizeof types[0]) return HexStr(type, NULL, 0); return types[type-1]; } struct cbcp_addr { u_char type; char addr[1]; /* Really ASCIIZ */ }; /* cbcp_data::type values */ #define CBCP_ADDR_PSTN (1) static void cbcp_data_Show(struct cbcp_data *data) { struct cbcp_addr *addr; char *end; addr = (struct cbcp_addr *)data->addr_start; end = (char *)data + data->length; *end = '\0'; log_Printf(LogCBCP, " TYPE %s\n", cbcp_data_Type(data->type)); if ((char *)&data->delay < end) { log_Printf(LogCBCP, " DELAY %d\n", data->delay); while (addr->addr < end) { if (addr->type == CBCP_ADDR_PSTN) log_Printf(LogCBCP, " ADDR %s\n", addr->addr); else log_Printf(LogCBCP, " ADDR type %d ??\n", (int)addr->type); addr = (struct cbcp_addr *)(addr->addr + strlen(addr->addr) + 1); } } } static void cbcp_SendReq(struct cbcp *cbcp) { struct cbcp_data data; struct cbcp_addr *addr; char list[sizeof cbcp->fsm.phone], *next; int len, max; /* Only callees send REQs */ log_Printf(LogCBCP, "%s: SendReq(%d) state = %s\n", cbcp->p->dl->name, cbcp->fsm.id, cbcpstate(cbcp->fsm.state)); data.type = cbcp->fsm.type; data.delay = 0; strncpy(list, cbcp->fsm.phone, sizeof list - 1); list[sizeof list - 1] = '\0'; switch (data.type) { case CBCP_CLIENTNUM: addr = (struct cbcp_addr *)data.addr_start; addr->type = CBCP_ADDR_PSTN; *addr->addr = '\0'; data.length = addr->addr - (char *)&data; break; case CBCP_LISTNUM: addr = (struct cbcp_addr *)data.addr_start; for (next = strtok(list, ","); next; next = strtok(NULL, ",")) { len = strlen(next); max = data.addr_start + sizeof data.addr_start - addr->addr - 1; if (len <= max) { addr->type = CBCP_ADDR_PSTN; strcpy(addr->addr, next); addr = (struct cbcp_addr *)((char *)addr + len + 2); } else log_Printf(LogWARN, "CBCP ADDR \"%s\" skipped - packet too large\n", next); } data.length = (char *)addr - (char *)&data; break; case CBCP_SERVERNUM: data.length = data.addr_start - (char *)&data; break; default: data.length = (char *)&data.delay - (char *)&data; break; } cbcp_data_Show(&data); cbcp_Output(cbcp, CBCP_REQ, &data); cbcp->fsm.restart--; cbcp_StartTimer(cbcp, cbcp->fsm.delay); cbcp_NewPhase(cbcp, CBCP_REQSENT); /* Wait for a RESPONSE */ } void cbcp_Up(struct cbcp *cbcp) { struct lcp *lcp = &cbcp->p->link.lcp; cbcp->fsm.delay = cbcp->p->dl->cfg.cbcp.delay; if (*cbcp->p->dl->peer.authname == '\0' || !auth_SetPhoneList(cbcp->p->dl->peer.authname, cbcp->fsm.phone, sizeof cbcp->fsm.phone)) { strncpy(cbcp->fsm.phone, cbcp->p->dl->cfg.cbcp.phone, sizeof cbcp->fsm.phone - 1); cbcp->fsm.phone[sizeof cbcp->fsm.phone - 1] = '\0'; } if (lcp->want_callback.opmask) { if (*cbcp->fsm.phone == '\0') cbcp->fsm.type = CBCP_NONUM; else if (!strcmp(cbcp->fsm.phone, "*")) { cbcp->fsm.type = CBCP_SERVERNUM; *cbcp->fsm.phone = '\0'; } else cbcp->fsm.type = CBCP_CLIENTNUM; cbcp_NewPhase(cbcp, CBCP_STOPPED); /* Wait for a REQ */ cbcp_StartTimer(cbcp, cbcp->fsm.delay * DEF_FSMTRIES); } else { if (*cbcp->fsm.phone == '\0') cbcp->fsm.type = CBCP_NONUM; else if (!strcmp(cbcp->fsm.phone, "*")) { cbcp->fsm.type = CBCP_CLIENTNUM; *cbcp->fsm.phone = '\0'; } else if (strchr(cbcp->fsm.phone, ',')) cbcp->fsm.type = CBCP_LISTNUM; else cbcp->fsm.type = CBCP_SERVERNUM; cbcp->fsm.restart = DEF_FSMTRIES; cbcp_SendReq(cbcp); } } static int cbcp_AdjustResponse(struct cbcp *cbcp, struct cbcp_data *data) { /* * We've received a REQ (data). Adjust our reponse (cbcp->fsm.*) * so that we (hopefully) agree with the peer */ struct cbcp_addr *addr; switch (data->type) { case CBCP_NONUM: if (cbcp->p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) /* * if ``none'' is a configured callback possibility * (ie, ``set callback cbcp none''), go along with the callees * request */ cbcp->fsm.type = CBCP_NONUM; /* * Otherwise, we send our desired response anyway. This seems to be * what Win95 does - although I can't find this behaviour documented * in the CBCP spec.... */ return 1; case CBCP_CLIENTNUM: if (cbcp->fsm.type == CBCP_CLIENTNUM) { char *ptr; if (data->length > data->addr_start - (char *)data) { /* * The peer has given us an address type spec - make sure we * understand ! */ addr = (struct cbcp_addr *)data->addr_start; if (addr->type != CBCP_ADDR_PSTN) { log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n", (int)addr->type); return 0; } } /* we accept the REQ even if the peer didn't specify an addr->type */ ptr = strchr(cbcp->fsm.phone, ','); if (ptr) *ptr = '\0'; /* Just use the first number in our list */ return 1; } log_Printf(LogPHASE, "CBCP: no number to pass to the peer !\n"); return 0; case CBCP_SERVERNUM: if (cbcp->fsm.type == CBCP_SERVERNUM) { *cbcp->fsm.phone = '\0'; return 1; } if (data->length > data->addr_start - (char *)data) { /* * This violates the spec, but if the peer has told us the * number it wants to call back, take advantage of this fact * and allow things to proceed if we've specified the same * number */ addr = (struct cbcp_addr *)data->addr_start; if (addr->type != CBCP_ADDR_PSTN) { log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n", (int)addr->type); return 0; } else if (cbcp->fsm.type == CBCP_CLIENTNUM) { /* * If the peer's insisting on deciding the number, make sure * it's one of the ones in our list. If it is, let the peer * think it's in control :-) */ char list[sizeof cbcp->fsm.phone], *next; strncpy(list, cbcp->fsm.phone, sizeof list - 1); list[sizeof list - 1] = '\0'; for (next = strtok(list, ","); next; next = strtok(NULL, ",")) if (!strcmp(next, addr->addr)) { cbcp->fsm.type = CBCP_SERVERNUM; strcpy(cbcp->fsm.phone, next); return 1; } } } log_Printf(LogPHASE, "CBCP: Peer won't allow local decision !\n"); return 0; case CBCP_LISTNUM: if (cbcp->fsm.type == CBCP_CLIENTNUM || cbcp->fsm.type == CBCP_LISTNUM) { /* * Search through ``data''s addresses and see if cbcp->fsm.phone * contains any of them */ char list[sizeof cbcp->fsm.phone], *next, *end; addr = (struct cbcp_addr *)data->addr_start; end = (char *)data + data->length; while (addr->addr < end) { if (addr->type == CBCP_ADDR_PSTN) { strncpy(list, cbcp->fsm.phone, sizeof list - 1); list[sizeof list - 1] = '\0'; for (next = strtok(list, ","); next; next = strtok(NULL, ",")) if (!strcmp(next, addr->addr)) { cbcp->fsm.type = CBCP_LISTNUM; strcpy(cbcp->fsm.phone, next); return 1; } } else log_Printf(LogCBCP, "Warning: Unrecognised address type %d !\n", (int)addr->type); addr = (struct cbcp_addr *)(addr->addr + strlen(addr->addr) + 1); } } log_Printf(LogPHASE, "CBCP: no good number to pass to the peer !\n"); return 0; } log_Printf(LogCBCP, "Unrecognised REQ type %d !\n", (int)data->type); return 0; } static void cbcp_SendResponse(struct cbcp *cbcp) { struct cbcp_data data; struct cbcp_addr *addr; /* Only callers send RESPONSEs */ log_Printf(LogCBCP, "%s: SendResponse(%d) state = %s\n", cbcp->p->dl->name, cbcp->fsm.id, cbcpstate(cbcp->fsm.state)); data.type = cbcp->fsm.type; data.delay = cbcp->fsm.delay; addr = (struct cbcp_addr *)data.addr_start; if (data.type == CBCP_NONUM) data.length = (char *)&data.delay - (char *)&data; else if (*cbcp->fsm.phone) { addr->type = CBCP_ADDR_PSTN; strcpy(addr->addr, cbcp->fsm.phone); data.length = (addr->addr + strlen(addr->addr) + 1) - (char *)&data; } else data.length = data.addr_start - (char *)&data; cbcp_data_Show(&data); cbcp_Output(cbcp, CBCP_RESPONSE, &data); cbcp->fsm.restart--; cbcp_StartTimer(cbcp, cbcp->fsm.delay); cbcp_NewPhase(cbcp, CBCP_RESPSENT); /* Wait for an ACK */ } /* What to do after checking an incoming response */ #define CBCP_ACTION_DOWN (0) #define CBCP_ACTION_REQ (1) #define CBCP_ACTION_ACK (2) static int cbcp_CheckResponse(struct cbcp *cbcp, struct cbcp_data *data) { /* * We've received a RESPONSE (data). Check if it agrees with * our REQ (cbcp->fsm) */ struct cbcp_addr *addr; addr = (struct cbcp_addr *)data->addr_start; if (data->type == cbcp->fsm.type) { switch (cbcp->fsm.type) { case CBCP_NONUM: return CBCP_ACTION_ACK; case CBCP_CLIENTNUM: if ((char *)data + data->length <= addr->addr) log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n"); else if (addr->type != CBCP_ADDR_PSTN) log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n", addr->type); else { strcpy(cbcp->fsm.phone, addr->addr); cbcp->fsm.delay = data->delay; return CBCP_ACTION_ACK; } return CBCP_ACTION_DOWN; case CBCP_SERVERNUM: cbcp->fsm.delay = data->delay; return CBCP_ACTION_ACK; case CBCP_LISTNUM: if ((char *)data + data->length <= addr->addr) log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n"); else if (addr->type != CBCP_ADDR_PSTN) log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n", addr->type); else { char list[sizeof cbcp->fsm.phone], *next; strncpy(list, cbcp->fsm.phone, sizeof list - 1); list[sizeof list - 1] = '\0'; for (next = strtok(list, ","); next; next = strtok(NULL, ",")) if (!strcmp(addr->addr, next)) { strcpy(cbcp->fsm.phone, next); cbcp->fsm.delay = data->delay; return CBCP_ACTION_ACK; } log_Printf(LogPHASE, "CBCP: peer didn't respond with a " "valid number !\n"); } return CBCP_ACTION_DOWN; } log_Printf(LogPHASE, "Internal CBCP error - agreed on %d !\n", (int)cbcp->fsm.type); return CBCP_ACTION_DOWN; } else if (data->type == CBCP_NONUM && cbcp->fsm.type == CBCP_CLIENTNUM) { /* * Client doesn't want CBCP after all.... * We only allow this when ``set cbcp *'' has been specified. */ cbcp->fsm.type = CBCP_NONUM; return CBCP_ACTION_ACK; } log_Printf(LogCBCP, "Invalid peer RESPONSE\n"); return CBCP_ACTION_REQ; } static void cbcp_SendAck(struct cbcp *cbcp) { struct cbcp_data data; struct cbcp_addr *addr; /* Only callees send ACKs */ log_Printf(LogCBCP, "%s: SendAck(%d) state = %s\n", cbcp->p->dl->name, cbcp->fsm.id, cbcpstate(cbcp->fsm.state)); data.type = cbcp->fsm.type; switch (data.type) { case CBCP_NONUM: data.length = (char *)&data.delay - (char *)&data; break; case CBCP_CLIENTNUM: addr = (struct cbcp_addr *)data.addr_start; addr->type = CBCP_ADDR_PSTN; strcpy(addr->addr, cbcp->fsm.phone); data.delay = cbcp->fsm.delay; data.length = addr->addr + strlen(addr->addr) + 1 - (char *)&data; break; default: data.delay = cbcp->fsm.delay; data.length = data.addr_start - (char *)&data; break; } cbcp_data_Show(&data); cbcp_Output(cbcp, CBCP_ACK, &data); cbcp->fsm.restart--; cbcp_StartTimer(cbcp, cbcp->fsm.delay); cbcp_NewPhase(cbcp, CBCP_ACKSENT); /* Wait for an ACK */ } extern struct mbuf * -cbcp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) +cbcp_Input(struct bundle *bundle __unused, struct link *l, struct mbuf *bp) { struct physical *p = link2physical(l); struct cbcp_header *head; struct cbcp_data *data; struct cbcp *cbcp = &p->dl->cbcp; - int len; + size_t len; if (p == NULL) { log_Printf(LogERROR, "cbcp_Input: Not a physical link - dropped\n"); m_freem(bp); return NULL; } bp = m_pullup(bp); len = m_length(bp); if (len < sizeof(struct cbcp_header)) { m_freem(bp); return NULL; } head = (struct cbcp_header *)MBUF_CTOP(bp); if (ntohs(head->length) != len) { - log_Printf(LogWARN, "Corrupt CBCP packet (code %d, length %d not %d)" + log_Printf(LogWARN, "Corrupt CBCP packet (code %d, length %u not %u)" " - ignored\n", head->code, ntohs(head->length), len); m_freem(bp); return NULL; } m_settype(bp, MB_CBCPIN); /* XXX check the id */ bp->m_offset += sizeof(struct cbcp_header); bp->m_len -= sizeof(struct cbcp_header); data = (struct cbcp_data *)MBUF_CTOP(bp); switch (head->code) { case CBCP_REQ: log_Printf(LogCBCP, "%s: RecvReq(%d) state = %s\n", p->dl->name, head->id, cbcpstate(cbcp->fsm.state)); cbcp_data_Show(data); if (cbcp->fsm.state == CBCP_STOPPED || cbcp->fsm.state == CBCP_RESPSENT) { timer_Stop(&cbcp->fsm.timer); if (cbcp_AdjustResponse(cbcp, data)) { cbcp->fsm.restart = DEF_FSMTRIES; cbcp->fsm.id = head->id; cbcp_SendResponse(cbcp); } else datalink_CBCPFailed(cbcp->p->dl); } else log_Printf(LogCBCP, "%s: unexpected REQ dropped\n", p->dl->name); break; case CBCP_RESPONSE: log_Printf(LogCBCP, "%s: RecvResponse(%d) state = %s\n", p->dl->name, head->id, cbcpstate(cbcp->fsm.state)); cbcp_data_Show(data); if (cbcp->fsm.id != head->id) { log_Printf(LogCBCP, "Warning: Expected id was %d, not %d\n", cbcp->fsm.id, head->id); cbcp->fsm.id = head->id; } if (cbcp->fsm.state == CBCP_REQSENT || cbcp->fsm.state == CBCP_ACKSENT) { timer_Stop(&cbcp->fsm.timer); switch (cbcp_CheckResponse(cbcp, data)) { case CBCP_ACTION_REQ: cbcp_SendReq(cbcp); break; case CBCP_ACTION_ACK: cbcp->fsm.restart = DEF_FSMTRIES; cbcp_SendAck(cbcp); if (cbcp->fsm.type == CBCP_NONUM) { /* * Don't change state in case the peer doesn't get our ACK, * just bring the layer up. */ timer_Stop(&cbcp->fsm.timer); datalink_NCPUp(cbcp->p->dl); } break; default: datalink_CBCPFailed(cbcp->p->dl); break; } } else log_Printf(LogCBCP, "%s: unexpected RESPONSE dropped\n", p->dl->name); break; case CBCP_ACK: log_Printf(LogCBCP, "%s: RecvAck(%d) state = %s\n", p->dl->name, head->id, cbcpstate(cbcp->fsm.state)); cbcp_data_Show(data); if (cbcp->fsm.id != head->id) { log_Printf(LogCBCP, "Warning: Expected id was %d, not %d\n", cbcp->fsm.id, head->id); cbcp->fsm.id = head->id; } if (cbcp->fsm.type == CBCP_NONUM) { /* * Don't change state in case the peer doesn't get our ACK, * just bring the layer up. */ timer_Stop(&cbcp->fsm.timer); datalink_NCPUp(cbcp->p->dl); } else if (cbcp->fsm.state == CBCP_RESPSENT) { timer_Stop(&cbcp->fsm.timer); datalink_CBCPComplete(cbcp->p->dl); log_Printf(LogPHASE, "%s: CBCP: Peer will dial back\n", p->dl->name); } else log_Printf(LogCBCP, "%s: unexpected ACK dropped\n", p->dl->name); break; default: log_Printf(LogWARN, "Unrecognised CBCP packet (code %d, length %d)\n", head->code, len); break; } m_freem(bp); return NULL; } void cbcp_Down(struct cbcp *cbcp) { timer_Stop(&cbcp->fsm.timer); cbcp_NewPhase(cbcp, CBCP_CLOSED); cbcp->required = 0; } void cbcp_ReceiveTerminateReq(struct physical *p) { if (p->dl->cbcp.fsm.state == CBCP_ACKSENT) { /* Don't change our state in case the peer doesn't get the ACK */ p->dl->cbcp.required = 1; log_Printf(LogPHASE, "%s: CBCP: Will dial back on %s\n", p->dl->name, p->dl->cbcp.fsm.phone); } else cbcp_NewPhase(&p->dl->cbcp, CBCP_CLOSED); } Index: head/usr.sbin/ppp/ccp.c =================================================================== --- head/usr.sbin/ppp/ccp.c (revision 134788) +++ head/usr.sbin/ppp/ccp.c (revision 134789) @@ -1,819 +1,822 @@ /*- * Copyright (c) 1996 - 2001 Brian Somers * based on work by Toshiharu OHNO * Internet Initiative Japan, Inc (IIJ) * 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. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include /* memcpy() on some archs */ #include #include "layer.h" #include "defs.h" #include "command.h" #include "mbuf.h" #include "log.h" #include "timer.h" #include "fsm.h" #include "proto.h" #include "pred.h" #include "deflate.h" #include "throughput.h" #include "iplist.h" #include "slcompress.h" #include "lqr.h" #include "hdlc.h" #include "lcp.h" #include "ccp.h" #include "ncpaddr.h" #include "ipcp.h" #include "filter.h" #include "descriptor.h" #include "prompt.h" #include "link.h" #include "mp.h" #include "async.h" #include "physical.h" #ifndef NORADIUS #include "radius.h" #endif #ifndef NODES #include "mppe.h" #endif #include "ipv6cp.h" #include "ncp.h" #include "bundle.h" static void CcpSendConfigReq(struct fsm *); static void CcpSentTerminateReq(struct fsm *); static void CcpSendTerminateAck(struct fsm *, u_char); static void CcpDecodeConfig(struct fsm *, u_char *, u_char *, int, struct fsm_decode *); static void CcpLayerStart(struct fsm *); static void CcpLayerFinish(struct fsm *); static int CcpLayerUp(struct fsm *); static void CcpLayerDown(struct fsm *); static void CcpInitRestartCounter(struct fsm *, int); static int CcpRecvResetReq(struct fsm *); static void CcpRecvResetAck(struct fsm *, u_char); static struct fsm_callbacks ccp_Callbacks = { CcpLayerUp, CcpLayerDown, CcpLayerStart, CcpLayerFinish, CcpInitRestartCounter, CcpSendConfigReq, CcpSentTerminateReq, CcpSendTerminateAck, CcpDecodeConfig, CcpRecvResetReq, CcpRecvResetAck }; static const char * const ccp_TimerNames[] = {"CCP restart", "CCP openmode", "CCP stopped"}; static const char * protoname(int proto) { static char const * const cftypes[] = { /* Check out the latest ``Compression Control Protocol'' rfc (1962) */ "OUI", /* 0: OUI */ "PRED1", /* 1: Predictor type 1 */ "PRED2", /* 2: Predictor type 2 */ "PUDDLE", /* 3: Puddle Jumber */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "HWPPC", /* 16: Hewlett-Packard PPC */ "STAC", /* 17: Stac Electronics LZS (rfc1974) */ "MPPE", /* 18: Microsoft PPC (rfc2118) and */ /* Microsoft PPE (draft-ietf-pppext-mppe) */ "GAND", /* 19: Gandalf FZA (rfc1993) */ "V42BIS", /* 20: ARG->DATA.42bis compression */ "BSD", /* 21: BSD LZW Compress */ NULL, "LZS-DCP", /* 23: LZS-DCP Compression Protocol (rfc1967) */ "MAGNALINK/DEFLATE",/* 24: Magnalink Variable Resource (rfc1975) */ /* 24: Deflate (according to pppd-2.3.*) */ "DCE", /* 25: Data Circuit-Terminating Equip (rfc1976) */ "DEFLATE", /* 26: Deflate (rfc1979) */ }; - if (proto < 0 || proto > sizeof cftypes / sizeof *cftypes || + if (proto < 0 || (unsigned)proto > sizeof cftypes / sizeof *cftypes || cftypes[proto] == NULL) { if (proto == -1) return "none"; return HexStr(proto, NULL, 0); } return cftypes[proto]; } /* We support these algorithms, and Req them in the given order */ static const struct ccp_algorithm * const algorithm[] = { &DeflateAlgorithm, &Pred1Algorithm, &PppdDeflateAlgorithm #ifndef NODES , &MPPEAlgorithm #endif }; #define NALGORITHMS (sizeof algorithm/sizeof algorithm[0]) int ccp_ReportStatus(struct cmdargs const *arg) { struct ccp_opt **o; struct link *l; struct ccp *ccp; int f; l = command_ChooseLink(arg); ccp = &l->ccp; prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name, State2Nam(ccp->fsm.state)); if (ccp->fsm.state == ST_OPENED) { prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n", protoname(ccp->my_proto), protoname(ccp->his_proto)); prompt_Printf(arg->prompt, " Output: %ld --> %ld, Input: %ld --> %ld\n", ccp->uncompout, ccp->compout, ccp->compin, ccp->uncompin); } if (ccp->in.algorithm != -1) prompt_Printf(arg->prompt, "\n Input Options: %s\n", (*algorithm[ccp->in.algorithm]->Disp)(&ccp->in.opt)); if (ccp->out.algorithm != -1) { o = &ccp->out.opt; for (f = 0; f < ccp->out.algorithm; f++) if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg])) o = &(*o)->next; prompt_Printf(arg->prompt, " Output Options: %s\n", (*algorithm[ccp->out.algorithm]->Disp)(&(*o)->val)); } prompt_Printf(arg->prompt, "\n Defaults: "); prompt_Printf(arg->prompt, "FSM retry = %us, max %u Config" " REQ%s, %u Term REQ%s\n", ccp->cfg.fsm.timeout, ccp->cfg.fsm.maxreq, ccp->cfg.fsm.maxreq == 1 ? "" : "s", ccp->cfg.fsm.maxtrm, ccp->cfg.fsm.maxtrm == 1 ? "" : "s"); prompt_Printf(arg->prompt, " deflate windows: "); prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize); prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize); #ifndef NODES prompt_Printf(arg->prompt, " MPPE: "); if (ccp->cfg.mppe.keybits) prompt_Printf(arg->prompt, "%d bits, ", ccp->cfg.mppe.keybits); else prompt_Printf(arg->prompt, "any bits, "); switch (ccp->cfg.mppe.state) { case MPPE_STATEFUL: prompt_Printf(arg->prompt, "stateful"); break; case MPPE_STATELESS: prompt_Printf(arg->prompt, "stateless"); break; case MPPE_ANYSTATE: prompt_Printf(arg->prompt, "any state"); break; } prompt_Printf(arg->prompt, "%s\n", ccp->cfg.mppe.required ? ", required" : ""); #endif prompt_Printf(arg->prompt, "\n DEFLATE: %s\n", command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE])); prompt_Printf(arg->prompt, " PREDICTOR1: %s\n", command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1])); prompt_Printf(arg->prompt, " DEFLATE24: %s\n", command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24])); #ifndef NODES prompt_Printf(arg->prompt, " MPPE: %s\n", command_ShowNegval(ccp->cfg.neg[CCP_NEG_MPPE])); #endif return 0; } void ccp_SetupCallbacks(struct ccp *ccp) { ccp->fsm.fn = &ccp_Callbacks; ccp->fsm.FsmTimer.name = ccp_TimerNames[0]; ccp->fsm.OpenTimer.name = ccp_TimerNames[1]; ccp->fsm.StoppedTimer.name = ccp_TimerNames[2]; } 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, 1, CCP_MAXCODE, LogCCP, bundle, l, parent, &ccp_Callbacks, ccp_TimerNames); ccp->cfg.deflate.in.winsize = 0; ccp->cfg.deflate.out.winsize = 15; ccp->cfg.fsm.timeout = DEF_FSMRETRY; ccp->cfg.fsm.maxreq = DEF_FSMTRIES; ccp->cfg.fsm.maxtrm = DEF_FSMTRIES; ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED; ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED; ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0; #ifndef NODES ccp->cfg.mppe.keybits = 0; ccp->cfg.mppe.state = MPPE_ANYSTATE; ccp->cfg.mppe.required = 0; ccp->cfg.neg[CCP_NEG_MPPE] = NEG_ENABLED|NEG_ACCEPTED; #endif ccp_Setup(ccp); } void ccp_Setup(struct ccp *ccp) { /* Set ourselves up for a startup */ ccp->fsm.open_mode = 0; ccp->his_proto = ccp->my_proto = -1; ccp->reset_sent = ccp->last_reset = -1; ccp->in.algorithm = ccp->out.algorithm = -1; ccp->in.state = ccp->out.state = NULL; ccp->in.opt.hdr.id = -1; ccp->out.opt = NULL; ccp->his_reject = ccp->my_reject = 0; ccp->uncompout = ccp->compout = 0; ccp->uncompin = ccp->compin = 0; } /* * Is ccp *REQUIRED* ? * We ask each of the configured ccp protocols if they're required and * return TRUE if they are. * * It's not possible for the peer to reject a required ccp protocol * without our state machine bringing the supporting lcp layer down. * * If ccp is required but not open, the NCP layer should not push * any data into the link. */ int ccp_Required(struct ccp *ccp) { - int f; + unsigned f; for (f = 0; f < NALGORITHMS; f++) if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) && (*algorithm[f]->Required)(&ccp->fsm)) return 1; return 0; } /* * Report whether it's possible to increase a packet's size after * compression (and by how much). */ int ccp_MTUOverhead(struct ccp *ccp) { if (ccp->fsm.state == ST_OPENED && ccp->out.algorithm >= 0) return algorithm[ccp->out.algorithm]->o.MTUOverhead; return 0; } static void CcpInitRestartCounter(struct fsm *fp, int what) { /* Set fsm timer load */ struct ccp *ccp = fsm2ccp(fp); fp->FsmTimer.load = ccp->cfg.fsm.timeout * SECTICKS; switch (what) { case FSM_REQ_TIMER: fp->restart = ccp->cfg.fsm.maxreq; break; case FSM_TRM_TIMER: fp->restart = ccp->cfg.fsm.maxtrm; break; default: fp->restart = 1; break; } } static void CcpSendConfigReq(struct fsm *fp) { /* Send config REQ please */ struct ccp *ccp = fsm2ccp(fp); struct ccp_opt **o; u_char *cp, buff[100]; - int f, alloc; + unsigned f; + int alloc; cp = buff; o = &ccp->out.opt; alloc = ccp->his_reject == 0 && ccp->out.opt == NULL; ccp->my_proto = -1; ccp->out.algorithm = -1; for (f = 0; f < NALGORITHMS; f++) if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) && !REJECTED(ccp, algorithm[f]->id) && (*algorithm[f]->Usable)(fp)) { if (!alloc) for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next) - if ((*o)->val.hdr.id == algorithm[f]->id && (*o)->algorithm == f) + if ((*o)->val.hdr.id == algorithm[f]->id && (*o)->algorithm == (int)f) break; if (alloc || *o == NULL) { *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt)); (*o)->val.hdr.id = algorithm[f]->id; (*o)->val.hdr.len = 2; (*o)->next = NULL; (*o)->algorithm = f; (*algorithm[f]->o.OptInit)(fp->bundle, &(*o)->val, &ccp->cfg); } if (cp + (*o)->val.hdr.len > buff + sizeof buff) { log_Printf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name); break; } memcpy(cp, &(*o)->val, (*o)->val.hdr.len); cp += (*o)->val.hdr.len; ccp->my_proto = (*o)->val.hdr.id; ccp->out.algorithm = f; if (alloc) o = &(*o)->next; } fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff, MB_CCPOUT); } void ccp_SendResetReq(struct fsm *fp) { /* We can't read our input - ask peer to reset */ struct ccp *ccp = fsm2ccp(fp); ccp->reset_sent = fp->reqid; ccp->last_reset = -1; fsm_Output(fp, CODE_RESETREQ, fp->reqid, NULL, 0, MB_CCPOUT); } static void -CcpSentTerminateReq(struct fsm *fp) +CcpSentTerminateReq(struct fsm *fp __unused) { /* Term REQ just sent by FSM */ } static void CcpSendTerminateAck(struct fsm *fp, u_char id) { /* Send Term ACK please */ fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_CCPOUT); } static int CcpRecvResetReq(struct fsm *fp) { /* Got a reset REQ, reset outgoing dictionary */ struct ccp *ccp = fsm2ccp(fp); if (ccp->out.state == NULL) return 1; return (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state); } static void CcpLayerStart(struct fsm *fp) { /* We're about to start up ! */ struct ccp *ccp = fsm2ccp(fp); log_Printf(LogCCP, "%s: LayerStart.\n", fp->link->name); fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3; } static void CcpLayerDown(struct fsm *fp) { /* About to come down */ struct ccp *ccp = fsm2ccp(fp); struct ccp_opt *next; log_Printf(LogCCP, "%s: LayerDown.\n", fp->link->name); if (ccp->in.state != NULL) { (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state); ccp->in.state = NULL; ccp->in.algorithm = -1; } if (ccp->out.state != NULL) { (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state); ccp->out.state = NULL; ccp->out.algorithm = -1; } ccp->his_reject = ccp->my_reject = 0; while (ccp->out.opt) { next = ccp->out.opt->next; free(ccp->out.opt); ccp->out.opt = next; } ccp_Setup(ccp); } static void CcpLayerFinish(struct fsm *fp) { /* We're now down */ struct ccp *ccp = fsm2ccp(fp); struct ccp_opt *next; log_Printf(LogCCP, "%s: LayerFinish.\n", fp->link->name); /* * Nuke options that may be left over from sending a REQ but never * coming up. */ while (ccp->out.opt) { next = ccp->out.opt->next; free(ccp->out.opt); ccp->out.opt = next; } if (ccp_Required(ccp)) { if (fp->link->lcp.fsm.state == ST_OPENED) log_Printf(LogLCP, "%s: Closing due to CCP completion\n", fp->link->name); fsm_Close(&fp->link->lcp.fsm); } } /* Called when CCP has reached the OPEN state */ static int CcpLayerUp(struct fsm *fp) { /* We're now up */ struct ccp *ccp = fsm2ccp(fp); struct ccp_opt **o; - int f, fail; + unsigned f, fail; for (f = fail = 0; f < NALGORITHMS; f++) if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) && (*algorithm[f]->Required)(&ccp->fsm) && - (ccp->in.algorithm != f || ccp->out.algorithm != f)) { + (ccp->in.algorithm != (int)f || ccp->out.algorithm != (int)f)) { /* Blow it all away - we haven't negotiated a required algorithm */ log_Printf(LogWARN, "%s: Failed to negotiate (required) %s\n", fp->link->name, protoname(algorithm[f]->id)); fail = 1; } if (fail) { ccp->his_proto = ccp->my_proto = -1; fsm_Close(fp); fsm_Close(&fp->link->lcp.fsm); return 0; } log_Printf(LogCCP, "%s: LayerUp.\n", fp->link->name); if (ccp->in.state == NULL && ccp->in.algorithm >= 0 && - ccp->in.algorithm < NALGORITHMS) { + ccp->in.algorithm < (int)NALGORITHMS) { ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init) (fp->bundle, &ccp->in.opt); if (ccp->in.state == NULL) { log_Printf(LogERROR, "%s: %s (in) initialisation failure\n", fp->link->name, protoname(ccp->his_proto)); ccp->his_proto = ccp->my_proto = -1; fsm_Close(fp); return 0; } } o = &ccp->out.opt; - for (f = 0; f < ccp->out.algorithm; f++) - if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg])) - o = &(*o)->next; + if (ccp->out.algorithm > 0) + for (f = 0; f < (unsigned)ccp->out.algorithm; f++) + if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg])) + o = &(*o)->next; if (ccp->out.state == NULL && ccp->out.algorithm >= 0 && - ccp->out.algorithm < NALGORITHMS) { + ccp->out.algorithm < (int)NALGORITHMS) { ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init) (fp->bundle, &(*o)->val); if (ccp->out.state == NULL) { log_Printf(LogERROR, "%s: %s (out) initialisation failure\n", fp->link->name, protoname(ccp->my_proto)); ccp->his_proto = ccp->my_proto = -1; fsm_Close(fp); return 0; } } fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3; log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n", fp->link->name, protoname(ccp->my_proto), ccp->my_proto, protoname(ccp->his_proto), ccp->his_proto); return 1; } static void CcpDecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type, struct fsm_decode *dec) { /* Deal with incoming data */ struct ccp *ccp = fsm2ccp(fp); int f; const char *disp; struct fsm_opt *opt; if (mode_type == MODE_REQ) ccp->in.algorithm = -1; /* In case we've received two REQs in a row */ - while (end - cp >= sizeof(opt->hdr)) { + while (end >= cp + sizeof(opt->hdr)) { if ((opt = fsm_readopt(&cp)) == NULL) break; for (f = NALGORITHMS-1; f > -1; f--) if (algorithm[f]->id == opt->hdr.id) break; disp = f == -1 ? "" : (*algorithm[f]->Disp)(opt); if (disp == NULL) disp = ""; log_Printf(LogCCP, " %s[%d] %s\n", protoname(opt->hdr.id), opt->hdr.len, disp); if (f == -1) { /* Don't understand that :-( */ if (mode_type == MODE_REQ) { ccp->my_reject |= (1 << opt->hdr.id); fsm_rej(dec, opt); } } else { struct ccp_opt *o; switch (mode_type) { case MODE_REQ: if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) && (*algorithm[f]->Usable)(fp) && ccp->in.algorithm == -1) { memcpy(&ccp->in.opt, opt, opt->hdr.len); switch ((*algorithm[f]->i.Set)(fp->bundle, &ccp->in.opt, &ccp->cfg)) { case MODE_REJ: fsm_rej(dec, &ccp->in.opt); break; case MODE_NAK: fsm_nak(dec, &ccp->in.opt); break; case MODE_ACK: fsm_ack(dec, &ccp->in.opt); ccp->his_proto = opt->hdr.id; - ccp->in.algorithm = f; /* This one'll do :-) */ + ccp->in.algorithm = (int)f; /* This one'll do :-) */ break; } } else { fsm_rej(dec, opt); } break; case MODE_NAK: for (o = ccp->out.opt; o != NULL; o = o->next) if (o->val.hdr.id == opt->hdr.id) break; if (o == NULL) log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent" " option\n", fp->link->name); else { memcpy(&o->val, opt, opt->hdr.len); if ((*algorithm[f]->o.Set)(fp->bundle, &o->val, &ccp->cfg) == MODE_ACK) ccp->my_proto = algorithm[f]->id; else { ccp->his_reject |= (1 << opt->hdr.id); ccp->my_proto = -1; if (algorithm[f]->Required(fp)) { log_Printf(LogWARN, "%s: Cannot understand peers (required)" " %s negotiation\n", fp->link->name, protoname(algorithm[f]->id)); fsm_Close(&fp->link->lcp.fsm); } } } break; case MODE_REJ: ccp->his_reject |= (1 << opt->hdr.id); ccp->my_proto = -1; if (algorithm[f]->Required(fp)) { log_Printf(LogWARN, "%s: Peer rejected (required) %s negotiation\n", fp->link->name, protoname(algorithm[f]->id)); fsm_Close(&fp->link->lcp.fsm); } break; } } } if (mode_type != MODE_NOP) { fsm_opt_normalise(dec); if (dec->rejend != dec->rej || dec->nakend != dec->nak) { if (ccp->in.state == NULL) { ccp->his_proto = -1; ccp->in.algorithm = -1; } } } } extern struct mbuf * ccp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) { /* Got PROTO_CCP from link */ m_settype(bp, MB_CCPIN); if (bundle_Phase(bundle) == PHASE_NETWORK) fsm_Input(&l->ccp.fsm, bp); else { if (bundle_Phase(bundle) < PHASE_NETWORK) log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n", l->ccp.fsm.link->name, bundle_PhaseName(bundle)); m_freem(bp); } return NULL; } 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) { log_Printf(LogCCP, "%s: Incorrect ResetAck (id %d, not %d)" " ignored\n", fp->link->name, id, ccp->reset_sent); return; } /* Whaddaya know - a correct reset ack */ } else if (id == ccp->last_reset) log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n", fp->link->name); else { log_Printf(LogCCP, "%s: Unexpected ResetAck (id %d) ignored\n", fp->link->name, id); return; } ccp->last_reset = ccp->reset_sent; ccp->reset_sent = -1; if (ccp->in.state != NULL) (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state); } static struct mbuf * -ccp_LayerPush(struct bundle *b, struct link *l, struct mbuf *bp, +ccp_LayerPush(struct bundle *b __unused, struct link *l, struct mbuf *bp, int pri, u_short *proto) { if (PROTO_COMPRESSIBLE(*proto)) { if (l->ccp.fsm.state != ST_OPENED) { if (ccp_Required(&l->ccp)) { /* The NCP layer shouldn't have let this happen ! */ log_Printf(LogERROR, "%s: Unexpected attempt to use an unopened and" " required CCP layer\n", l->name); m_freem(bp); bp = NULL; } } else if (l->ccp.out.state != NULL) { bp = (*algorithm[l->ccp.out.algorithm]->o.Write) (l->ccp.out.state, &l->ccp, l, pri, proto, bp); switch (*proto) { case PROTO_ICOMPD: m_settype(bp, MB_ICOMPDOUT); break; case PROTO_COMPD: m_settype(bp, MB_COMPDOUT); break; } } } return bp; } static struct mbuf * -ccp_LayerPull(struct bundle *b, struct link *l, struct mbuf *bp, u_short *proto) +ccp_LayerPull(struct bundle *b __unused, struct link *l, struct mbuf *bp, + u_short *proto) { /* * If proto isn't PROTO_[I]COMPD, we still want to pass it to the * decompression routines so that the dictionary's updated */ if (l->ccp.fsm.state == ST_OPENED) { if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) { /* Decompress incoming data */ if (l->ccp.reset_sent != -1) /* Send another REQ and put the packet in the bit bucket */ fsm_Output(&l->ccp.fsm, CODE_RESETREQ, l->ccp.reset_sent, NULL, 0, MB_CCPOUT); else if (l->ccp.in.state != NULL) { bp = (*algorithm[l->ccp.in.algorithm]->i.Read) (l->ccp.in.state, &l->ccp, proto, bp); switch (*proto) { case PROTO_ICOMPD: m_settype(bp, MB_ICOMPDIN); break; case PROTO_COMPD: m_settype(bp, MB_COMPDIN); break; } return bp; } m_freem(bp); bp = NULL; } else if (PROTO_COMPRESSIBLE(*proto) && l->ccp.in.state != NULL) { /* Add incoming Network Layer traffic to our dictionary */ (*algorithm[l->ccp.in.algorithm]->i.DictSetup) (l->ccp.in.state, &l->ccp, *proto, bp); } } return bp; } u_short ccp_Proto(struct ccp *ccp) { return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ? PROTO_COMPD : PROTO_ICOMPD; } int ccp_SetOpenMode(struct ccp *ccp) { int f; for (f = 0; f < CCP_NEG_TOTAL; f++) if (IsEnabled(ccp->cfg.neg[f])) { ccp->fsm.open_mode = 0; return 1; } ccp->fsm.open_mode = OPEN_PASSIVE; /* Go straight to ST_STOPPED ? */ for (f = 0; f < CCP_NEG_TOTAL; f++) if (IsAccepted(ccp->cfg.neg[f])) return 1; return 0; /* No CCP at all */ } int -ccp_DefaultUsable(struct fsm *fp) +ccp_DefaultUsable(struct fsm *fp __unused) { return 1; } int -ccp_DefaultRequired(struct fsm *fp) +ccp_DefaultRequired(struct fsm *fp __unused) { return 0; } struct layer ccplayer = { LAYER_CCP, "ccp", ccp_LayerPush, ccp_LayerPull }; Index: head/usr.sbin/ppp/chap.c =================================================================== --- head/usr.sbin/ppp/chap.c (revision 134788) +++ head/usr.sbin/ppp/chap.c (revision 134789) @@ -1,967 +1,972 @@ /*- * Copyright (c) 1996 - 2001 Brian Somers * based on work by Toshiharu OHNO * Internet Initiative Japan, Inc (IIJ) * 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. * * $FreeBSD$ */ #include #include #include #include #include #include +#include #include #include #ifndef NODES #include #endif #include #include #include #include #include #include #include #include #include #include "layer.h" #include "mbuf.h" #include "log.h" #include "defs.h" #include "timer.h" #include "fsm.h" #include "proto.h" #include "lqr.h" #include "hdlc.h" #include "lcp.h" #include "auth.h" #include "async.h" #include "throughput.h" #include "descriptor.h" #include "chap.h" #include "iplist.h" #include "slcompress.h" #include "ncpaddr.h" #include "ipcp.h" #include "filter.h" #include "ccp.h" #include "link.h" #include "physical.h" #include "mp.h" #ifndef NORADIUS #include "radius.h" #endif #include "ipv6cp.h" #include "ncp.h" #include "bundle.h" #include "chat.h" #include "cbcp.h" #include "command.h" #include "datalink.h" #ifndef NODES #include "chap_ms.h" #include "mppe.h" #endif #include "id.h" static const char * const chapcodes[] = { "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE" }; #define MAXCHAPCODE (sizeof chapcodes / sizeof chapcodes[0] - 1) static void ChapOutput(struct physical *physical, u_int code, u_int id, const u_char *ptr, int count, const char *text) { int plen; struct fsmheader lh; struct mbuf *bp; plen = sizeof(struct fsmheader) + count; lh.code = code; lh.id = id; lh.length = htons(plen); bp = m_get(plen, MB_CHAPOUT); memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); if (count) memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); log_DumpBp(LogDEBUG, "ChapOutput", bp); if (text == NULL) log_Printf(LogPHASE, "Chap Output: %s\n", chapcodes[code]); else log_Printf(LogPHASE, "Chap Output: %s (%s)\n", chapcodes[code], text); link_PushPacket(&physical->link, bp, physical->dl->bundle, LINK_QUEUES(&physical->link) - 1, PROTO_CHAP); } static char * -chap_BuildAnswer(char *name, char *key, u_char id, char *challenge, u_char type +chap_BuildAnswer(char *name, char *key, u_char id, char *challenge #ifndef NODES - , char *peerchallenge, char *authresponse, int lanman + , u_char type, char *peerchallenge, char *authresponse, + int lanman #endif ) { char *result, *digest; size_t nlen, klen; nlen = strlen(name); klen = strlen(key); #ifndef NODES if (type == 0x80) { char expkey[AUTHLEN << 2]; MD4_CTX MD4context; - int f; + size_t f; if ((result = malloc(1 + nlen + MS_CHAP_RESPONSE_LEN)) == NULL) return result; digest = result; /* the response */ *digest++ = MS_CHAP_RESPONSE_LEN; /* 49 */ memcpy(digest + MS_CHAP_RESPONSE_LEN, name, nlen); if (lanman) { memset(digest + 24, '\0', 25); mschap_LANMan(digest, challenge + 1, key); /* LANMan response */ } else { memset(digest, '\0', 25); digest += 24; for (f = 0; f < klen; f++) { expkey[2*f] = key[f]; expkey[2*f+1] = '\0'; } /* * ----------- * expkey = | k\0e\0y\0 | * ----------- */ MD4Init(&MD4context); MD4Update(&MD4context, expkey, klen << 1); MD4Final(digest, &MD4context); /* * ---- -------- ---------------- ------- ------ * result = | 49 | LANMan | 16 byte digest | 9 * ? | name | * ---- -------- ---------------- ------- ------ */ mschap_NT(digest, challenge + 1); } /* * ---- -------- ------------- ----- ------ * | | struct MS_ChapResponse24 | | * result = | 49 | LANMan | NT digest | 0/1 | name | * ---- -------- ------------- ----- ------ * where only one of LANMan & NT digest are set. */ } else if (type == 0x81) { char expkey[AUTHLEN << 2]; char pwdhash[CHAP81_HASH_LEN]; char pwdhashhash[CHAP81_HASH_LEN]; char *ntresponse; - int f; + size_t f; if ((result = malloc(1 + nlen + CHAP81_RESPONSE_LEN)) == NULL) return result; memset(result, 0, 1 + nlen + CHAP81_RESPONSE_LEN); digest = result; *digest++ = CHAP81_RESPONSE_LEN; /* value size */ /* Copy our challenge */ memcpy(digest, peerchallenge + 1, CHAP81_CHALLENGE_LEN); /* Expand password to Unicode XXX */ for (f = 0; f < klen; f++) { expkey[2*f] = key[f]; expkey[2*f+1] = '\0'; } ntresponse = digest + CHAP81_NTRESPONSE_OFF; /* Get some needed hashes */ NtPasswordHash(expkey, klen * 2, pwdhash); HashNtPasswordHash(pwdhash, pwdhashhash); /* Generate NTRESPONSE to respond on challenge call */ - GenerateNTResponse(challenge + 1, peerchallenge + 1, name, nlen, + GenerateNTResponse(challenge + 1, peerchallenge + 1, name, expkey, klen * 2, ntresponse); /* Generate MPPE MASTERKEY */ GetMasterKey(pwdhashhash, ntresponse, MPPE_MasterKey); /* XXX Global ! */ /* Generate AUTHRESPONSE to verify on auth success */ GenerateAuthenticatorResponse(expkey, klen * 2, ntresponse, - peerchallenge + 1, challenge + 1, name, nlen, + peerchallenge + 1, challenge + 1, name, authresponse); authresponse[CHAP81_AUTHRESPONSE_LEN] = 0; memcpy(digest + CHAP81_RESPONSE_LEN, name, nlen); } else #endif if ((result = malloc(nlen + 17)) != NULL) { /* Normal MD5 stuff */ MD5_CTX MD5context; digest = result; *digest++ = 16; /* value size */ MD5Init(&MD5context); MD5Update(&MD5context, &id, 1); MD5Update(&MD5context, key, klen); MD5Update(&MD5context, challenge + 1, *challenge); MD5Final(digest, &MD5context); memcpy(digest + 16, name, nlen); /* * ---- -------- ------ * result = | 16 | digest | name | * ---- -------- ------ */ } return result; } static void chap_StartChild(struct chap *chap, char *prog, const char *name) { char *argv[MAXARGS], *nargv[MAXARGS]; int argc, fd; int in[2], out[2]; pid_t pid; if (chap->child.fd != -1) { log_Printf(LogWARN, "Chap: %s: Program already running\n", prog); return; } if (pipe(in) == -1) { log_Printf(LogERROR, "Chap: pipe: %s\n", strerror(errno)); return; } if (pipe(out) == -1) { log_Printf(LogERROR, "Chap: pipe: %s\n", strerror(errno)); close(in[0]); close(in[1]); return; } pid = getpid(); switch ((chap->child.pid = fork())) { case -1: log_Printf(LogERROR, "Chap: fork: %s\n", strerror(errno)); close(in[0]); close(in[1]); close(out[0]); close(out[1]); chap->child.pid = 0; return; case 0: timer_TermService(); if ((argc = command_Interpret(prog, strlen(prog), argv)) <= 0) { if (argc < 0) { log_Printf(LogWARN, "CHAP: Invalid command syntax\n"); _exit(255); } _exit(0); } close(in[1]); close(out[0]); if (out[1] == STDIN_FILENO) out[1] = dup(out[1]); dup2(in[0], STDIN_FILENO); dup2(out[1], STDOUT_FILENO); close(STDERR_FILENO); if (open(_PATH_DEVNULL, O_RDWR) != STDERR_FILENO) { log_Printf(LogALERT, "Chap: Failed to open %s: %s\n", _PATH_DEVNULL, strerror(errno)); exit(1); } for (fd = getdtablesize(); fd > STDERR_FILENO; fd--) fcntl(fd, F_SETFD, 1); #ifndef NOSUID setuid(ID0realuid()); #endif command_Expand(nargv, argc, (char const *const *)argv, chap->auth.physical->dl->bundle, 0, pid); execvp(nargv[0], nargv); printf("exec() of %s failed: %s\n", nargv[0], strerror(errno)); _exit(255); default: close(in[0]); close(out[1]); chap->child.fd = out[0]; chap->child.buf.len = 0; write(in[1], chap->auth.in.name, strlen(chap->auth.in.name)); write(in[1], "\n", 1); write(in[1], chap->challenge.peer + 1, *chap->challenge.peer); write(in[1], "\n", 1); write(in[1], name, strlen(name)); write(in[1], "\n", 1); close(in[1]); break; } } static void chap_Cleanup(struct chap *chap, int sig) { if (chap->child.pid) { int status; close(chap->child.fd); chap->child.fd = -1; if (sig) kill(chap->child.pid, SIGTERM); chap->child.pid = 0; chap->child.buf.len = 0; if (wait(&status) == -1) log_Printf(LogERROR, "Chap: wait: %s\n", strerror(errno)); else if (WIFSIGNALED(status)) log_Printf(LogWARN, "Chap: Child received signal %d\n", WTERMSIG(status)); else if (WIFEXITED(status) && WEXITSTATUS(status)) log_Printf(LogERROR, "Chap: Child exited %d\n", WEXITSTATUS(status)); } *chap->challenge.local = *chap->challenge.peer = '\0'; #ifndef NODES chap->peertries = 0; #endif } static void -chap_Respond(struct chap *chap, char *name, char *key, u_char type +chap_Respond(struct chap *chap, char *name, char *key #ifndef NODES - , int lm + , u_char type, int lm #endif ) { u_char *ans; - ans = chap_BuildAnswer(name, key, chap->auth.id, chap->challenge.peer, type + ans = chap_BuildAnswer(name, key, chap->auth.id, chap->challenge.peer #ifndef NODES - , chap->challenge.local, chap->authresponse, lm + , type, chap->challenge.local, chap->authresponse, lm #endif ); if (ans) { ChapOutput(chap->auth.physical, CHAP_RESPONSE, chap->auth.id, ans, *ans + 1 + strlen(name), name); #ifndef NODES chap->NTRespSent = !lm; MPPE_IsServer = 0; /* XXX Global ! */ #endif free(ans); } else ChapOutput(chap->auth.physical, CHAP_FAILURE, chap->auth.id, "Out of memory!", 14, NULL); } static int -chap_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) +chap_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w __unused, + fd_set *e __unused, int *n) { struct chap *chap = descriptor2chap(d); if (r && chap && chap->child.fd != -1) { FD_SET(chap->child.fd, r); if (*n < chap->child.fd + 1) *n = chap->child.fd + 1; log_Printf(LogTIMER, "Chap: fdset(r) %d\n", chap->child.fd); return 1; } return 0; } static int chap_IsSet(struct fdescriptor *d, const fd_set *fdset) { struct chap *chap = descriptor2chap(d); return chap && chap->child.fd != -1 && FD_ISSET(chap->child.fd, fdset); } static void -chap_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) +chap_Read(struct fdescriptor *d, struct bundle *bundle __unused, + const fd_set *fdset __unused) { struct chap *chap = descriptor2chap(d); int got; got = read(chap->child.fd, chap->child.buf.ptr + chap->child.buf.len, sizeof chap->child.buf.ptr - chap->child.buf.len - 1); if (got == -1) { log_Printf(LogERROR, "Chap: Read: %s\n", strerror(errno)); chap_Cleanup(chap, SIGTERM); } else if (got == 0) { log_Printf(LogWARN, "Chap: Read: Child terminated connection\n"); chap_Cleanup(chap, SIGTERM); } else { char *name, *key, *end; chap->child.buf.len += got; chap->child.buf.ptr[chap->child.buf.len] = '\0'; name = chap->child.buf.ptr; name += strspn(name, " \t"); if ((key = strchr(name, '\n')) == NULL) end = NULL; else end = strchr(++key, '\n'); if (end == NULL) { if (chap->child.buf.len == sizeof chap->child.buf.ptr - 1) { log_Printf(LogWARN, "Chap: Read: Input buffer overflow\n"); chap_Cleanup(chap, SIGTERM); } } else { #ifndef NODES int lanman = chap->auth.physical->link.lcp.his_authtype == 0x80 && ((chap->NTRespSent && IsAccepted(chap->auth.physical->link.lcp.cfg.chap80lm)) || !IsAccepted(chap->auth.physical->link.lcp.cfg.chap80nt)); #endif while (end >= name && strchr(" \t\r\n", *end)) *end-- = '\0'; end = key - 1; while (end >= name && strchr(" \t\r\n", *end)) *end-- = '\0'; key += strspn(key, " \t"); - chap_Respond(chap, name, key, chap->auth.physical->link.lcp.his_authtype + chap_Respond(chap, name, key #ifndef NODES - , lanman + , chap->auth.physical->link.lcp.his_authtype, lanman #endif ); chap_Cleanup(chap, 0); } } } static int -chap_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) +chap_Write(struct fdescriptor *d __unused, struct bundle *bundle __unused, + const fd_set *fdset __unused) { /* We never want to write here ! */ log_Printf(LogALERT, "chap_Write: Internal error: Bad call !\n"); return 0; } static void chap_ChallengeInit(struct authinfo *authp) { struct chap *chap = auth2chap(authp); int len, i; char *cp; len = strlen(authp->physical->dl->bundle->cfg.auth.name); if (!*chap->challenge.local) { randinit(); cp = chap->challenge.local; #ifndef NORADIUS if (*authp->physical->dl->bundle->radius.cfg.file) { /* For radius, our challenge is 16 readable NUL terminated bytes :*/ *cp++ = 16; for (i = 0; i < 16; i++) *cp++ = (random() % 10) + '0'; } else #endif { #ifndef NODES if (authp->physical->link.lcp.want_authtype == 0x80) *cp++ = 8; /* MS does 8 byte callenges :-/ */ else if (authp->physical->link.lcp.want_authtype == 0x81) *cp++ = 16; /* MS-CHAP-V2 does 16 bytes challenges */ else #endif *cp++ = random() % (CHAPCHALLENGELEN-16) + 16; for (i = 0; i < *chap->challenge.local; i++) *cp++ = random() & 0xff; } memcpy(cp, authp->physical->dl->bundle->cfg.auth.name, len); } } static void chap_Challenge(struct authinfo *authp) { struct chap *chap = auth2chap(authp); int len; log_Printf(LogDEBUG, "CHAP%02X: Challenge\n", authp->physical->link.lcp.want_authtype); len = strlen(authp->physical->dl->bundle->cfg.auth.name); /* Generate new local challenge value */ if (!*chap->challenge.local) chap_ChallengeInit(authp); #ifndef NODES if (authp->physical->link.lcp.want_authtype == 0x81) ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id, chap->challenge.local, 1 + *chap->challenge.local, NULL); else #endif ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id, chap->challenge.local, 1 + *chap->challenge.local + len, NULL); } static void chap_Success(struct authinfo *authp) { struct bundle *bundle = authp->physical->dl->bundle; const char *msg; datalink_GotAuthname(authp->physical->dl, authp->in.name); #ifndef NODES if (authp->physical->link.lcp.want_authtype == 0x81) { #ifndef NORADIUS if (*bundle->radius.cfg.file && bundle->radius.msrepstr) msg = bundle->radius.msrepstr; else #endif msg = auth2chap(authp)->authresponse; MPPE_MasterKeyValid = 1; /* XXX Global ! */ } else #endif #ifndef NORADIUS if (*bundle->radius.cfg.file && bundle->radius.repstr) msg = bundle->radius.repstr; else #endif msg = "Welcome!!"; ChapOutput(authp->physical, CHAP_SUCCESS, authp->id, msg, strlen(msg), NULL); authp->physical->link.lcp.auth_ineed = 0; if (Enabled(bundle, OPT_UTMP)) physical_Login(authp->physical, authp->in.name); if (authp->physical->link.lcp.auth_iwait == 0) /* * Either I didn't need to authenticate, or I've already been * told that I got the answer right. */ datalink_AuthOk(authp->physical->dl); } static void chap_Failure(struct authinfo *authp) { #ifndef NODES char buf[1024], *ptr; #endif const char *msg; #ifndef NORADIUS struct bundle *bundle = authp->physical->link.lcp.fsm.bundle; if (*bundle->radius.cfg.file && bundle->radius.errstr) msg = bundle->radius.errstr; else #endif #ifndef NODES if (authp->physical->link.lcp.want_authtype == 0x80) { sprintf(buf, "E=691 R=1 M=Invalid!"); msg = buf; } else if (authp->physical->link.lcp.want_authtype == 0x81) { int i; ptr = buf; ptr += sprintf(buf, "E=691 R=0 C="); for (i=0; i<16; i++) ptr += sprintf(ptr, "%02X", *(auth2chap(authp)->challenge.local+1+i)); sprintf(ptr, " V=3 M=Invalid!"); msg = buf; } else #endif msg = "Invalid!!"; ChapOutput(authp->physical, CHAP_FAILURE, authp->id, msg, strlen(msg) + 1, NULL); datalink_AuthNotOk(authp->physical->dl); } static int -chap_Cmp(u_char type, char *myans, int mylen, char *hisans, int hislen +chap_Cmp(char *myans, int mylen, char *hisans, int hislen #ifndef NODES - , int lm + , u_char type, int lm #endif ) { int off; if (mylen != hislen) return 0; off = 0; #ifndef NODES if (type == 0x80) { off = lm ? 0 : 24; mylen = 24; } #endif for (; mylen; off++, mylen--) if (toupper(myans[off]) != toupper(hisans[off])) return 0; return 1; } #ifndef NODES static int chap_HaveAnotherGo(struct chap *chap) { if (++chap->peertries < 3) { /* Give the peer another shot */ *chap->challenge.local = '\0'; chap_Challenge(&chap->auth); return 1; } return 0; } #endif void chap_Init(struct chap *chap, struct physical *p) { chap->desc.type = CHAP_DESCRIPTOR; chap->desc.UpdateSet = chap_UpdateSet; chap->desc.IsSet = chap_IsSet; chap->desc.Read = chap_Read; chap->desc.Write = chap_Write; chap->child.pid = 0; chap->child.fd = -1; auth_Init(&chap->auth, p, chap_Challenge, chap_Success, chap_Failure); *chap->challenge.local = *chap->challenge.peer = '\0'; #ifndef NODES chap->NTRespSent = 0; chap->peertries = 0; #endif } void chap_ReInit(struct chap *chap) { chap_Cleanup(chap, SIGTERM); } struct mbuf * chap_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) { struct physical *p = link2physical(l); struct chap *chap = &p->dl->chap; char *name, *key, *ans; - int len, nlen; + int len; + size_t nlen; u_char alen; #ifndef NODES int lanman; #endif if (p == NULL) { log_Printf(LogERROR, "chap_Input: Not a physical link - dropped\n"); m_freem(bp); return NULL; } if (bundle_Phase(bundle) != PHASE_NETWORK && bundle_Phase(bundle) != PHASE_AUTHENTICATE) { log_Printf(LogPHASE, "Unexpected chap input - dropped !\n"); m_freem(bp); return NULL; } m_settype(bp, MB_CHAPIN); if ((bp = auth_ReadHeader(&chap->auth, bp)) == NULL && ntohs(chap->auth.in.hdr.length) == 0) log_Printf(LogWARN, "Chap Input: Truncated header !\n"); else if (chap->auth.in.hdr.code == 0 || chap->auth.in.hdr.code > MAXCHAPCODE) log_Printf(LogPHASE, "Chap Input: %d: Bad CHAP code !\n", chap->auth.in.hdr.code); else { len = m_length(bp); ans = NULL; if (chap->auth.in.hdr.code != CHAP_CHALLENGE && chap->auth.id != chap->auth.in.hdr.id && Enabled(bundle, OPT_IDCHECK)) { /* Wrong conversation dude ! */ log_Printf(LogPHASE, "Chap Input: %s dropped (got id %d, not %d)\n", chapcodes[chap->auth.in.hdr.code], chap->auth.in.hdr.id, chap->auth.id); m_freem(bp); return NULL; } chap->auth.id = chap->auth.in.hdr.id; /* We respond with this id */ #ifndef NODES lanman = 0; #endif switch (chap->auth.in.hdr.code) { case CHAP_CHALLENGE: bp = mbuf_Read(bp, &alen, 1); len -= alen + 1; if (len < 0) { log_Printf(LogERROR, "Chap Input: Truncated challenge !\n"); m_freem(bp); return NULL; } *chap->challenge.peer = alen; bp = mbuf_Read(bp, chap->challenge.peer + 1, alen); bp = auth_ReadName(&chap->auth, bp, len); #ifndef NODES lanman = p->link.lcp.his_authtype == 0x80 && ((chap->NTRespSent && IsAccepted(p->link.lcp.cfg.chap80lm)) || !IsAccepted(p->link.lcp.cfg.chap80nt)); /* Generate local challenge value */ chap_ChallengeInit(&chap->auth); #endif break; case CHAP_RESPONSE: auth_StopTimer(&chap->auth); bp = mbuf_Read(bp, &alen, 1); len -= alen + 1; if (len < 0) { log_Printf(LogERROR, "Chap Input: Truncated response !\n"); m_freem(bp); return NULL; } if ((ans = malloc(alen + 1)) == NULL) { log_Printf(LogERROR, "Chap Input: Out of memory !\n"); m_freem(bp); return NULL; } *ans = chap->auth.id; bp = mbuf_Read(bp, ans + 1, alen); bp = auth_ReadName(&chap->auth, bp, len); #ifndef NODES lanman = p->link.lcp.want_authtype == 0x80 && alen == 49 && ans[alen] == 0; #endif break; case CHAP_SUCCESS: case CHAP_FAILURE: /* chap->auth.in.name is already set up at CHALLENGE time */ if ((ans = malloc(len + 1)) == NULL) { log_Printf(LogERROR, "Chap Input: Out of memory !\n"); m_freem(bp); return NULL; } bp = mbuf_Read(bp, ans, len); ans[len] = '\0'; break; } switch (chap->auth.in.hdr.code) { case CHAP_CHALLENGE: case CHAP_RESPONSE: if (*chap->auth.in.name) log_Printf(LogPHASE, "Chap Input: %s (%d bytes from %s%s)\n", chapcodes[chap->auth.in.hdr.code], alen, chap->auth.in.name, #ifndef NODES lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ? " - lanman" : #endif ""); else log_Printf(LogPHASE, "Chap Input: %s (%d bytes%s)\n", chapcodes[chap->auth.in.hdr.code], alen, #ifndef NODES lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ? " - lanman" : #endif ""); break; case CHAP_SUCCESS: case CHAP_FAILURE: if (*ans) log_Printf(LogPHASE, "Chap Input: %s (%s)\n", chapcodes[chap->auth.in.hdr.code], ans); else log_Printf(LogPHASE, "Chap Input: %s\n", chapcodes[chap->auth.in.hdr.code]); break; } switch (chap->auth.in.hdr.code) { case CHAP_CHALLENGE: if (*bundle->cfg.auth.key == '!' && bundle->cfg.auth.key[1] != '!') chap_StartChild(chap, bundle->cfg.auth.key + 1, bundle->cfg.auth.name); else chap_Respond(chap, bundle->cfg.auth.name, bundle->cfg.auth.key + - (*bundle->cfg.auth.key == '!' ? 1 : 0), - p->link.lcp.his_authtype + (*bundle->cfg.auth.key == '!' ? 1 : 0) + #ifndef NODES - , lanman + , p->link.lcp.his_authtype, lanman #endif ); break; case CHAP_RESPONSE: name = chap->auth.in.name; nlen = strlen(name); #ifndef NODES if (p->link.lcp.want_authtype == 0x81) { struct MSCHAPv2_resp *resp = (struct MSCHAPv2_resp *)(ans + 1); chap->challenge.peer[0] = sizeof resp->PeerChallenge; memcpy(chap->challenge.peer + 1, resp->PeerChallenge, sizeof resp->PeerChallenge); } #endif #ifndef NORADIUS if (*bundle->radius.cfg.file) { if (!radius_Authenticate(&bundle->radius, &chap->auth, chap->auth.in.name, ans, alen + 1, chap->challenge.local + 1, *chap->challenge.local)) chap_Failure(&chap->auth); } else #endif { if (p->link.lcp.want_authtype == 0x81 && ans[alen] != '\0' && alen == sizeof(struct MSCHAPv2_resp)) { struct MSCHAPv2_resp *resp = (struct MSCHAPv2_resp *)(ans + 1); log_Printf(LogWARN, "%s: Compensating for corrupt (Win98/WinME?) " "CHAP81 RESPONSE\n", l->name); resp->Flags = '\0'; /* rfc2759 says it *MUST* be zero */ } - key = auth_GetSecret(bundle, name, nlen, p); + key = auth_GetSecret(name, nlen); if (key) { #ifndef NODES if (p->link.lcp.want_authtype == 0x80 && lanman && !IsEnabled(p->link.lcp.cfg.chap80lm)) { log_Printf(LogPHASE, "Auth failure: LANMan not enabled\n"); if (chap_HaveAnotherGo(chap)) break; key = NULL; } else if (p->link.lcp.want_authtype == 0x80 && !lanman && !IsEnabled(p->link.lcp.cfg.chap80nt)) { log_Printf(LogPHASE, "Auth failure: mschap not enabled\n"); if (chap_HaveAnotherGo(chap)) break; key = NULL; } else if (p->link.lcp.want_authtype == 0x81 && !IsEnabled(p->link.lcp.cfg.chap81)) { log_Printf(LogPHASE, "Auth failure: CHAP81 not enabled\n"); key = NULL; } else #endif { char *myans = chap_BuildAnswer(name, key, chap->auth.id, - chap->challenge.local, - p->link.lcp.want_authtype + chap->challenge.local #ifndef NODES - , chap->challenge.peer, - chap->authresponse, lanman); + , p->link.lcp.want_authtype, + chap->challenge.peer, + chap->authresponse, lanman); MPPE_IsServer = 1; /* XXX Global ! */ #else ); #endif if (myans == NULL) key = NULL; else { - if (!chap_Cmp(p->link.lcp.want_authtype, myans + 1, *myans, - ans + 1, alen + if (!chap_Cmp(myans + 1, *myans, ans + 1, alen #ifndef NODES - , lanman + , p->link.lcp.want_authtype, lanman #endif )) key = NULL; free(myans); } } } if (key) chap_Success(&chap->auth); else chap_Failure(&chap->auth); } break; case CHAP_SUCCESS: if (p->link.lcp.auth_iwait == PROTO_CHAP) { p->link.lcp.auth_iwait = 0; if (p->link.lcp.auth_ineed == 0) { #ifndef NODES if (p->link.lcp.his_authtype == 0x81) { if (strncasecmp(ans, chap->authresponse, 42)) { datalink_AuthNotOk(p->dl); log_Printf(LogWARN, "CHAP81: AuthenticatorResponse: (%.42s)" " != ans: (%.42s)\n", chap->authresponse, ans); } else { /* Successful login */ MPPE_MasterKeyValid = 1; /* XXX Global ! */ datalink_AuthOk(p->dl); } } else #endif /* * We've succeeded in our ``login'' * If we're not expecting the peer to authenticate (or he already * has), proceed to network phase. */ datalink_AuthOk(p->dl); } } break; case CHAP_FAILURE: datalink_AuthNotOk(p->dl); break; } free(ans); } m_freem(bp); return NULL; } Index: head/usr.sbin/ppp/chap_ms.c =================================================================== --- head/usr.sbin/ppp/chap_ms.c (revision 134788) +++ head/usr.sbin/ppp/chap_ms.c (revision 134789) @@ -1,417 +1,415 @@ /*- * Copyright (c) 1997 Gabor Kincses * 1997 - 2001 Brian Somers * based on work by Eric Rosenquist * Strata Software Limited. * 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. * * $FreeBSD$ */ #include #ifdef __FreeBSD__ #include #include #else #include #include #ifdef __NetBSD__ #include #else #include #endif #include #endif #include #include #include "chap_ms.h" /* * Documentation & specifications: * * MS-CHAP (CHAP80) rfc2433 * MS-CHAP-V2 (CHAP81) rfc2759 * MPPE key management draft-ietf-pppext-mppe-keys-02.txt */ static char SHA1_Pad1[40] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static char SHA1_Pad2[40] = {0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2}; /* unused, for documentation only */ /* only NTResp is filled in for FreeBSD */ struct MS_ChapResponse { u_char LANManResp[24]; u_char NTResp[24]; u_char UseNT; /* If 1, ignore the LANMan response field */ }; static u_char Get7Bits(u_char *input, int startBit) { register unsigned int word; word = (unsigned)input[startBit / 8] << 8; word |= (unsigned)input[startBit / 8 + 1]; word >>= 15 - (startBit % 8 + 7); return word & 0xFE; } /* IN 56 bit DES key missing parity bits OUT 64 bit DES key with parity bits added */ static void MakeKey(u_char *key, u_char *des_key) { des_key[0] = Get7Bits(key, 0); des_key[1] = Get7Bits(key, 7); des_key[2] = Get7Bits(key, 14); des_key[3] = Get7Bits(key, 21); des_key[4] = Get7Bits(key, 28); des_key[5] = Get7Bits(key, 35); des_key[6] = Get7Bits(key, 42); des_key[7] = Get7Bits(key, 49); des_set_odd_parity((des_cblock *)des_key); } static void /* IN 8 octets IN 7 octest OUT 8 octets */ DesEncrypt(u_char *clear, u_char *key, u_char *cipher) { des_cblock des_key; des_key_schedule key_schedule; MakeKey(key, des_key); des_set_key(&des_key, key_schedule); des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1); } static void /* IN 8 octets IN 16 octets OUT 24 octets */ ChallengeResponse(u_char *challenge, u_char *pwHash, u_char *response) { char ZPasswordHash[21]; memset(ZPasswordHash, '\0', sizeof ZPasswordHash); memcpy(ZPasswordHash, pwHash, 16); DesEncrypt(challenge, ZPasswordHash + 0, response + 0); DesEncrypt(challenge, ZPasswordHash + 7, response + 8); DesEncrypt(challenge, ZPasswordHash + 14, response + 16); } void NtPasswordHash(char *key, int keylen, char *hash) { MD4_CTX MD4context; MD4Init(&MD4context); MD4Update(&MD4context, key, keylen); MD4Final(hash, &MD4context); } void HashNtPasswordHash(char *hash, char *hashhash) { MD4_CTX MD4context; MD4Init(&MD4context); MD4Update(&MD4context, hash, 16); MD4Final(hashhash, &MD4context); } -void +static void ChallengeHash(char *PeerChallenge, char *AuthenticatorChallenge, - char *UserName, int UserNameLen, char *Challenge) + char *UserName, char *Challenge) { SHA_CTX Context; char Digest[SHA_DIGEST_LENGTH]; char *Name; Name = strrchr(UserName, '\\'); if(NULL == Name) Name = UserName; else Name++; SHA1_Init(&Context); SHA1_Update(&Context, PeerChallenge, 16); SHA1_Update(&Context, AuthenticatorChallenge, 16); SHA1_Update(&Context, Name, strlen(Name)); SHA1_Final(Digest, &Context); memcpy(Challenge, Digest, 8); } void GenerateNTResponse(char *AuthenticatorChallenge, char *PeerChallenge, - char *UserName, int UserNameLen, char *Password, + char *UserName, char *Password, int PasswordLen, char *Response) { char Challenge[8]; char PasswordHash[16]; - ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, UserNameLen, - Challenge); + ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, Challenge); NtPasswordHash(Password, PasswordLen, PasswordHash); ChallengeResponse(Challenge, PasswordHash, Response); } #ifndef __FreeBSD__ #define LENGTH 20 static char * SHA1_End(SHA_CTX *ctx, char *buf) { int i; unsigned char digest[LENGTH]; static const char hex[]="0123456789abcdef"; if (!buf) buf = malloc(2*LENGTH + 1); if (!buf) return 0; SHA1_Final(digest, ctx); for (i = 0; i < LENGTH; i++) { buf[i+i] = hex[digest[i] >> 4]; buf[i+i+1] = hex[digest[i] & 0x0f]; } buf[i+i] = '\0'; return buf; } #endif void GenerateAuthenticatorResponse(char *Password, int PasswordLen, char *NTResponse, char *PeerChallenge, char *AuthenticatorChallenge, char *UserName, - int UserNameLen, char *AuthenticatorResponse) + char *AuthenticatorResponse) { SHA_CTX Context; char PasswordHash[16]; char PasswordHashHash[16]; char Challenge[8]; u_char Digest[SHA_DIGEST_LENGTH]; int i; /* * "Magic" constants used in response generation */ char Magic1[39] = {0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74}; char Magic2[41] = {0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x6E}; /* * Hash the password with MD4 */ NtPasswordHash(Password, PasswordLen, PasswordHash); /* * Now hash the hash */ HashNtPasswordHash(PasswordHash, PasswordHashHash); SHA1_Init(&Context); SHA1_Update(&Context, PasswordHashHash, 16); SHA1_Update(&Context, NTResponse, 24); SHA1_Update(&Context, Magic1, 39); SHA1_Final(Digest, &Context); - ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, UserNameLen, - Challenge); + ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, Challenge); SHA1_Init(&Context); SHA1_Update(&Context, Digest, 20); SHA1_Update(&Context, Challenge, 8); SHA1_Update(&Context, Magic2, 41); /* * Encode the value of 'Digest' as "S=" followed by * 40 ASCII hexadecimal digits and return it in * AuthenticatorResponse. * For example, * "S=0123456789ABCDEF0123456789ABCDEF01234567" */ AuthenticatorResponse[0] = 'S'; AuthenticatorResponse[1] = '='; SHA1_End(&Context, AuthenticatorResponse + 2); for (i=2; i<42; i++) AuthenticatorResponse[i] = toupper(AuthenticatorResponse[i]); } void GetMasterKey(char *PasswordHashHash, char *NTResponse, char *MasterKey) { char Digest[SHA_DIGEST_LENGTH]; SHA_CTX Context; static char Magic1[27] = {0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79}; SHA1_Init(&Context); SHA1_Update(&Context, PasswordHashHash, 16); SHA1_Update(&Context, NTResponse, 24); SHA1_Update(&Context, Magic1, 27); SHA1_Final(Digest, &Context); memcpy(MasterKey, Digest, 16); } void GetAsymetricStartKey(char *MasterKey, char *SessionKey, int SessionKeyLength, int IsSend, int IsServer) { char Digest[SHA_DIGEST_LENGTH]; SHA_CTX Context; char *s; static char Magic2[84] = {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x2e}; static char Magic3[84] = {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, 0x2e}; if (IsSend) { if (IsServer) { s = Magic3; } else { s = Magic2; } } else { if (IsServer) { s = Magic2; } else { s = Magic3; } } SHA1_Init(&Context); SHA1_Update(&Context, MasterKey, 16); SHA1_Update(&Context, SHA1_Pad1, 40); SHA1_Update(&Context, s, 84); SHA1_Update(&Context, SHA1_Pad2, 40); SHA1_Final(Digest, &Context); memcpy(SessionKey, Digest, SessionKeyLength); } void GetNewKeyFromSHA(char *StartKey, char *SessionKey, long SessionKeyLength, char *InterimKey) { SHA_CTX Context; char Digest[SHA_DIGEST_LENGTH]; SHA1_Init(&Context); SHA1_Update(&Context, StartKey, SessionKeyLength); SHA1_Update(&Context, SHA1_Pad1, 40); SHA1_Update(&Context, SessionKey, SessionKeyLength); SHA1_Update(&Context, SHA1_Pad2, 40); SHA1_Final(Digest, &Context); memcpy(InterimKey, Digest, SessionKeyLength); } #if 0 static void Get_Key(char *InitialSessionKey, char *CurrentSessionKey, int LengthOfDesiredKey) { SHA_CTX Context; char Digest[SHA_DIGEST_LENGTH]; SHA1_Init(&Context); SHA1_Update(&Context, InitialSessionKey, LengthOfDesiredKey); SHA1_Update(&Context, SHA1_Pad1, 40); SHA1_Update(&Context, CurrentSessionKey, LengthOfDesiredKey); SHA1_Update(&Context, SHA1_Pad2, 40); SHA1_Final(Digest, &Context); memcpy(CurrentSessionKey, Digest, LengthOfDesiredKey); } #endif /* passwordHash 16-bytes MD4 hashed password challenge 8-bytes peer CHAP challenge since passwordHash is in a 24-byte buffer, response is written in there */ void mschap_NT(char *passwordHash, char *challenge) { u_char response[24]; ChallengeResponse(challenge, passwordHash, response); memcpy(passwordHash, response, 24); passwordHash[24] = 1; /* NT-style response */ } void mschap_LANMan(char *digest, char *challenge, char *secret) { static u_char salt[] = "KGS!@#$%"; /* RASAPI32.dll */ char SECRET[14], *ptr, *end; u_char hash[16]; end = SECRET + sizeof SECRET; for (ptr = SECRET; *secret && ptr < end; ptr++, secret++) *ptr = toupper(*secret); if (ptr < end) memset(ptr, '\0', end - ptr); DesEncrypt(salt, SECRET, hash); DesEncrypt(salt, SECRET + 7, hash + 8); ChallengeResponse(challenge, hash, digest); } Index: head/usr.sbin/ppp/chap_ms.h =================================================================== --- head/usr.sbin/ppp/chap_ms.h (revision 134788) +++ head/usr.sbin/ppp/chap_ms.h (revision 134789) @@ -1,53 +1,52 @@ /*- * Copyright (c) 1997 Gabor Kincses * 1997 - 2001 Brian Somers * based on work by Eric Rosenquist * Strata Software Limited. * 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. * * $FreeBSD$ */ /* Max # of (Unicode) chars in an NT password */ #define MAX_NT_PASSWORD 256 /* Don't rely on sizeof(MS_ChapResponse) in case of struct padding */ #define MS_CHAP_RESPONSE_LEN 49 #define CHAP81_RESPONSE_LEN 49 #define CHAP81_NTRESPONSE_LEN 24 #define CHAP81_NTRESPONSE_OFF 24 #define CHAP81_HASH_LEN 16 #define CHAP81_AUTHRESPONSE_LEN 42 #define CHAP81_CHALLENGE_LEN 16 extern void mschap_NT(char *, char *); extern void mschap_LANMan(char *, char *, char *); -extern void GenerateNTResponse(char *, char *, char *, int, char *, int , char *); +extern void GenerateNTResponse(char *, char *, char *, char *, int , char *); extern void HashNtPasswordHash(char *, char *); extern void NtPasswordHash(char *, int, char *); -extern void ChallengeHash(char *, char *, char *UserName, int, char *); -extern void GenerateAuthenticatorResponse(char *, int, char *, char *, char *, char *, int, char *); +extern void GenerateAuthenticatorResponse(char *, int, char *, char *, char *, char *, char *); extern void GetAsymetricStartKey(char *, char *, int, int, int); extern void GetMasterKey(char *, char *, char *); extern void GetNewKeyFromSHA(char *, char *, long, char *); Index: head/usr.sbin/ppp/chat.c =================================================================== --- head/usr.sbin/ppp/chat.c (revision 134788) +++ head/usr.sbin/ppp/chat.c (revision 134789) @@ -1,794 +1,796 @@ /*- * 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. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "layer.h" #include "mbuf.h" #include "log.h" #include "defs.h" #include "timer.h" #include "lqr.h" #include "hdlc.h" #include "throughput.h" #include "fsm.h" #include "lcp.h" #include "ccp.h" #include "link.h" #include "async.h" #include "descriptor.h" #include "physical.h" #include "chat.h" #include "mp.h" #include "auth.h" #include "chap.h" #include "slcompress.h" #include "iplist.h" #include "ncpaddr.h" #include "ipcp.h" #include "filter.h" #include "cbcp.h" #include "command.h" #include "datalink.h" #ifndef NORADIUS #include "radius.h" #endif #include "ipv6cp.h" #include "ncp.h" #include "bundle.h" #include "id.h" #define BUFLEFT(c) (sizeof (c)->buf - ((c)->bufend - (c)->buf)) static void ExecStr(struct physical *, char *, char *, int); static char *ExpandString(struct chat *, const char *, char *, int, int); static void chat_PauseTimer(void *v) { struct chat *c = (struct chat *)v; timer_Stop(&c->pause); c->pause.load = 0; } static void chat_Pause(struct chat *c, u_long load) { timer_Stop(&c->pause); c->pause.load += load; c->pause.func = chat_PauseTimer; c->pause.name = "chat pause"; c->pause.arg = c; timer_Start(&c->pause); } static void chat_TimeoutTimer(void *v) { struct chat *c = (struct chat *)v; timer_Stop(&c->timeout); c->TimedOut = 1; } static void chat_SetTimeout(struct chat *c) { timer_Stop(&c->timeout); if (c->TimeoutSec > 0) { c->timeout.load = SECTICKS * c->TimeoutSec; c->timeout.func = chat_TimeoutTimer; c->timeout.name = "chat timeout"; c->timeout.arg = c; timer_Start(&c->timeout); } } static char * chat_NextChar(char *ptr, char ch) { for (; *ptr; ptr++) if (*ptr == ch) return ptr; else if (*ptr == '\\') if (*++ptr == '\0') return NULL; return NULL; } static int chat_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) { struct chat *c = descriptor2chat(d); int special, gotabort, gottimeout, needcr; int TimedOut = c->TimedOut; static char arg_term; /* An empty string */ if (c->pause.state == TIMER_RUNNING) return 0; if (TimedOut) { log_Printf(LogCHAT, "Expect timeout\n"); if (c->nargptr == NULL) c->state = CHAT_FAILED; else { /* c->state = CHAT_EXPECT; */ c->argptr = &arg_term; } c->TimedOut = 0; } if (c->state != CHAT_EXPECT && c->state != CHAT_SEND) return 0; gottimeout = gotabort = 0; if (c->arg < c->argc && (c->arg < 0 || *c->argptr == '\0')) { /* Go get the next string */ if (c->arg < 0 || c->state == CHAT_SEND) c->state = CHAT_EXPECT; else c->state = CHAT_SEND; special = 1; while (special && (c->nargptr || c->arg < c->argc - 1)) { if (c->arg < 0 || (!TimedOut && c->state == CHAT_SEND)) c->nargptr = NULL; if (c->nargptr != NULL) { /* We're doing expect-send-expect.... */ c->argptr = c->nargptr; /* Put the '-' back in case we ever want to rerun our script */ c->nargptr[-1] = '-'; c->nargptr = chat_NextChar(c->nargptr, '-'); if (c->nargptr != NULL) *c->nargptr++ = '\0'; } else { int minus; if ((c->argptr = c->argv[++c->arg]) == NULL) { /* End of script - all ok */ c->state = CHAT_DONE; return 0; } if (c->state == CHAT_EXPECT) { /* Look for expect-send-expect sequence */ c->nargptr = c->argptr; minus = 0; while ((c->nargptr = chat_NextChar(c->nargptr, '-'))) { c->nargptr++; minus++; } if (minus % 2) log_Printf(LogWARN, "chat_UpdateSet: \"%s\": Uneven number of" " '-' chars, all ignored\n", c->argptr); else if (minus) { c->nargptr = chat_NextChar(c->argptr, '-'); *c->nargptr++ = '\0'; } } } /* * c->argptr now temporarily points into c->script (via c->argv) * If it's an expect-send-expect sequence, we've just got the correct * portion of that sequence. */ needcr = c->state == CHAT_SEND && (*c->argptr != '!' || c->argptr[1] == '!'); /* We leave room for a potential HDLC header in the target string */ ExpandString(c, c->argptr, c->exp + 2, sizeof c->exp - 2, needcr); /* * Now read our string. If it's not a special string, we unset * ``special'' to break out of the loop. */ if (gotabort) { if (c->abort.num < MAXABORTS) { int len, i; len = strlen(c->exp+2); for (i = 0; i < c->abort.num; i++) if (len > c->abort.string[i].len) { int last; for (last = c->abort.num; last > i; last--) { c->abort.string[last].data = c->abort.string[last-1].data; c->abort.string[last].len = c->abort.string[last-1].len; } break; } c->abort.string[i].len = len; c->abort.string[i].data = (char *)malloc(len+1); memcpy(c->abort.string[i].data, c->exp+2, len+1); c->abort.num++; } else log_Printf(LogERROR, "chat_UpdateSet: too many abort strings\n"); gotabort = 0; } else if (gottimeout) { c->TimeoutSec = atoi(c->exp + 2); if (c->TimeoutSec <= 0) c->TimeoutSec = 30; gottimeout = 0; } else if (c->nargptr == NULL && !strcmp(c->exp+2, "ABORT")) gotabort = 1; else if (c->nargptr == NULL && !strcmp(c->exp+2, "TIMEOUT")) gottimeout = 1; else { if (c->exp[2] == '!' && c->exp[3] != '!') ExecStr(c->physical, c->exp + 3, c->exp + 3, sizeof c->exp - 3); if (c->exp[2] == '\0') { /* Empty string, reparse (this may be better as a `goto start') */ c->argptr = &arg_term; return chat_UpdateSet(d, r, w, e, n); } special = 0; } } if (special) { if (gottimeout) log_Printf(LogWARN, "chat_UpdateSet: TIMEOUT: Argument expected\n"); else if (gotabort) log_Printf(LogWARN, "chat_UpdateSet: ABORT: Argument expected\n"); /* End of script - all ok */ c->state = CHAT_DONE; return 0; } /* set c->argptr to point in the right place */ c->argptr = c->exp + (c->exp[2] == '!' ? 3 : 2); c->arglen = strlen(c->argptr); if (c->state == CHAT_EXPECT) { /* We must check to see if the string's already been found ! */ char *begin, *end; end = c->bufend - c->arglen + 1; if (end < c->bufstart) end = c->bufstart; for (begin = c->bufstart; begin < end; begin++) if (!strncmp(begin, c->argptr, c->arglen)) { c->bufstart = begin + c->arglen; c->argptr += c->arglen; c->arglen = 0; /* Continue - we've already read our expect string */ return chat_UpdateSet(d, r, w, e, n); } log_Printf(LogCHAT, "Expect(%d): %s\n", c->TimeoutSec, c->argptr); chat_SetTimeout(c); } } /* * We now have c->argptr pointing at what we want to expect/send and * c->state saying what we want to do... we now know what to put in * the fd_set :-) */ if (c->state == CHAT_EXPECT) return physical_doUpdateSet(&c->physical->desc, r, NULL, e, n, 1); else return physical_doUpdateSet(&c->physical->desc, NULL, w, e, n, 1); } static int chat_IsSet(struct fdescriptor *d, const fd_set *fdset) { struct chat *c = descriptor2chat(d); return c->argptr && physical_IsSet(&c->physical->desc, fdset); } static void chat_UpdateLog(struct chat *c, int in) { if (log_IsKept(LogCHAT) || log_IsKept(LogCONNECT)) { /* * If a linefeed appears in the last `in' characters of `c's input * buffer, output from there, all the way back to the last linefeed. * This is called for every read of `in' bytes. */ char *ptr, *end, *stop, ch; int level; level = log_IsKept(LogCHAT) ? LogCHAT : LogCONNECT; if (in == -1) end = ptr = c->bufend; else { ptr = c->bufend - in; for (end = c->bufend - 1; end >= ptr; end--) if (*end == '\n') break; } if (end >= ptr) { for (ptr = c->bufend - (in == -1 ? 1 : in + 1); ptr >= c->bufstart; ptr--) if (*ptr == '\n') break; ptr++; stop = NULL; while (stop < end) { if ((stop = memchr(ptr, '\n', end - ptr)) == NULL) stop = end; ch = *stop; *stop = '\0'; if (level == LogCHAT || strstr(ptr, "CONNECT")) log_Printf(level, "Received: %s\n", ptr); *stop = ch; ptr = stop + 1; } } } } static void -chat_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) +chat_Read(struct fdescriptor *d, struct bundle *bundle __unused, + const fd_set *fdset __unused) { struct chat *c = descriptor2chat(d); if (c->state == CHAT_EXPECT) { ssize_t in; char *abegin, *ebegin, *begin, *aend, *eend, *end; int n; /* * XXX - should this read only 1 byte to guarantee that we don't * swallow any ppp talk from the peer ? */ in = BUFLEFT(c); - if (in > sizeof c->buf / 2) + if (in > (ssize_t)sizeof c->buf / 2) in = sizeof c->buf / 2; in = physical_Read(c->physical, c->bufend, in); if (in <= 0) return; /* `begin' and `end' delimit where we're going to strncmp() from */ ebegin = c->bufend - c->arglen + 1; eend = ebegin + in; if (ebegin < c->bufstart) ebegin = c->bufstart; if (c->abort.num) { abegin = c->bufend - c->abort.string[0].len + 1; aend = c->bufend - c->abort.string[c->abort.num-1].len + in + 1; if (abegin < c->bufstart) abegin = c->bufstart; } else { abegin = ebegin; aend = eend; } begin = abegin < ebegin ? abegin : ebegin; end = aend < eend ? eend : aend; c->bufend += in; chat_UpdateLog(c, in); if (c->bufend > c->buf + sizeof c->buf / 2) { /* Shuffle our receive buffer back a bit */ int chop; for (chop = begin - c->buf; chop; chop--) if (c->buf[chop] == '\n') /* found some already-logged garbage to remove :-) */ break; if (!chop) chop = begin - c->buf; if (chop) { char *from, *to; to = c->buf; from = to + chop; while (from < c->bufend) *to++ = *from++; c->bufstart -= chop; c->bufend -= chop; begin -= chop; end -= chop; abegin -= chop; aend -= chop; ebegin -= chop; eend -= chop; } } for (; begin < end; begin++) if (begin >= ebegin && begin < eend && !strncmp(begin, c->argptr, c->arglen)) { /* Got it ! */ timer_Stop(&c->timeout); if (memchr(begin + c->arglen - 1, '\n', c->bufend - begin - c->arglen + 1) == NULL) { /* force it into the log */ end = c->bufend; c->bufend = begin + c->arglen; chat_UpdateLog(c, -1); c->bufend = end; } c->bufstart = begin + c->arglen; c->argptr += c->arglen; c->arglen = 0; break; } else if (begin >= abegin && begin < aend) { for (n = c->abort.num - 1; n >= 0; n--) { if (begin + c->abort.string[n].len > c->bufend) break; if (!strncmp(begin, c->abort.string[n].data, c->abort.string[n].len)) { if (memchr(begin + c->abort.string[n].len - 1, '\n', c->bufend - begin - c->abort.string[n].len + 1) == NULL) { /* force it into the log */ end = c->bufend; c->bufend = begin + c->abort.string[n].len; chat_UpdateLog(c, -1); c->bufend = end; } c->bufstart = begin + c->abort.string[n].len; c->state = CHAT_FAILED; return; } } } } } static int -chat_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) +chat_Write(struct fdescriptor *d, struct bundle *bundle __unused, + const fd_set *fdset __unused) { struct chat *c = descriptor2chat(d); int result = 0; if (c->state == CHAT_SEND) { int wrote; if (strstr(c->argv[c->arg], "\\P")) /* Don't log the password */ log_Printf(LogCHAT, "Send: %s\n", c->argv[c->arg]); else { int sz; sz = c->arglen - 1; while (sz >= 0 && c->argptr[sz] == '\n') sz--; log_Printf(LogCHAT, "Send: %.*s\n", sz + 1, c->argptr); } if (physical_IsSync(c->physical)) { /* * XXX: Fix me * This data should be stuffed down through the link layers */ /* There's always room for the HDLC header */ c->argptr -= 2; c->arglen += 2; memcpy(c->argptr, "\377\003", 2); /* Prepend HDLC header */ } wrote = physical_Write(c->physical, c->argptr, c->arglen); result = wrote > 0 ? 1 : 0; if (wrote == -1) { if (errno != EINTR) { log_Printf(LogWARN, "chat_Write: %s\n", strerror(errno)); result = -1; } if (physical_IsSync(c->physical)) { c->argptr += 2; c->arglen -= 2; } } else if (wrote < 2 && physical_IsSync(c->physical)) { /* Oops - didn't even write our HDLC header ! */ c->argptr += 2; c->arglen -= 2; } else { c->argptr += wrote; c->arglen -= wrote; } } return result; } void chat_Init(struct chat *c, struct physical *p) { c->desc.type = CHAT_DESCRIPTOR; c->desc.UpdateSet = chat_UpdateSet; c->desc.IsSet = chat_IsSet; c->desc.Read = chat_Read; c->desc.Write = chat_Write; c->physical = p; *c->script = '\0'; c->argc = 0; c->arg = -1; c->argptr = NULL; c->nargptr = NULL; c->bufstart = c->bufend = c->buf; memset(&c->pause, '\0', sizeof c->pause); memset(&c->timeout, '\0', sizeof c->timeout); } int chat_Setup(struct chat *c, const char *data, const char *phone) { c->state = CHAT_EXPECT; if (data == NULL) { *c->script = '\0'; c->argc = 0; } else { strncpy(c->script, data, sizeof c->script - 1); c->script[sizeof c->script - 1] = '\0'; c->argc = MakeArgs(c->script, c->argv, VECSIZE(c->argv), PARSE_NOHASH); } c->arg = -1; c->argptr = NULL; c->nargptr = NULL; c->TimeoutSec = 30; c->TimedOut = 0; c->phone = phone; c->abort.num = 0; timer_Stop(&c->pause); timer_Stop(&c->timeout); return c->argc >= 0; } void chat_Finish(struct chat *c) { timer_Stop(&c->pause); timer_Stop(&c->timeout); while (c->abort.num) free(c->abort.string[--c->abort.num].data); c->abort.num = 0; } void chat_Destroy(struct chat *c) { chat_Finish(c); } /* * \c don't add a cr * \d Sleep a little (delay 2 seconds * \n Line feed character * \P Auth Key password * \p pause 0.25 sec * \r Carrige return character * \s Space character * \T Telephone number(s) (defined via `set phone') * \t Tab character * \U Auth User */ static char * ExpandString(struct chat *c, const char *str, char *result, int reslen, int cr) { int len; result[--reslen] = '\0'; while (*str && reslen > 0) { switch (*str) { case '\\': str++; switch (*str) { case 'c': cr = 0; break; case 'd': /* Delay 2 seconds */ chat_Pause(c, 2 * SECTICKS); break; case 'p': chat_Pause(c, SECTICKS / 4); break; /* Delay 0.25 seconds */ case 'n': *result++ = '\n'; reslen--; break; case 'r': *result++ = '\r'; reslen--; break; case 's': *result++ = ' '; reslen--; break; case 't': *result++ = '\t'; reslen--; break; case 'P': strncpy(result, c->physical->dl->bundle->cfg.auth.key, reslen); len = strlen(result); reslen -= len; result += len; break; case 'T': if (c->phone) { strncpy(result, c->phone, reslen); len = strlen(result); reslen -= len; result += len; } break; case 'U': strncpy(result, c->physical->dl->bundle->cfg.auth.name, reslen); len = strlen(result); reslen -= len; result += len; break; default: reslen--; *result++ = *str; break; } if (*str) str++; break; case '^': str++; if (*str) { *result++ = *str++ & 0x1f; reslen--; } break; default: *result++ = *str++; reslen--; break; } } if (--reslen > 0) { if (cr) *result++ = '\r'; } if (--reslen > 0) *result++ = '\0'; return (result); } static void ExecStr(struct physical *physical, char *command, char *out, int olen) { pid_t pid; int fids[2]; char *argv[MAXARGS], *vector[MAXARGS], *startout, *endout; int stat, nb, argc, i; log_Printf(LogCHAT, "Exec: %s\n", command); if ((argc = MakeArgs(command, vector, VECSIZE(vector), PARSE_REDUCE|PARSE_NOHASH)) <= 0) { if (argc < 0) log_Printf(LogWARN, "Syntax error in exec command\n"); *out = '\0'; return; } if (pipe(fids) < 0) { log_Printf(LogCHAT, "Unable to create pipe in ExecStr: %s\n", strerror(errno)); *out = '\0'; return; } if ((pid = fork()) == 0) { command_Expand(argv, argc, (char const *const *)vector, physical->dl->bundle, 0, getpid()); close(fids[0]); timer_TermService(); if (fids[1] == STDIN_FILENO) fids[1] = dup(fids[1]); dup2(physical->fd, STDIN_FILENO); dup2(fids[1], STDERR_FILENO); dup2(STDIN_FILENO, STDOUT_FILENO); close(3); if (open(_PATH_TTY, O_RDWR) != 3) open(_PATH_DEVNULL, O_RDWR); /* Leave it closed if it fails... */ for (i = getdtablesize(); i > 3; i--) fcntl(i, F_SETFD, 1); #ifndef NOSUID setuid(ID0realuid()); #endif execvp(argv[0], argv); fprintf(stderr, "execvp: %s: %s\n", argv[0], strerror(errno)); _exit(127); } else { char *name = strdup(vector[0]); close(fids[1]); endout = out + olen - 1; startout = out; while (out < endout) { nb = read(fids[0], out, 1); if (nb <= 0) break; out++; } *out = '\0'; close(fids[0]); close(fids[1]); waitpid(pid, &stat, WNOHANG); if (WIFSIGNALED(stat)) { log_Printf(LogWARN, "%s: signal %d\n", name, WTERMSIG(stat)); free(name); *out = '\0'; return; } else if (WIFEXITED(stat)) { switch (WEXITSTATUS(stat)) { case 0: free(name); break; case 127: log_Printf(LogWARN, "%s: %s\n", name, startout); free(name); *out = '\0'; return; break; default: log_Printf(LogWARN, "%s: exit %d\n", name, WEXITSTATUS(stat)); free(name); *out = '\0'; return; break; } } else { log_Printf(LogWARN, "%s: Unexpected exit result\n", name); free(name); *out = '\0'; return; } } } Index: head/usr.sbin/ppp/command.c =================================================================== --- head/usr.sbin/ppp/command.c (revision 134788) +++ head/usr.sbin/ppp/command.c (revision 134789) @@ -1,3246 +1,3251 @@ /*- * Copyright (c) 1996 - 2001 Brian Somers * based on work by Toshiharu OHNO * Internet Initiative Japan, Inc (IIJ) * 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. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef NONAT #ifdef LOCALNAT #include "alias.h" #else #include #endif #endif #include "layer.h" #include "defs.h" #include "command.h" #include "mbuf.h" #include "log.h" #include "timer.h" #include "fsm.h" #include "iplist.h" #include "throughput.h" #include "slcompress.h" #include "lqr.h" #include "hdlc.h" #include "lcp.h" #include "ncpaddr.h" #include "ipcp.h" #ifndef NONAT #include "nat_cmd.h" #endif #include "systems.h" #include "filter.h" #include "descriptor.h" #include "main.h" #include "route.h" #include "ccp.h" #include "auth.h" #include "async.h" #include "link.h" #include "physical.h" #include "mp.h" #ifndef NORADIUS #include "radius.h" #endif #include "ipv6cp.h" #include "ncp.h" #include "bundle.h" #include "server.h" #include "prompt.h" #include "chat.h" #include "chap.h" #include "cbcp.h" #include "datalink.h" #include "iface.h" #include "id.h" #include "probe.h" /* ``set'' values */ #define VAR_AUTHKEY 0 #define VAR_DIAL 1 #define VAR_LOGIN 2 #define VAR_AUTHNAME 3 #define VAR_AUTOLOAD 4 #define VAR_WINSIZE 5 #define VAR_DEVICE 6 #define VAR_ACCMAP 7 #define VAR_MRRU 8 #define VAR_MRU 9 #define VAR_MTU 10 #define VAR_OPENMODE 11 #define VAR_PHONE 12 #define VAR_HANGUP 13 #define VAR_IDLETIMEOUT 14 #define VAR_LQRPERIOD 15 #define VAR_LCPRETRY 16 #define VAR_CHAPRETRY 17 #define VAR_PAPRETRY 18 #define VAR_CCPRETRY 19 #define VAR_IPCPRETRY 20 #define VAR_DNS 21 #define VAR_NBNS 22 #define VAR_MODE 23 #define VAR_CALLBACK 24 #define VAR_CBCP 25 #define VAR_CHOKED 26 #define VAR_SENDPIPE 27 #define VAR_RECVPIPE 28 #define VAR_RADIUS 29 #define VAR_CD 30 #define VAR_PARITY 31 #define VAR_CRTSCTS 32 #define VAR_URGENTPORTS 33 #define VAR_LOGOUT 34 #define VAR_IFQUEUE 35 #define VAR_MPPE 36 #define VAR_IPV6CPRETRY 37 #define VAR_RAD_ALIVE 38 #define VAR_PPPOE 39 /* ``accept|deny|disable|enable'' masks */ #define NEG_HISMASK (1) #define NEG_MYMASK (2) /* ``accept|deny|disable|enable'' values */ #define NEG_ACFCOMP 40 #define NEG_CHAP05 41 #define NEG_CHAP80 42 #define NEG_CHAP80LM 43 #define NEG_DEFLATE 44 #define NEG_DNS 45 #define NEG_ENDDISC 46 #define NEG_LQR 47 #define NEG_PAP 48 #define NEG_PPPDDEFLATE 49 #define NEG_PRED1 50 #define NEG_PROTOCOMP 51 #define NEG_SHORTSEQ 52 #define NEG_VJCOMP 53 #define NEG_MPPE 54 #define NEG_CHAP81 55 -const char Version[] = "3.2"; +const char Version[] = "3.3"; static int ShowCommand(struct cmdargs const *); static int TerminalCommand(struct cmdargs const *); static int QuitCommand(struct cmdargs const *); static int OpenCommand(struct cmdargs const *); static int CloseCommand(struct cmdargs const *); static int DownCommand(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 NegotiateCommand(struct cmdargs const *); static int ClearCommand(struct cmdargs const *); static int RunListCommand(struct cmdargs const *); static int IfaceAddCommand(struct cmdargs const *); static int IfaceDeleteCommand(struct cmdargs const *); static int IfaceClearCommand(struct cmdargs const *); static int SetProcTitle(struct cmdargs const *); #ifndef NONAT static int NatEnable(struct cmdargs const *); static int NatOption(struct cmdargs const *); #endif static const char * showcx(struct cmdtab const *cmd) { if (cmd->lauth & LOCAL_CX) return "(c)"; else if (cmd->lauth & LOCAL_CX_OPT) return "(o)"; return ""; } static int HelpCommand(struct cmdargs const *arg) { struct cmdtab const *cmd; int n, cmax, dmax, cols, cxlen; const char *cx; if (!arg->prompt) { log_Printf(LogWARN, "help: Cannot help without a prompt\n"); return 0; } if (arg->argc > arg->argn) { for (cmd = arg->cmdtab; cmd->name || cmd->alias; cmd++) if ((cmd->lauth & arg->prompt->auth) && ((cmd->name && !strcasecmp(cmd->name, arg->argv[arg->argn])) || (cmd->alias && !strcasecmp(cmd->alias, arg->argv[arg->argn])))) { prompt_Printf(arg->prompt, "%s %s\n", cmd->syntax, showcx(cmd)); return 0; } return -1; } cmax = dmax = 0; for (cmd = arg->cmdtab; cmd->func; cmd++) if (cmd->name && (cmd->lauth & arg->prompt->auth)) { if ((n = strlen(cmd->name) + strlen(showcx(cmd))) > cmax) cmax = n; if ((n = strlen(cmd->helpmes)) > dmax) dmax = n; } cols = 80 / (dmax + cmax + 3); n = 0; prompt_Printf(arg->prompt, "(o) = Optional context," " (c) = Context required\n"); for (cmd = arg->cmdtab; cmd->func; cmd++) if (cmd->name && (cmd->lauth & arg->prompt->auth)) { cx = showcx(cmd); cxlen = cmax - strlen(cmd->name); if (n % cols != 0) prompt_Printf(arg->prompt, " "); prompt_Printf(arg->prompt, "%s%-*.*s: %-*.*s", cmd->name, cxlen, cxlen, cx, dmax, dmax, cmd->helpmes); if (++n % cols == 0) prompt_Printf(arg->prompt, "\n"); } if (n % cols != 0) prompt_Printf(arg->prompt, "\n"); return 0; } static int IdentCommand(struct cmdargs const *arg) { Concatinate(arg->cx->physical->link.lcp.cfg.ident, sizeof arg->cx->physical->link.lcp.cfg.ident, arg->argc - arg->argn, arg->argv + arg->argn); return 0; } static int SendIdentification(struct cmdargs const *arg) { if (arg->cx->state < DATALINK_LCP) { log_Printf(LogWARN, "sendident: link has not reached LCP\n"); return 2; } return lcp_SendIdentification(&arg->cx->physical->link.lcp) ? 0 : 1; } static int CloneCommand(struct cmdargs const *arg) { char namelist[LINE_LEN]; char *name; int f; if (arg->argc == arg->argn) return -1; namelist[sizeof namelist - 1] = '\0'; for (f = arg->argn; f < arg->argc; f++) { strncpy(namelist, arg->argv[f], sizeof namelist - 1); for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) bundle_DatalinkClone(arg->bundle, arg->cx, name); } return 0; } static int RemoveCommand(struct cmdargs const *arg) { if (arg->argc != arg->argn) return -1; if (arg->cx->state != DATALINK_CLOSED) { log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n"); return 2; } bundle_DatalinkRemove(arg->bundle, arg->cx); return 0; } static int RenameCommand(struct cmdargs const *arg) { if (arg->argc != arg->argn + 1) return -1; if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn])) return 0; log_Printf(LogWARN, "%s -> %s: target name already exists\n", arg->cx->name, arg->argv[arg->argn]); return 1; } static int LoadCommand(struct cmdargs const *arg) { const char *err; int n, mode; mode = arg->bundle->phys_type.all; if (arg->argn < arg->argc) { for (n = arg->argn; n < arg->argc; n++) if ((err = system_IsValid(arg->argv[n], arg->prompt, mode)) != NULL) { log_Printf(LogWARN, "%s: %s\n", arg->argv[n], err); return 1; } for (n = arg->argn; n < arg->argc; n++) { bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]); system_Select(arg->bundle, arg->argv[n], CONFFILE, arg->prompt, arg->cx); } bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]); } else if ((err = system_IsValid("default", arg->prompt, mode)) != NULL) { log_Printf(LogWARN, "default: %s\n", err); return 1; } else { bundle_SetLabel(arg->bundle, "default"); system_Select(arg->bundle, "default", CONFFILE, arg->prompt, arg->cx); bundle_SetLabel(arg->bundle, "default"); } return 0; } static int LogCommand(struct cmdargs const *arg) { char buf[LINE_LEN]; if (arg->argn < arg->argc) { char *argv[MAXARGS]; int argc = arg->argc - arg->argn; - if (argc >= sizeof argv / sizeof argv[0]) { + if (argc >= (int)(sizeof argv / sizeof argv[0])) { argc = sizeof argv / sizeof argv[0] - 1; log_Printf(LogWARN, "Truncating log command to %d args\n", argc); } command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 1, getpid()); Concatinate(buf, sizeof buf, argc, (const char *const *)argv); log_Printf(LogLOG, "%s\n", buf); command_Free(argc, argv); return 0; } return -1; } static int -SaveCommand(struct cmdargs const *arg) +SaveCommand(struct cmdargs const *arg __unused) { log_Printf(LogWARN, "save command is not yet implemented.\n"); return 1; } static int DialCommand(struct cmdargs const *arg) { int res; if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO))) || (!arg->cx && (arg->bundle->phys_type.all & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) { log_Printf(LogWARN, "Manual dial is only available for auto and" " interactive links\n"); return 1; } if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0) return res; bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1); return 0; } #define isinword(ch) (isalnum(ch) || (ch) == '_') static char * strstrword(char *big, const char *little) { /* Get the first occurance of the word ``little'' in ``big'' */ char *pos; int len; pos = big; len = strlen(little); while ((pos = strstr(pos, little)) != NULL) if ((pos != big && isinword(pos[-1])) || isinword(pos[len])) pos++; else if (pos != big && pos[-1] == '\\') memmove(pos - 1, pos, strlen(pos) + 1); else break; return pos; } static char * subst(char *tgt, const char *oldstr, const char *newstr) { /* tgt is a malloc()d area... realloc() as necessary */ char *word, *ntgt; int ltgt, loldstr, lnewstr, pos; if ((word = strstrword(tgt, oldstr)) == NULL) return tgt; ltgt = strlen(tgt) + 1; loldstr = strlen(oldstr); lnewstr = strlen(newstr); do { pos = word - tgt; if (loldstr > lnewstr) bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr); if (loldstr != lnewstr) { ntgt = realloc(tgt, ltgt += lnewstr - loldstr); if (ntgt == NULL) break; /* Oh wonderful ! */ word = ntgt + pos; tgt = ntgt; } if (lnewstr > loldstr) bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr); bcopy(newstr, word, lnewstr); } while ((word = strstrword(word, oldstr))); return tgt; } static char * substip(char *tgt, const char *oldstr, struct in_addr ip) { return subst(tgt, oldstr, inet_ntoa(ip)); } static char * substlong(char *tgt, const char *oldstr, long l) { char buf[23]; snprintf(buf, sizeof buf, "%ld", l); return subst(tgt, oldstr, buf); } static char * substull(char *tgt, const char *oldstr, unsigned long long ull) { char buf[21]; snprintf(buf, sizeof buf, "%llu", ull); return subst(tgt, oldstr, buf); } #ifndef NOINET6 static char * substipv6(char *tgt, const char *oldstr, const struct ncpaddr *ip) { return subst(tgt, oldstr, ncpaddr_ntoa(ip)); } #ifndef NORADIUS static char * substipv6prefix(char *tgt, const char *oldstr, const uint8_t *ipv6prefix) { uint8_t ipv6addr[INET6_ADDRSTRLEN]; uint8_t prefix[INET6_ADDRSTRLEN + sizeof("/128") - 1]; if (ipv6prefix) { inet_ntop(AF_INET6, &ipv6prefix[2], ipv6addr, sizeof(ipv6addr)); snprintf(prefix, sizeof(prefix), "%s/%d", ipv6addr, ipv6prefix[1]); } else prefix[0] = '\0'; return subst(tgt, oldstr, prefix); } #endif #endif void command_Expand(char **nargv, int argc, char const *const *oargv, struct bundle *bundle, int inc0, pid_t pid) { int arg, secs; char uptime[20]; unsigned long long oin, oout, pin, pout; if (inc0) arg = 0; /* Start at arg 0 */ else { nargv[0] = strdup(oargv[0]); arg = 1; } secs = bundle_Uptime(bundle); snprintf(uptime, sizeof uptime, "%d:%02d:%02d", secs / 3600, (secs / 60) % 60, secs % 60); oin = bundle->ncp.ipcp.throughput.OctetsIn; oout = bundle->ncp.ipcp.throughput.OctetsOut; pin = bundle->ncp.ipcp.throughput.PacketsIn; pout = bundle->ncp.ipcp.throughput.PacketsOut; #ifndef NOINET6 oin += bundle->ncp.ipv6cp.throughput.OctetsIn; oout += bundle->ncp.ipv6cp.throughput.OctetsOut; pin += bundle->ncp.ipv6cp.throughput.PacketsIn; pout += bundle->ncp.ipv6cp.throughput.PacketsOut; #endif for (; arg < argc; arg++) { nargv[arg] = strdup(oargv[arg]); nargv[arg] = subst(nargv[arg], "AUTHNAME", bundle->cfg.auth.name); nargv[arg] = subst(nargv[arg], "COMPILATIONDATE", __DATE__); nargv[arg] = substip(nargv[arg], "DNS0", bundle->ncp.ipcp.ns.dns[0]); nargv[arg] = substip(nargv[arg], "DNS1", bundle->ncp.ipcp.ns.dns[1]); nargv[arg] = subst(nargv[arg], "ENDDISC", mp_Enddisc(bundle->ncp.mp.cfg.enddisc.class, bundle->ncp.mp.cfg.enddisc.address, bundle->ncp.mp.cfg.enddisc.len)); nargv[arg] = substip(nargv[arg], "HISADDR", bundle->ncp.ipcp.peer_ip); #ifndef NOINET6 nargv[arg] = substipv6(nargv[arg], "HISADDR6", &bundle->ncp.ipv6cp.hisaddr); #endif nargv[arg] = subst(nargv[arg], "INTERFACE", bundle->iface->name); nargv[arg] = substull(nargv[arg], "IPOCTETSIN", bundle->ncp.ipcp.throughput.OctetsIn); nargv[arg] = substull(nargv[arg], "IPOCTETSOUT", bundle->ncp.ipcp.throughput.OctetsOut); nargv[arg] = substull(nargv[arg], "IPPACKETSIN", bundle->ncp.ipcp.throughput.PacketsIn); nargv[arg] = substull(nargv[arg], "IPPACKETSOUT", bundle->ncp.ipcp.throughput.PacketsOut); #ifndef NOINET6 nargv[arg] = substull(nargv[arg], "IPV6OCTETSIN", bundle->ncp.ipv6cp.throughput.OctetsIn); nargv[arg] = substull(nargv[arg], "IPV6OCTETSOUT", bundle->ncp.ipv6cp.throughput.OctetsOut); nargv[arg] = substull(nargv[arg], "IPV6PACKETSIN", bundle->ncp.ipv6cp.throughput.PacketsIn); nargv[arg] = substull(nargv[arg], "IPV6PACKETSOUT", bundle->ncp.ipv6cp.throughput.PacketsOut); #endif nargv[arg] = subst(nargv[arg], "LABEL", bundle_GetLabel(bundle)); nargv[arg] = substip(nargv[arg], "MYADDR", bundle->ncp.ipcp.my_ip); #ifndef NOINET6 nargv[arg] = substipv6(nargv[arg], "MYADDR6", &bundle->ncp.ipv6cp.myaddr); #ifndef NORADIUS nargv[arg] = substipv6prefix(nargv[arg], "IPV6PREFIX", bundle->radius.ipv6prefix); #endif #endif nargv[arg] = substull(nargv[arg], "OCTETSIN", oin); nargv[arg] = substull(nargv[arg], "OCTETSOUT", oout); nargv[arg] = substull(nargv[arg], "PACKETSIN", pin); nargv[arg] = substull(nargv[arg], "PACKETSOUT", pout); nargv[arg] = subst(nargv[arg], "PEER_ENDDISC", mp_Enddisc(bundle->ncp.mp.peer.enddisc.class, bundle->ncp.mp.peer.enddisc.address, bundle->ncp.mp.peer.enddisc.len)); nargv[arg] = substlong(nargv[arg], "PROCESSID", pid); if (server.cfg.port) nargv[arg] = substlong(nargv[arg], "SOCKNAME", server.cfg.port); else nargv[arg] = subst(nargv[arg], "SOCKNAME", server.cfg.sockname); nargv[arg] = subst(nargv[arg], "UPTIME", uptime); nargv[arg] = subst(nargv[arg], "USER", bundle->ncp.mp.peer.authname); nargv[arg] = subst(nargv[arg], "VERSION", Version); } nargv[arg] = NULL; } void command_Free(int argc, char **argv) { while (argc) { free(*argv); argc--; argv++; } } static int ShellCommand(struct cmdargs const *arg, int bg) { const char *shell; pid_t shpid, pid; #ifdef SHELL_ONLY_INTERACTIVELY /* we're only allowed to shell when we run ppp interactively */ if (arg->prompt && arg->prompt->owner) { log_Printf(LogWARN, "Can't start a shell from a network connection\n"); return 1; } #endif if (arg->argc == arg->argn) { if (!arg->prompt) { log_Printf(LogWARN, "Can't start an interactive shell from" " a config file\n"); return 1; } else if (arg->prompt->owner) { log_Printf(LogWARN, "Can't start an interactive shell from" " a socket connection\n"); return 1; } else if (bg) { log_Printf(LogWARN, "Can only start an interactive shell in" " the foreground mode\n"); return 1; } } pid = getpid(); if ((shpid = fork()) == 0) { int i, fd; if ((shell = getenv("SHELL")) == 0) shell = _PATH_BSHELL; timer_TermService(); if (arg->prompt) fd = arg->prompt->fd_out; else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) { log_Printf(LogALERT, "Failed to open %s: %s\n", _PATH_DEVNULL, strerror(errno)); exit(1); } dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); for (i = getdtablesize(); i > STDERR_FILENO; i--) fcntl(i, F_SETFD, 1); #ifndef NOSUID setuid(ID0realuid()); #endif if (arg->argc > arg->argn) { /* substitute pseudo args */ char *argv[MAXARGS]; int argc = arg->argc - arg->argn; - if (argc >= sizeof argv / sizeof argv[0]) { + if (argc >= (int)(sizeof argv / sizeof argv[0])) { argc = sizeof argv / sizeof argv[0] - 1; log_Printf(LogWARN, "Truncating shell command to %d args\n", argc); } command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 0, pid); if (bg) { pid_t p; p = getpid(); if (daemon(1, 1) == -1) { log_Printf(LogERROR, "%ld: daemon: %s\n", (long)p, strerror(errno)); exit(1); } } else if (arg->prompt) printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]); execvp(argv[0], argv); } else { if (arg->prompt) printf("ppp: Pausing until %s finishes\n", shell); prompt_TtyOldMode(arg->prompt); execl(shell, shell, (char *)NULL); } log_Printf(LogWARN, "exec() of %s failed: %s\n", arg->argc > arg->argn ? arg->argv[arg->argn] : shell, strerror(errno)); _exit(255); } if (shpid == (pid_t)-1) log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno)); else { int status; waitpid(shpid, &status, 0); } if (arg->prompt && !arg->prompt->owner) prompt_TtyCommandMode(arg->prompt); return 0; } static int BgShellCommand(struct cmdargs const *arg) { if (arg->argc == arg->argn) return -1; return ShellCommand(arg, 1); } static int FgShellCommand(struct cmdargs const *arg) { return ShellCommand(arg, 0); } static int ResolvCommand(struct cmdargs const *arg) { if (arg->argc == arg->argn + 1) { if (!strcasecmp(arg->argv[arg->argn], "reload")) ipcp_LoadDNS(&arg->bundle->ncp.ipcp); else if (!strcasecmp(arg->argv[arg->argn], "restore")) ipcp_RestoreDNS(&arg->bundle->ncp.ipcp); else if (!strcasecmp(arg->argv[arg->argn], "rewrite")) ipcp_WriteDNS(&arg->bundle->ncp.ipcp); else if (!strcasecmp(arg->argv[arg->argn], "readonly")) arg->bundle->ncp.ipcp.ns.writable = 0; else if (!strcasecmp(arg->argv[arg->argn], "writable")) arg->bundle->ncp.ipcp.ns.writable = 1; else return -1; return 0; } return -1; } #ifndef NONAT static struct cmdtab const NatCommands[] = { {"addr", NULL, nat_RedirectAddr, LOCAL_AUTH, - "static address translation", "nat addr [addr_local addr_alias]"}, + "static address translation", "nat addr [addr_local addr_alias]", NULL}, {"deny_incoming", NULL, NatOption, LOCAL_AUTH, "stop incoming connections", "nat deny_incoming yes|no", (const void *) PKT_ALIAS_DENY_INCOMING}, {"enable", NULL, NatEnable, LOCAL_AUTH, - "enable NAT", "nat enable yes|no"}, + "enable NAT", "nat enable yes|no", NULL}, {"log", NULL, NatOption, LOCAL_AUTH, "log NAT link creation", "nat log yes|no", (const void *) PKT_ALIAS_LOG}, {"port", NULL, nat_RedirectPort, LOCAL_AUTH, "port redirection", - "nat port proto localaddr:port[-port] aliasport[-aliasport]"}, + "nat port proto localaddr:port[-port] aliasport[-aliasport]", NULL}, {"proto", NULL, nat_RedirectProto, LOCAL_AUTH, "protocol redirection", - "nat proto proto localIP [publicIP [remoteIP]]"}, + "nat proto proto localIP [publicIP [remoteIP]]", NULL}, {"proxy", NULL, nat_ProxyRule, LOCAL_AUTH, - "proxy control", "nat proxy server host[:port] ..."}, + "proxy control", "nat proxy server host[:port] ...", NULL}, #ifndef NO_FW_PUNCH {"punch_fw", NULL, nat_PunchFW, LOCAL_AUTH, - "firewall control", "nat punch_fw [base count]"}, + "firewall control", "nat punch_fw [base count]", NULL}, #endif {"skinny_port", NULL, nat_SkinnyPort, LOCAL_AUTH, - "TCP port used by Skinny Station protocol", "nat skinny_port [port]"}, + "TCP port used by Skinny Station protocol", "nat skinny_port [port]", NULL}, {"same_ports", NULL, NatOption, LOCAL_AUTH, "try to leave port numbers unchanged", "nat same_ports yes|no", (const void *) PKT_ALIAS_SAME_PORTS}, {"target", NULL, nat_SetTarget, LOCAL_AUTH, - "Default address for incoming connections", "nat target addr" }, + "Default address for incoming connections", "nat target addr", NULL}, {"unregistered_only", NULL, NatOption, LOCAL_AUTH, "translate unregistered (private) IP address space only", "nat unregistered_only yes|no", (const void *) PKT_ALIAS_UNREGISTERED_ONLY}, {"use_sockets", NULL, NatOption, LOCAL_AUTH, "allocate host sockets", "nat use_sockets yes|no", (const void *) PKT_ALIAS_USE_SOCKETS}, {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, "Display this message", "nat help|? [command]", NatCommands}, - {NULL, NULL, NULL}, + {NULL, NULL, NULL, 0, NULL, NULL, NULL}, }; #endif static struct cmdtab const AllowCommands[] = { {"modes", "mode", AllowModes, LOCAL_AUTH, - "Only allow certain ppp modes", "allow modes mode..."}, + "Only allow certain ppp modes", "allow modes mode...", NULL}, {"users", "user", AllowUsers, LOCAL_AUTH, - "Only allow ppp access to certain users", "allow users logname..."}, + "Only allow ppp access to certain users", "allow users logname...", NULL}, {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, "Display this message", "allow help|? [command]", AllowCommands}, - {NULL, NULL, NULL}, + {NULL, NULL, NULL, 0, NULL, NULL, NULL}, }; static struct cmdtab const IfaceCommands[] = { {"add", NULL, IfaceAddCommand, LOCAL_AUTH, "Add iface address", "iface add addr[/bits| mask] peer", NULL}, {NULL, "add!", IfaceAddCommand, LOCAL_AUTH, "Add or change an iface address", "iface add! addr[/bits| mask] peer", (void *)1}, {"clear", NULL, IfaceClearCommand, LOCAL_AUTH, - "Clear iface address(es)", "iface clear [INET | INET6]"}, + "Clear iface address(es)", "iface clear [INET | INET6]", NULL}, {"delete", "rm", IfaceDeleteCommand, LOCAL_AUTH, "Delete iface address", "iface delete addr", NULL}, {NULL, "rm!", IfaceDeleteCommand, LOCAL_AUTH, "Delete iface address", "iface delete addr", (void *)1}, {NULL, "delete!", IfaceDeleteCommand, LOCAL_AUTH, "Delete iface address", "iface delete addr", (void *)1}, {"show", NULL, iface_Show, LOCAL_AUTH, - "Show iface address(es)", "iface show"}, + "Show iface address(es)", "iface show", NULL}, {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, "Display this message", "nat help|? [command]", IfaceCommands}, - {NULL, NULL, NULL}, + {NULL, NULL, NULL, 0, NULL, NULL, NULL}, }; static struct cmdtab const Commands[] = { {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT, - "accept option request", "accept option .."}, + "accept option request", "accept option ..", NULL}, {"add", NULL, AddCommand, LOCAL_AUTH, "add route", "add dest mask gateway", NULL}, {NULL, "add!", AddCommand, LOCAL_AUTH, "add or change route", "add! dest mask gateway", (void *)1}, {"allow", "auth", RunListCommand, LOCAL_AUTH, "Allow ppp access", "allow users|modes ....", AllowCommands}, {"bg", "!bg", BgShellCommand, LOCAL_AUTH, - "Run a background command", "[!]bg command"}, + "Run a background command", "[!]bg command", NULL}, {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT, "Clear throughput statistics", - "clear ipcp|ipv6cp|physical [current|overall|peak]..."}, + "clear ipcp|ipv6cp|physical [current|overall|peak]...", NULL}, {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX, - "Clone a link", "clone newname..."}, + "Clone a link", "clone newname...", NULL}, {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT, - "Close an FSM", "close [lcp|ccp]"}, + "Close an FSM", "close [lcp|ccp]", NULL}, {"delete", NULL, DeleteCommand, LOCAL_AUTH, "delete route", "delete dest", NULL}, {NULL, "delete!", DeleteCommand, LOCAL_AUTH, "delete a route if it exists", "delete! dest", (void *)1}, {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT, - "Deny option request", "deny option .."}, + "Deny option request", "deny option ..", NULL}, {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT, "Dial and login", "dial|call [system ...]", NULL}, {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT, - "Disable option", "disable option .."}, + "Disable option", "disable option ..", NULL}, {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT, - "Generate a down event", "down [ccp|lcp]"}, + "Generate a down event", "down [ccp|lcp]", NULL}, {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT, - "Enable option", "enable option .."}, + "Enable option", "enable option ..", NULL}, {"ident", NULL, IdentCommand, LOCAL_AUTH | LOCAL_CX, - "Set the link identity", "ident text..."}, + "Set the link identity", "ident text...", NULL}, {"iface", "interface", RunListCommand, LOCAL_AUTH, "interface control", "iface option ...", IfaceCommands}, {"link", "datalink", LinkCommand, LOCAL_AUTH, - "Link specific commands", "link name command ..."}, + "Link specific commands", "link name command ...", NULL}, {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT, - "Load settings", "load [system ...]"}, + "Load settings", "load [system ...]", NULL}, {"log", NULL, LogCommand, LOCAL_AUTH | LOCAL_CX_OPT, - "log information", "log word ..."}, + "log information", "log word ...", NULL}, #ifndef NONAT {"nat", "alias", RunListCommand, LOCAL_AUTH, "NAT control", "nat option yes|no", NatCommands}, #endif {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT, "Open an FSM", "open! [lcp|ccp|ipcp]", (void *)1}, {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH, - "Password for manipulation", "passwd LocalPassword"}, + "Password for manipulation", "passwd LocalPassword", NULL}, {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH, - "Quit PPP program", "quit|bye [all]"}, + "Quit PPP program", "quit|bye [all]", NULL}, {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX, - "Remove a link", "remove"}, + "Remove a link", "remove", NULL}, {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX, - "Rename a link", "rename name"}, + "Rename a link", "rename name", NULL}, {"resolv", NULL, ResolvCommand, LOCAL_AUTH, - "Manipulate resolv.conf", "resolv readonly|reload|restore|rewrite|writable"}, + "Manipulate resolv.conf", "resolv readonly|reload|restore|rewrite|writable", + NULL}, {"save", NULL, SaveCommand, LOCAL_AUTH, - "Save settings", "save"}, + "Save settings", "save", NULL}, {"sendident", NULL, SendIdentification, LOCAL_AUTH | LOCAL_CX, - "Transmit the link identity", "sendident"}, + "Transmit the link identity", "sendident", NULL}, {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT, - "Set parameters", "set[up] var value"}, + "Set parameters", "set[up] var value", NULL}, {"shell", "!", FgShellCommand, LOCAL_AUTH, - "Run a subshell", "shell|! [sh command]"}, + "Run a subshell", "shell|! [sh command]", NULL}, {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT, - "Show status and stats", "show var"}, + "Show status and stats", "show var", NULL}, {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX, - "Enter terminal mode", "term"}, + "Enter terminal mode", "term", NULL}, {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, "Display this message", "help|? [command]", Commands}, - {NULL, NULL, NULL}, + {NULL, NULL, NULL, 0, NULL, NULL, NULL}, }; static int ShowEscape(struct cmdargs const *arg) { if (arg->cx->physical->async.cfg.EscMap[32]) { int code, bit; const 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(arg->prompt, "%s0x%02x", sep, (code << 3) + bit); sep = ", "; } prompt_Printf(arg->prompt, "\n"); } return 0; } static int ShowTimerList(struct cmdargs const *arg) { timer_Show(0, arg->prompt); return 0; } static int ShowStopped(struct cmdargs const *arg) { prompt_Printf(arg->prompt, " Stopped Timer: LCP: "); if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load) prompt_Printf(arg->prompt, "Disabled"); else prompt_Printf(arg->prompt, "%ld secs", arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS); prompt_Printf(arg->prompt, ", CCP: "); if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load) prompt_Printf(arg->prompt, "Disabled"); else prompt_Printf(arg->prompt, "%ld secs", arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS); prompt_Printf(arg->prompt, "\n"); return 0; } static int ShowVersion(struct cmdargs const *arg) { prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, __DATE__); return 0; } static int ShowProtocolStats(struct cmdargs const *arg) { struct link *l = command_ChooseLink(arg); prompt_Printf(arg->prompt, "%s:\n", l->name); link_ReportProtocolStatus(l, arg->prompt); return 0; } static struct cmdtab const ShowCommands[] = { {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH, - "bundle details", "show bundle"}, + "bundle details", "show bundle", NULL}, {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT, - "CCP status", "show cpp"}, + "CCP status", "show cpp", NULL}, {"compress", NULL, sl_Show, LOCAL_AUTH, - "VJ compression stats", "show compress"}, + "VJ compression stats", "show compress", NULL}, {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX, - "escape characters", "show escape"}, + "escape characters", "show escape", NULL}, {"filter", NULL, filter_Show, LOCAL_AUTH, - "packet filters", "show filter [in|out|dial|alive]"}, + "packet filters", "show filter [in|out|dial|alive]", NULL}, {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX, - "HDLC errors", "show hdlc"}, + "HDLC errors", "show hdlc", NULL}, {"iface", "interface", iface_Show, LOCAL_AUTH, - "Interface status", "show iface"}, + "Interface status", "show iface", NULL}, {"ipcp", NULL, ipcp_Show, LOCAL_AUTH, - "IPCP status", "show ipcp"}, + "IPCP status", "show ipcp", NULL}, #ifndef NOINET6 {"ipv6cp", NULL, ipv6cp_Show, LOCAL_AUTH, - "IPV6CP status", "show ipv6cp"}, + "IPV6CP status", "show ipv6cp", NULL}, #endif {"layers", NULL, link_ShowLayers, LOCAL_AUTH | LOCAL_CX_OPT, - "Protocol layers", "show layers"}, + "Protocol layers", "show layers", NULL}, {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX, - "LCP status", "show lcp"}, + "LCP status", "show lcp", NULL}, {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX, - "(high-level) link info", "show link"}, + "(high-level) link info", "show link", NULL}, {"links", NULL, bundle_ShowLinks, LOCAL_AUTH, - "available link names", "show links"}, + "available link names", "show links", NULL}, {"log", NULL, log_ShowLevel, LOCAL_AUTH, - "log levels", "show log"}, + "log levels", "show log", NULL}, {"mem", NULL, mbuf_Show, LOCAL_AUTH, - "mbuf allocations", "show mem"}, + "mbuf allocations", "show mem", NULL}, {"ncp", NULL, ncp_Show, LOCAL_AUTH, - "NCP status", "show ncp"}, + "NCP status", "show ncp", NULL}, {"physical", NULL, physical_ShowStatus, LOCAL_AUTH | LOCAL_CX, - "(low-level) link info", "show physical"}, + "(low-level) link info", "show physical", NULL}, {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH, - "multilink setup", "show mp"}, + "multilink setup", "show mp", NULL}, {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT, - "protocol summary", "show proto"}, + "protocol summary", "show proto", NULL}, {"route", NULL, route_Show, LOCAL_AUTH, - "routing table", "show route"}, + "routing table", "show route", NULL}, {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX, - "STOPPED timeout", "show stopped"}, + "STOPPED timeout", "show stopped", NULL}, {"timers", NULL, ShowTimerList, LOCAL_AUTH, - "alarm timers", "show timers"}, + "alarm timers", "show timers", NULL}, {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH, - "version string", "show version"}, + "version string", "show version", NULL}, {"who", NULL, log_ShowWho, LOCAL_AUTH, - "client list", "show who"}, + "client list", "show who", NULL}, {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH, "Display this message", "show help|? [command]", ShowCommands}, - {NULL, NULL, NULL}, + {NULL, NULL, NULL, 0, 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 const char * mkPrefix(int argc, char const *const *argv, char *tgt, int sz) { int f, tlen, len; tlen = 0; for (f = 0; f < argc && tlen < sz - 2; f++) { if (f) tgt[tlen++] = ' '; len = strlen(argv[f]); if (len > sz - tlen - 1) len = sz - tlen - 1; strncpy(tgt+tlen, argv[f], len); tlen += len; } tgt[tlen] = '\0'; return tgt; } static int FindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn, char const *const *argv, struct prompt *prompt, struct datalink *cx) { struct cmdtab const *cmd; int val = 1; int nmatch; struct cmdargs arg; char prefix[100]; cmd = FindCommand(cmds, argv[argn], &nmatch); if (nmatch > 1) log_Printf(LogWARN, "%s: Ambiguous command\n", mkPrefix(argn+1, argv, prefix, sizeof prefix)); else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) { 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) log_Printf(LogWARN, "%s: No context (use the `link' command)\n", mkPrefix(argn+1, argv, prefix, sizeof prefix)); else { if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) { log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n", mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name); cx = NULL; } arg.cmdtab = cmds; arg.cmd = cmd; arg.argc = argc; arg.argn = argn+1; arg.argv = argv; arg.bundle = bundle; arg.cx = cx; arg.prompt = prompt; val = (*cmd->func) (&arg); } } else log_Printf(LogWARN, "%s: Invalid command\n", mkPrefix(argn+1, argv, prefix, sizeof prefix)); if (val == -1) log_Printf(LogWARN, "usage: %s\n", cmd->syntax); else if (val) log_Printf(LogWARN, "%s: Failed %d\n", mkPrefix(argn+1, argv, prefix, sizeof prefix), val); return val; } int command_Expand_Interpret(char *buff, int nb, char *argv[MAXARGS], int offset) { char buff2[LINE_LEN-offset]; InterpretArg(buff, buff2); strncpy(buff, buff2, LINE_LEN - offset - 1); buff[LINE_LEN - offset - 1] = '\0'; return command_Interpret(buff, nb, argv); } int command_Interpret(char *buff, int nb, char *argv[MAXARGS]) { char *cp; if (nb > 0) { cp = buff + strcspn(buff, "\r\n"); if (cp) *cp = '\0'; return MakeArgs(buff, argv, MAXARGS, PARSE_REDUCE); } return 0; } static int -arghidden(int argc, char const *const *argv, int n) +arghidden(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; /* set server port xxxxx .... */ if (n == 3 && !strncasecmp(argv[0], "se", 2) && !strncasecmp(argv[1], "se", 2)) return 1; return 0; } void command_Run(struct bundle *bundle, int argc, char const *const *argv, struct prompt *prompt, const char *label, struct datalink *cx) { if (argc > 0) { if (log_IsKept(LogCOMMAND)) { char buf[LINE_LEN]; - int f, n; + int f; + size_t n; if (label) { strncpy(buf, label, sizeof buf - 3); buf[sizeof buf - 3] = '\0'; strcat(buf, ": "); n = strlen(buf); } else { *buf = '\0'; n = 0; } buf[sizeof buf - 1] = '\0'; /* In case we run out of room in buf */ for (f = 0; f < argc; f++) { if (n < sizeof buf - 1 && f) buf[n++] = ' '; - if (arghidden(argc, argv, f)) + if (arghidden(argv, f)) strncpy(buf+n, "********", sizeof buf - n - 1); else strncpy(buf+n, argv[f], sizeof buf - n - 1); n += strlen(buf+n); } log_Printf(LogCOMMAND, "%s\n", buf); } FindExec(bundle, Commands, argc, 0, argv, prompt, cx); } } int command_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt, const char *label) { int argc; char *argv[MAXARGS]; if ((argc = command_Expand_Interpret(buff, nb, argv, 0)) < 0) return 0; command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL); return 1; } static int ShowCommand(struct cmdargs const *arg) { if (!arg->prompt) log_Printf(LogWARN, "show: Cannot show without a prompt\n"); else if (arg->argc > arg->argn) FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv, arg->prompt, arg->cx); else prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n"); return 0; } static int TerminalCommand(struct cmdargs const *arg) { if (!arg->prompt) { log_Printf(LogWARN, "term: Need a prompt\n"); return 1; } if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) { prompt_Printf(arg->prompt, "LCP state is [%s]\n", State2Nam(arg->cx->physical->link.lcp.fsm.state)); return 1; } datalink_Up(arg->cx, 0, 0); prompt_TtyTermMode(arg->prompt, arg->cx); return 0; } static int QuitCommand(struct cmdargs const *arg) { if (!arg->prompt || prompt_IsController(arg->prompt) || (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") && (arg->prompt->auth & LOCAL_AUTH))) - Cleanup(EX_NORMAL); + Cleanup(); if (arg->prompt) prompt_Destroy(arg->prompt, 1); return 0; } static int OpenCommand(struct cmdargs const *arg) { if (arg->argc == arg->argn) bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1); else if (arg->argc == arg->argn + 1) { if (!strcasecmp(arg->argv[arg->argn], "lcp")) { struct datalink *cx = arg->cx ? arg->cx : bundle2datalink(arg->bundle, NULL); if (cx) { if (cx->physical->link.lcp.fsm.state == ST_OPENED) fsm_Reopen(&cx->physical->link.lcp.fsm); else bundle_Open(arg->bundle, cx->name, PHYS_ALL, 1); } else log_Printf(LogWARN, "open lcp: You must specify a link\n"); } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) { struct fsm *fp; fp = &command_ChooseLink(arg)->ccp.fsm; if (fp->link->lcp.fsm.state != ST_OPENED) log_Printf(LogWARN, "open: LCP must be open before opening CCP\n"); else if (fp->state == ST_OPENED) fsm_Reopen(fp); else { fp->open_mode = 0; /* Not passive any more */ if (fp->state == ST_STOPPED) { fsm_Down(fp); fsm_Up(fp); } else { fsm_Up(fp); fsm_Open(fp); } } } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) { if (arg->cx) log_Printf(LogWARN, "open ipcp: You need not specify a link\n"); if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED) fsm_Reopen(&arg->bundle->ncp.ipcp.fsm); else bundle_Open(arg->bundle, NULL, PHYS_ALL, 1); } else return -1; } else return -1; return 0; } static int CloseCommand(struct cmdargs const *arg) { if (arg->argc == arg->argn) bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN); else if (arg->argc == arg->argn + 1) { if (!strcasecmp(arg->argv[arg->argn], "lcp")) bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP); else if (!strcasecmp(arg->argv[arg->argn], "ccp") || !strcasecmp(arg->argv[arg->argn], "ccp!")) { struct fsm *fp; fp = &command_ChooseLink(arg)->ccp.fsm; if (fp->state == ST_OPENED) { fsm_Close(fp); if (arg->argv[arg->argn][3] == '!') fp->open_mode = 0; /* Stay ST_CLOSED */ else fp->open_mode = OPEN_PASSIVE; /* Wait for the peer to start */ } } else return -1; } else return -1; return 0; } static int DownCommand(struct cmdargs const *arg) { if (arg->argc == arg->argn) { if (arg->cx) datalink_Down(arg->cx, CLOSE_STAYDOWN); else bundle_Down(arg->bundle, CLOSE_STAYDOWN); } else if (arg->argc == arg->argn + 1) { if (!strcasecmp(arg->argv[arg->argn], "lcp")) { if (arg->cx) datalink_Down(arg->cx, CLOSE_LCP); else bundle_Down(arg->bundle, CLOSE_LCP); } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) { struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm : &arg->bundle->ncp.mp.link.ccp.fsm; fsm2initial(fp); } else return -1; } else return -1; return 0; } static int SetModemSpeed(struct cmdargs const *arg) { long speed; char *end; if (arg->argc > arg->argn && *arg->argv[arg->argn]) { if (arg->argc > arg->argn+1) { log_Printf(LogWARN, "SetModemSpeed: Too many arguments\n"); return -1; } if (strcasecmp(arg->argv[arg->argn], "sync") == 0) { physical_SetSync(arg->cx->physical); return 0; } end = NULL; speed = strtol(arg->argv[arg->argn], &end, 10); - if (*end) { + if (*end || speed < 0) { log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"", arg->argv[arg->argn]); return -1; } if (physical_SetSpeed(arg->cx->physical, speed)) return 0; log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]); } else log_Printf(LogWARN, "SetModemSpeed: No speed specified\n"); return -1; } static int SetStoppedTimeout(struct cmdargs const *arg) { struct link *l = &arg->cx->physical->link; l->lcp.fsm.StoppedTimer.load = 0; l->ccp.fsm.StoppedTimer.load = 0; if (arg->argc <= arg->argn+2) { if (arg->argc > arg->argn) { l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS; if (arg->argc > arg->argn+1) l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS; } return 0; } return -1; } static int SetServer(struct cmdargs const *arg) { int res = -1; if (arg->argc > arg->argn && arg->argc < arg->argn+4) { const char *port, *passwd, *mask; - int mlen; + size_t mlen; /* What's what ? */ port = arg->argv[arg->argn]; if (arg->argc == arg->argn + 2) { passwd = arg->argv[arg->argn+1]; mask = NULL; } else if (arg->argc == arg->argn + 3) { passwd = arg->argv[arg->argn+1]; mask = arg->argv[arg->argn+2]; mlen = strlen(mask); if (mlen == 0 || mlen > 4 || strspn(mask, "01234567") != mlen || (mlen == 4 && *mask != '0')) { log_Printf(LogWARN, "%s %s: %s: Invalid mask\n", arg->argv[arg->argn - 2], arg->argv[arg->argn - 1], mask); return -1; } } else if (arg->argc != arg->argn + 1) return -1; else if (strcasecmp(port, "none") == 0) { if (server_Clear(arg->bundle)) log_Printf(LogPHASE, "Disabled server socket\n"); return 0; } else if (strcasecmp(port, "open") == 0) { switch (server_Reopen(arg->bundle)) { case SERVER_OK: return 0; case SERVER_FAILED: log_Printf(LogWARN, "Failed to reopen server port\n"); return 1; case SERVER_UNSET: log_Printf(LogWARN, "Cannot reopen unset server socket\n"); return 1; default: break; } return -1; } else if (strcasecmp(port, "closed") == 0) { if (server_Close(arg->bundle)) log_Printf(LogPHASE, "Closed server socket\n"); else log_Printf(LogWARN, "Server socket not open\n"); return 0; } else return -1; strncpy(server.cfg.passwd, passwd, sizeof server.cfg.passwd - 1); server.cfg.passwd[sizeof server.cfg.passwd - 1] = '\0'; if (*port == '/') { mode_t imask; char *ptr, name[LINE_LEN + 12]; if (mask == NULL) imask = (mode_t)-1; else for (imask = mlen = 0; mask[mlen]; mlen++) imask = (imask * 8) + mask[mlen] - '0'; ptr = strstr(port, "%d"); if (ptr) { snprintf(name, sizeof name, "%.*s%d%s", (int)(ptr - port), port, arg->bundle->unit, ptr + 2); port = name; } res = server_LocalOpen(arg->bundle, port, imask); } else { int iport, add = 0; if (mask != NULL) return -1; if (*port == '+') { port++; add = 1; } if (strspn(port, "0123456789") != strlen(port)) { struct servent *s; if ((s = getservbyname(port, "tcp")) == NULL) { iport = 0; log_Printf(LogWARN, "%s: Invalid port or service\n", port); } else iport = ntohs(s->s_port); } else iport = atoi(port); if (iport) { if (add) iport += arg->bundle->unit; res = server_TcpOpen(arg->bundle, iport); } else res = -1; } } return res; } static int SetEscape(struct cmdargs const *arg) { int code; int argc = arg->argc - arg->argn; char const *const *argv = arg->argv + arg->argn; 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 SetInterfaceAddr(struct cmdargs const *arg) { struct ncp *ncp = &arg->bundle->ncp; struct ncpaddr ncpaddr; const char *hisaddr; if (arg->argc > arg->argn + 4) return -1; hisaddr = NULL; memset(&ncp->ipcp.cfg.my_range, '\0', sizeof ncp->ipcp.cfg.my_range); memset(&ncp->ipcp.cfg.peer_range, '\0', sizeof ncp->ipcp.cfg.peer_range); ncp->ipcp.cfg.HaveTriggerAddress = 0; ncp->ipcp.cfg.netmask.s_addr = INADDR_ANY; iplist_reset(&ncp->ipcp.cfg.peer_list); if (arg->argc > arg->argn) { if (!ncprange_aton(&ncp->ipcp.cfg.my_range, ncp, arg->argv[arg->argn])) return 1; if (arg->argc > arg->argn+1) { hisaddr = arg->argv[arg->argn+1]; if (arg->argc > arg->argn+2) { ncp->ipcp.ifmask = ncp->ipcp.cfg.netmask = GetIpAddr(arg->argv[arg->argn+2]); if (arg->argc > arg->argn+3) { ncp->ipcp.cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]); ncp->ipcp.cfg.HaveTriggerAddress = 1; } } } } /* 0.0.0.0 means any address (0 bits) */ ncprange_getaddr(&ncp->ipcp.cfg.my_range, &ncpaddr); ncpaddr_getip4(&ncpaddr, &ncp->ipcp.my_ip); if (ncp->ipcp.my_ip.s_addr == INADDR_ANY) ncprange_setwidth(&ncp->ipcp.cfg.my_range, 0); bundle_AdjustFilters(arg->bundle, &ncpaddr, NULL); if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr, arg->bundle->phys_type.all & PHYS_AUTO)) return 4; return 0; } static int SetRetry(int argc, char const *const *argv, u_int *timeout, u_int *maxreq, u_int *maxtrm, int def) { if (argc == 0) { *timeout = DEF_FSMRETRY; *maxreq = def; if (maxtrm != NULL) *maxtrm = def; } else { long l = atol(argv[0]); if (l < MIN_FSMRETRY) { log_Printf(LogWARN, "%ld: Invalid FSM retry period - min %d\n", l, MIN_FSMRETRY); return 1; } else *timeout = l; if (argc > 1) { l = atol(argv[1]); if (l < 1) { log_Printf(LogWARN, "%ld: Invalid FSM REQ tries - changed to 1\n", l); l = 1; } *maxreq = l; if (argc > 2 && maxtrm != NULL) { l = atol(argv[2]); if (l < 1) { log_Printf(LogWARN, "%ld: Invalid FSM TRM tries - changed to 1\n", l); l = 1; } *maxtrm = l; } } } return 0; } static int SetVariable(struct cmdargs const *arg) { long long_val, param = (long)arg->cmd->args; int mode, dummyint, f, first, res; u_short *change; const char *argp; struct datalink *cx = arg->cx; /* LOCAL_CX uses this */ struct link *l = command_ChooseLink(arg); /* LOCAL_CX_OPT uses this */ struct in_addr *ipaddr; struct ncpaddr ncpaddr[2]; if (arg->argc > arg->argn) argp = arg->argv[arg->argn]; else argp = ""; res = 0; if ((arg->cmd->lauth & LOCAL_CX) && !cx) { log_Printf(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))) { log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n", arg->cmd->name, cx->name); cx = NULL; } switch (param) { case VAR_AUTHKEY: strncpy(arg->bundle->cfg.auth.key, argp, sizeof arg->bundle->cfg.auth.key - 1); arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0'; break; case VAR_AUTHNAME: switch (bundle_Phase(arg->bundle)) { default: log_Printf(LogWARN, "Altering authname while at phase %s\n", bundle_PhaseName(arg->bundle)); /* drop through */ case PHASE_DEAD: case PHASE_ESTABLISH: strncpy(arg->bundle->cfg.auth.name, argp, sizeof arg->bundle->cfg.auth.name - 1); arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name-1] = '\0'; break; } break; case VAR_AUTOLOAD: if (arg->argc == arg->argn + 3) { int v1, v2, v3; char *end; v1 = strtol(arg->argv[arg->argn], &end, 0); if (v1 < 0 || *end) { log_Printf(LogWARN, "autoload: %s: Invalid min percentage\n", arg->argv[arg->argn]); res = 1; break; } v2 = strtol(arg->argv[arg->argn + 1], &end, 0); if (v2 < 0 || *end) { log_Printf(LogWARN, "autoload: %s: Invalid max percentage\n", arg->argv[arg->argn + 1]); res = 1; break; } if (v2 < v1) { v3 = v1; v1 = v2; v2 = v3; } v3 = strtol(arg->argv[arg->argn + 2], &end, 0); if (v3 <= 0 || *end) { log_Printf(LogWARN, "autoload: %s: Invalid throughput period\n", arg->argv[arg->argn + 2]); res = 1; break; } arg->bundle->ncp.mp.cfg.autoload.min = v1; arg->bundle->ncp.mp.cfg.autoload.max = v2; arg->bundle->ncp.mp.cfg.autoload.period = v3; mp_RestartAutoloadTimer(&arg->bundle->ncp.mp); } else { log_Printf(LogWARN, "Set autoload requires three arguments\n"); res = 1; } break; case VAR_DIAL: 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: 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_WINSIZE: if (arg->argc > arg->argn) { l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]); if (l->ccp.cfg.deflate.out.winsize < 8 || l->ccp.cfg.deflate.out.winsize > 15) { log_Printf(LogWARN, "%d: Invalid outgoing window size\n", l->ccp.cfg.deflate.out.winsize); l->ccp.cfg.deflate.out.winsize = 15; } if (arg->argc > arg->argn+1) { l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]); if (l->ccp.cfg.deflate.in.winsize < 8 || l->ccp.cfg.deflate.in.winsize > 15) { log_Printf(LogWARN, "%d: Invalid incoming window size\n", l->ccp.cfg.deflate.in.winsize); l->ccp.cfg.deflate.in.winsize = 15; } } else l->ccp.cfg.deflate.in.winsize = 0; } else { log_Printf(LogWARN, "No window size specified\n"); res = 1; } break; #ifndef NODES case VAR_MPPE: if (arg->argc > arg->argn + 2) { res = -1; break; } if (arg->argc == arg->argn) { l->ccp.cfg.mppe.keybits = 0; l->ccp.cfg.mppe.state = MPPE_ANYSTATE; l->ccp.cfg.mppe.required = 0; break; } if (!strcmp(argp, "*")) long_val = 0; else { long_val = atol(argp); if (long_val != 40 && long_val != 56 && long_val != 128) { log_Printf(LogWARN, "%s: Invalid bits value\n", argp); res = -1; break; } } if (arg->argc == arg->argn + 2) { if (!strcmp(arg->argv[arg->argn + 1], "*")) l->ccp.cfg.mppe.state = MPPE_ANYSTATE; else if (!strcasecmp(arg->argv[arg->argn + 1], "stateless")) l->ccp.cfg.mppe.state = MPPE_STATELESS; else if (!strcasecmp(arg->argv[arg->argn + 1], "stateful")) l->ccp.cfg.mppe.state = MPPE_STATEFUL; else { log_Printf(LogWARN, "%s: Invalid state value\n", arg->argv[arg->argn + 1]); res = -1; break; } } else l->ccp.cfg.mppe.state = MPPE_ANYSTATE; l->ccp.cfg.mppe.keybits = long_val; l->ccp.cfg.mppe.required = 1; break; #endif case VAR_DEVICE: physical_SetDeviceList(cx->physical, arg->argc - arg->argn, arg->argv + arg->argn); break; case VAR_ACCMAP: if (arg->argc > arg->argn) { u_long ulong_val; sscanf(argp, "%lx", &ulong_val); cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val; } else { log_Printf(LogWARN, "No accmap specified\n"); res = 1; } break; case VAR_MODE: mode = Nam2mode(argp); if (mode == PHYS_NONE || mode == PHYS_ALL) { log_Printf(LogWARN, "%s: Invalid mode\n", argp); res = -1; break; } bundle_SetMode(arg->bundle, cx, mode); break; case VAR_MRRU: switch (bundle_Phase(arg->bundle)) { case PHASE_DEAD: break; case PHASE_ESTABLISH: /* Make sure none of our links are DATALINK_LCP or greater */ if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) { log_Printf(LogWARN, "mrru: Only changable before LCP negotiations\n"); res = 1; break; } break; default: log_Printf(LogWARN, "mrru: Only changable at phase DEAD/ESTABLISH\n"); res = 1; break; } if (res != 0) break; long_val = atol(argp); if (long_val && long_val < MIN_MRU) { log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU); res = 1; break; } else if (long_val > MAX_MRU) { log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU); res = 1; break; } else arg->bundle->ncp.mp.cfg.mrru = long_val; break; case VAR_MRU: long_val = 0; /* silence gcc */ change = NULL; /* silence gcc */ switch(arg->argc - arg->argn) { case 1: if (argp[strspn(argp, "0123456789")] != '\0') { res = -1; break; } /*FALLTHRU*/ case 0: long_val = atol(argp); change = &l->lcp.cfg.mru; if (long_val > l->lcp.cfg.max_mru) { log_Printf(LogWARN, "MRU %ld: too large - max set to %d\n", long_val, l->lcp.cfg.max_mru); res = 1; break; } break; case 2: if (strcasecmp(argp, "max") && strcasecmp(argp, "maximum")) { res = -1; break; } long_val = atol(arg->argv[arg->argn + 1]); change = &l->lcp.cfg.max_mru; if (long_val > MAX_MRU) { log_Printf(LogWARN, "MRU %ld: too large - maximum is %d\n", long_val, MAX_MRU); res = 1; break; } break; default: res = -1; break; } if (res != 0) break; if (long_val == 0) *change = 0; else if (long_val < MIN_MRU) { log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU); res = 1; break; } else if (long_val > MAX_MRU) { log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU); res = 1; break; } else *change = long_val; if (l->lcp.cfg.mru > *change) l->lcp.cfg.mru = *change; break; case VAR_MTU: long_val = 0; /* silence gcc */ change = NULL; /* silence gcc */ switch(arg->argc - arg->argn) { case 1: if (argp[strspn(argp, "0123456789")] != '\0') { res = -1; break; } /*FALLTHRU*/ case 0: long_val = atol(argp); change = &l->lcp.cfg.mtu; if (long_val > l->lcp.cfg.max_mtu) { log_Printf(LogWARN, "MTU %ld: too large - max set to %d\n", long_val, l->lcp.cfg.max_mtu); res = 1; break; } break; case 2: if (strcasecmp(argp, "max") && strcasecmp(argp, "maximum")) { res = -1; break; } long_val = atol(arg->argv[arg->argn + 1]); change = &l->lcp.cfg.max_mtu; if (long_val > MAX_MTU) { log_Printf(LogWARN, "MTU %ld: too large - maximum is %d\n", long_val, MAX_MTU); res = 1; break; } break; default: res = -1; break; } if (res != 0) break; if (long_val && long_val < MIN_MTU) { log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU); res = 1; break; } else if (long_val > MAX_MTU) { log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU); res = 1; break; } else *change = long_val; if (l->lcp.cfg.mtu > *change) l->lcp.cfg.mtu = *change; break; case VAR_OPENMODE: if (strcasecmp(argp, "active") == 0) cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ? atoi(arg->argv[arg->argn+1]) : 1; else if (strcasecmp(argp, "passive") == 0) cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE; else { log_Printf(LogWARN, "%s: Invalid openmode\n", argp); res = 1; } break; case VAR_PHONE: strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1); cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0'; cx->phone.alt = cx->phone.next = NULL; break; case VAR_HANGUP: strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1); cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0'; break; case VAR_IFQUEUE: long_val = atol(argp); arg->bundle->cfg.ifqueue = long_val < 0 ? 0 : long_val; break; case VAR_LOGOUT: strncpy(cx->cfg.script.logout, argp, sizeof cx->cfg.script.logout - 1); cx->cfg.script.logout[sizeof cx->cfg.script.logout - 1] = '\0'; break; case VAR_IDLETIMEOUT: if (arg->argc > arg->argn+2) { log_Printf(LogWARN, "Too many idle timeout values\n"); res = 1; } else if (arg->argc == arg->argn) { log_Printf(LogWARN, "Too few idle timeout values\n"); res = 1; } else { - int timeout, min; + unsigned long timeout, min; - timeout = atoi(argp); - min = arg->argc == arg->argn + 2 ? atoi(arg->argv[arg->argn + 1]) : -1; + timeout = strtoul(argp, NULL, 10); + min = arg->bundle->cfg.idle.min_timeout; + if (arg->argc == arg->argn + 2) + min = strtoul(arg->argv[arg->argn + 1], NULL, 10); bundle_SetIdleTimer(arg->bundle, timeout, min); } break; #ifndef NORADIUS case VAR_RAD_ALIVE: if (arg->argc > arg->argn + 2) { log_Printf(LogWARN, "Too many RADIUS alive interval values\n"); res = 1; } else if (arg->argc == arg->argn) { log_Printf(LogWARN, "Too few RADIUS alive interval values\n"); res = 1; } else { arg->bundle->radius.alive.interval = atoi(argp); if (arg->bundle->radius.alive.interval && !arg->bundle->radius.cfg.file) { log_Printf(LogWARN, "rad_alive requires radius to be configured\n"); res = 1; } else if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED) { if (arg->bundle->radius.alive.interval) radius_StartTimer(arg->bundle); else radius_StopTimer(&arg->bundle->radius); } } break; #endif case VAR_LQRPERIOD: long_val = atol(argp); if (long_val < MIN_LQRPERIOD) { log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n", long_val, MIN_LQRPERIOD); res = 1; } else l->lcp.cfg.lqrperiod = long_val; break; case VAR_LCPRETRY: res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn, &cx->physical->link.lcp.cfg.fsm.timeout, &cx->physical->link.lcp.cfg.fsm.maxreq, &cx->physical->link.lcp.cfg.fsm.maxtrm, DEF_FSMTRIES); break; case VAR_CHAPRETRY: res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn, &cx->chap.auth.cfg.fsm.timeout, &cx->chap.auth.cfg.fsm.maxreq, NULL, DEF_FSMAUTHTRIES); break; case VAR_PAPRETRY: res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn, &cx->pap.cfg.fsm.timeout, &cx->pap.cfg.fsm.maxreq, NULL, DEF_FSMAUTHTRIES); break; case VAR_CCPRETRY: res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn, &l->ccp.cfg.fsm.timeout, &l->ccp.cfg.fsm.maxreq, &l->ccp.cfg.fsm.maxtrm, DEF_FSMTRIES); break; case VAR_IPCPRETRY: res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn, &arg->bundle->ncp.ipcp.cfg.fsm.timeout, &arg->bundle->ncp.ipcp.cfg.fsm.maxreq, &arg->bundle->ncp.ipcp.cfg.fsm.maxtrm, DEF_FSMTRIES); break; #ifndef NOINET6 case VAR_IPV6CPRETRY: res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn, &arg->bundle->ncp.ipv6cp.cfg.fsm.timeout, &arg->bundle->ncp.ipv6cp.cfg.fsm.maxreq, &arg->bundle->ncp.ipv6cp.cfg.fsm.maxtrm, DEF_FSMTRIES); break; #endif case VAR_NBNS: case VAR_DNS: if (param == VAR_DNS) { ipaddr = arg->bundle->ncp.ipcp.cfg.ns.dns; ipaddr[0].s_addr = ipaddr[1].s_addr = INADDR_NONE; } else { ipaddr = arg->bundle->ncp.ipcp.cfg.ns.nbns; ipaddr[0].s_addr = ipaddr[1].s_addr = INADDR_ANY; } if (arg->argc > arg->argn) { ncpaddr_aton(ncpaddr, &arg->bundle->ncp, arg->argv[arg->argn]); if (!ncpaddr_getip4(ncpaddr, ipaddr)) return -1; if (arg->argc > arg->argn+1) { ncpaddr_aton(ncpaddr + 1, &arg->bundle->ncp, arg->argv[arg->argn + 1]); if (!ncpaddr_getip4(ncpaddr + 1, ipaddr + 1)) return -1; } if (ipaddr[0].s_addr == INADDR_ANY) { ipaddr[0] = ipaddr[1]; ipaddr[1].s_addr = INADDR_ANY; } if (ipaddr[0].s_addr == INADDR_NONE) { ipaddr[0] = ipaddr[1]; ipaddr[1].s_addr = INADDR_NONE; } } break; case VAR_CALLBACK: cx->cfg.callback.opmask = 0; for (dummyint = arg->argn; dummyint < arg->argc; dummyint++) { if (!strcasecmp(arg->argv[dummyint], "auth")) cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_AUTH); else if (!strcasecmp(arg->argv[dummyint], "cbcp")) cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_CBCP); else if (!strcasecmp(arg->argv[dummyint], "e.164")) { if (dummyint == arg->argc - 1) log_Printf(LogWARN, "No E.164 arg (E.164 ignored) !\n"); else { cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_E164); strncpy(cx->cfg.callback.msg, arg->argv[++dummyint], sizeof cx->cfg.callback.msg - 1); cx->cfg.callback.msg[sizeof cx->cfg.callback.msg - 1] = '\0'; } } else if (!strcasecmp(arg->argv[dummyint], "none")) cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_NONE); else { res = -1; break; } } if (cx->cfg.callback.opmask == CALLBACK_BIT(CALLBACK_NONE)) cx->cfg.callback.opmask = 0; break; case VAR_CBCP: cx->cfg.cbcp.delay = 0; *cx->cfg.cbcp.phone = '\0'; cx->cfg.cbcp.fsmretry = DEF_FSMRETRY; if (arg->argc > arg->argn) { strncpy(cx->cfg.cbcp.phone, arg->argv[arg->argn], sizeof cx->cfg.cbcp.phone - 1); cx->cfg.cbcp.phone[sizeof cx->cfg.cbcp.phone - 1] = '\0'; if (arg->argc > arg->argn + 1) { cx->cfg.cbcp.delay = atoi(arg->argv[arg->argn + 1]); if (arg->argc > arg->argn + 2) { long_val = atol(arg->argv[arg->argn + 2]); if (long_val < MIN_FSMRETRY) log_Printf(LogWARN, "%ld: Invalid CBCP FSM retry period - min %d\n", long_val, MIN_FSMRETRY); else cx->cfg.cbcp.fsmretry = long_val; } } } break; case VAR_CHOKED: arg->bundle->cfg.choked.timeout = atoi(argp); if (arg->bundle->cfg.choked.timeout <= 0) arg->bundle->cfg.choked.timeout = CHOKED_TIMEOUT; break; case VAR_SENDPIPE: long_val = atol(argp); arg->bundle->ncp.cfg.sendpipe = long_val; break; case VAR_RECVPIPE: long_val = atol(argp); arg->bundle->ncp.cfg.recvpipe = long_val; break; #ifndef NORADIUS case VAR_RADIUS: if (!*argp) *arg->bundle->radius.cfg.file = '\0'; else if (access(argp, R_OK)) { log_Printf(LogWARN, "%s: %s\n", argp, strerror(errno)); res = 1; break; } else { strncpy(arg->bundle->radius.cfg.file, argp, sizeof arg->bundle->radius.cfg.file - 1); arg->bundle->radius.cfg.file [sizeof arg->bundle->radius.cfg.file - 1] = '\0'; } break; #endif case VAR_CD: if (*argp) { if (strcasecmp(argp, "off")) { long_val = atol(argp); if (long_val < 0) long_val = 0; cx->physical->cfg.cd.delay = long_val; cx->physical->cfg.cd.necessity = argp[strlen(argp)-1] == '!' ? CD_REQUIRED : CD_VARIABLE; } else cx->physical->cfg.cd.necessity = CD_NOTREQUIRED; } else { cx->physical->cfg.cd.delay = 0; cx->physical->cfg.cd.necessity = CD_DEFAULT; } break; case VAR_PARITY: if (arg->argc == arg->argn + 1) res = physical_SetParity(arg->cx->physical, argp); else { log_Printf(LogWARN, "Parity value must be odd, even or none\n"); res = 1; } break; case VAR_CRTSCTS: if (strcasecmp(argp, "on") == 0) physical_SetRtsCts(arg->cx->physical, 1); else if (strcasecmp(argp, "off") == 0) physical_SetRtsCts(arg->cx->physical, 0); else { log_Printf(LogWARN, "RTS/CTS value must be on or off\n"); res = 1; } break; case VAR_URGENTPORTS: if (arg->argn == arg->argc) { ncp_SetUrgentTOS(&arg->bundle->ncp); ncp_ClearUrgentTcpPorts(&arg->bundle->ncp); ncp_ClearUrgentUdpPorts(&arg->bundle->ncp); } else if (!strcasecmp(arg->argv[arg->argn], "udp")) { ncp_SetUrgentTOS(&arg->bundle->ncp); if (arg->argn == arg->argc - 1) ncp_ClearUrgentUdpPorts(&arg->bundle->ncp); else for (f = arg->argn + 1; f < arg->argc; f++) if (*arg->argv[f] == '+') ncp_AddUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1)); else if (*arg->argv[f] == '-') ncp_RemoveUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1)); else { if (f == arg->argn) ncp_ClearUrgentUdpPorts(&arg->bundle->ncp); ncp_AddUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f])); } } else if (arg->argn == arg->argc - 1 && !strcasecmp(arg->argv[arg->argn], "none")) { ncp_ClearUrgentTcpPorts(&arg->bundle->ncp); ncp_ClearUrgentUdpPorts(&arg->bundle->ncp); ncp_ClearUrgentTOS(&arg->bundle->ncp); } else { ncp_SetUrgentTOS(&arg->bundle->ncp); first = arg->argn; if (!strcasecmp(arg->argv[first], "tcp") && ++first == arg->argc) ncp_ClearUrgentTcpPorts(&arg->bundle->ncp); for (f = first; f < arg->argc; f++) if (*arg->argv[f] == '+') ncp_AddUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1)); else if (*arg->argv[f] == '-') ncp_RemoveUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1)); else { if (f == first) ncp_ClearUrgentTcpPorts(&arg->bundle->ncp); ncp_AddUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f])); } } break; case VAR_PPPOE: if (strcasecmp(argp, "3Com") == 0) physical_SetPPPoEnonstandard(arg->cx->physical, 1); else if (strcasecmp(argp, "standard") == 0) physical_SetPPPoEnonstandard(arg->cx->physical, 0); else { log_Printf(LogWARN, "PPPoE standard value must be \"standard\" or \"3Com\"\n"); res = 1; } break; } return res; } static struct cmdtab const SetCommands[] = { {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP}, {"authkey", "key", SetVariable, LOCAL_AUTH, "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY}, {"authname", NULL, SetVariable, LOCAL_AUTH, "authentication name", "set authname name", (const void *)VAR_AUTHNAME}, {"autoload", NULL, SetVariable, LOCAL_AUTH, "auto link [de]activation", "set autoload maxtime maxload mintime minload", (const void *)VAR_AUTOLOAD}, {"bandwidth", NULL, mp_SetDatalinkBandwidth, LOCAL_AUTH | LOCAL_CX, - "datalink bandwidth", "set bandwidth value"}, + "datalink bandwidth", "set bandwidth value", NULL}, {"callback", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "callback control", "set callback [none|auth|cbcp|" "E.164 *|number[,number]...]...", (const void *)VAR_CALLBACK}, {"cbcp", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "CBCP control", "set cbcp [*|phone[,phone...] [delay [timeout]]]", (const void *)VAR_CBCP}, {"ccpretry", "ccpretries", SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, "CCP retries", "set ccpretry value [attempts]", (const void *)VAR_CCPRETRY}, {"cd", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "Carrier delay requirement", "set cd value[!]", (const void *)VAR_CD}, {"chapretry", "chapretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "CHAP retries", "set chapretry value [attempts]", (const void *)VAR_CHAPRETRY}, {"choked", NULL, SetVariable, LOCAL_AUTH, "choked timeout", "set choked [secs]", (const void *)VAR_CHOKED}, {"ctsrts", "crtscts", SetVariable, LOCAL_AUTH | LOCAL_CX, "Use hardware flow control", "set ctsrts [on|off]", (const char *)VAR_CRTSCTS}, {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, "deflate window sizes", "set deflate out-winsize in-winsize", (const void *) VAR_WINSIZE}, #ifndef NODES {"mppe", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, "MPPE key size and state", "set mppe [40|56|128|* [stateful|stateless|*]]", (const void *) VAR_MPPE}, #endif {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX, "physical device name", "set device|line device-name[,device-name]", (const void *) VAR_DEVICE}, {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "dialing script", "set dial chat-script", (const void *) VAR_DIAL}, {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server", "set dns pri-addr [sec-addr]", (const void *)VAR_DNS}, {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH, - "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]"}, + "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]", NULL}, {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX, - "escape characters", "set escape hex-digit ..."}, + "escape characters", "set escape hex-digit ...", NULL}, {"filter", NULL, filter_Set, LOCAL_AUTH, "packet filters", "set filter alive|dial|in|out rule-no permit|deny " "[src_addr[/width]] [dst_addr[/width]] [proto " - "[src [lt|eq|gt port]] [dst [lt|eq|gt port]] [estab] [syn] [finrst]]"}, + "[src [lt|eq|gt port]] [dst [lt|eq|gt port]] [estab] [syn] [finrst]]", NULL}, {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP}, {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address", - "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"}, + "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]", NULL}, {"ifqueue", NULL, SetVariable, LOCAL_AUTH, "interface queue", "set ifqueue packets", (const void *)VAR_IFQUEUE}, {"ipcpretry", "ipcpretries", SetVariable, LOCAL_AUTH, "IPCP retries", "set ipcpretry value [attempts]", (const void *)VAR_IPCPRETRY}, {"ipv6cpretry", "ipv6cpretries", SetVariable, LOCAL_AUTH, "IPV6CP retries", "set ipv6cpretry value [attempts]", (const void *)VAR_IPV6CPRETRY}, {"lcpretry", "lcpretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "LCP retries", "set lcpretry value [attempts]", (const void *)VAR_LCPRETRY}, {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level", "set log [local] [+|-]all|async|cbcp|ccp|chat|command|connect|debug|dns|hdlc|" - "id0|ipcp|lcp|lqm|phase|physical|radius|sync|tcp/ip|timer|tun..."}, + "id0|ipcp|lcp|lqm|phase|physical|radius|sync|tcp/ip|timer|tun...", NULL}, {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "login script", "set login chat-script", (const void *) VAR_LOGIN}, {"logout", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "logout script", "set logout chat-script", (const void *) VAR_LOGOUT}, {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD}, {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value", "set mode interactive|auto|ddial|background", (const void *)VAR_MODE}, {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value", "set mrru value", (const void *)VAR_MRRU}, {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "MRU value", "set mru [max[imum]] [value]", (const void *)VAR_MRU}, {"mtu", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "interface MTU value", "set mtu [max[imum]] [value]", (const void *)VAR_MTU}, {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server", "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS}, {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode", "set openmode active|passive [secs]", (const void *)VAR_OPENMODE}, {"papretry", "papretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "PAP retries", "set papretry value [attempts]", (const void *)VAR_PAPRETRY}, {"parity", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "serial parity", "set parity [odd|even|none]", (const void *)VAR_PARITY}, {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)", "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE}, {"proctitle", "title", SetProcTitle, LOCAL_AUTH, - "Process title", "set proctitle [value]"}, + "Process title", "set proctitle [value]", NULL}, #ifndef NORADIUS {"radius", NULL, SetVariable, LOCAL_AUTH, "RADIUS Config", "set radius cfgfile", (const void *)VAR_RADIUS}, {"rad_alive", NULL, SetVariable, LOCAL_AUTH, "Raduis alive interval", "set rad_alive value", (const void *)VAR_RAD_ALIVE}, #endif {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX, - "Reconnect timeout", "set reconnect value ntries"}, + "Reconnect timeout", "set reconnect value ntries", NULL}, {"recvpipe", NULL, SetVariable, LOCAL_AUTH, "RECVPIPE value", "set recvpipe value", (const void *)VAR_RECVPIPE}, {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX, - "Redial timeout", "set redial secs[+inc[-incmax]][.next] [attempts]"}, + "Redial timeout", "set redial secs[+inc[-incmax]][.next] [attempts]", NULL}, {"sendpipe", NULL, SetVariable, LOCAL_AUTH, "SENDPIPE value", "set sendpipe value", (const void *)VAR_SENDPIPE}, {"server", "socket", SetServer, LOCAL_AUTH, "diagnostic port", - "set server|socket TcpPort|LocalName|none|open|closed [password [mask]]"}, + "set server|socket TcpPort|LocalName|none|open|closed [password [mask]]", + NULL}, {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX, - "physical speed", "set speed value|sync"}, + "physical speed", "set speed value|sync", NULL}, {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX, - "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"}, + "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]", NULL}, {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout", "set timeout idletime", (const void *)VAR_IDLETIMEOUT}, {"urgent", NULL, SetVariable, LOCAL_AUTH, "urgent ports", "set urgent [tcp|udp] [+|-]port...", (const void *)VAR_URGENTPORTS}, {"vj", NULL, ipcp_vjset, LOCAL_AUTH, - "vj values", "set vj slots|slotcomp [value]"}, + "vj values", "set vj slots|slotcomp [value]", NULL}, {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, "Display this message", "set help|? [command]", SetCommands}, {"pppoe", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "Connect using standard/3Com mode", "set pppoe [standard|3Com]", (const char *)VAR_PPPOE}, - {NULL, NULL, NULL}, + {NULL, NULL, NULL, 0, NULL, NULL, NULL}, }; static int SetCommand(struct cmdargs const *arg) { if (arg->argc > arg->argn) FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv, arg->prompt, arg->cx); else if (arg->prompt) prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? ' for" " syntax help.\n"); else log_Printf(LogWARN, "set command must have arguments\n"); return 0; } static int AddCommand(struct cmdargs const *arg) { struct ncpaddr gw; struct ncprange dest; struct in_addr host; #ifndef NOINET6 struct in6_addr host6; #endif int dest_default, gw_arg, addrs; if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2) return -1; addrs = 0; dest_default = 0; if (arg->argc == arg->argn + 2) { if (!strcasecmp(arg->argv[arg->argn], "default")) dest_default = 1; else { if (!ncprange_aton(&dest, &arg->bundle->ncp, arg->argv[arg->argn])) return -1; if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6)) addrs = ROUTE_DSTMYADDR; else if (!strncasecmp(arg->argv[arg->argn], "MYADDR6", 7)) addrs = ROUTE_DSTMYADDR6; else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7)) addrs = ROUTE_DSTHISADDR; else if (!strncasecmp(arg->argv[arg->argn], "HISADDR6", 8)) addrs = ROUTE_DSTHISADDR6; else if (!strncasecmp(arg->argv[arg->argn], "DNS0", 4)) addrs = ROUTE_DSTDNS0; else if (!strncasecmp(arg->argv[arg->argn], "DNS1", 4)) addrs = ROUTE_DSTDNS1; } gw_arg = 1; } else { if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) { addrs = ROUTE_DSTMYADDR; host = arg->bundle->ncp.ipcp.my_ip; } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) { addrs = ROUTE_DSTHISADDR; host = arg->bundle->ncp.ipcp.peer_ip; } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) { addrs = ROUTE_DSTDNS0; host = arg->bundle->ncp.ipcp.ns.dns[0]; } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) { addrs = ROUTE_DSTDNS1; host = arg->bundle->ncp.ipcp.ns.dns[1]; } else { host = GetIpAddr(arg->argv[arg->argn]); if (host.s_addr == INADDR_NONE) { log_Printf(LogWARN, "%s: Invalid destination address\n", arg->argv[arg->argn]); return -1; } } ncprange_setip4(&dest, host, GetIpAddr(arg->argv[arg->argn + 1])); gw_arg = 2; } if (strcasecmp(arg->argv[arg->argn + gw_arg], "HISADDR") == 0) { ncpaddr_setip4(&gw, arg->bundle->ncp.ipcp.peer_ip); addrs |= ROUTE_GWHISADDR; #ifndef NOINET6 } else if (strcasecmp(arg->argv[arg->argn + gw_arg], "HISADDR6") == 0) { if (!ncpaddr_getip6(&arg->bundle->ncp.ipv6cp.hisaddr, &host6)) memset(&host6, '\0', sizeof host6); ncpaddr_setip6(&gw, &host6); addrs |= ROUTE_GWHISADDR6; #endif } else { if (!ncpaddr_aton(&gw, &arg->bundle->ncp, arg->argv[arg->argn + gw_arg])) { log_Printf(LogWARN, "%s: Invalid gateway address\n", arg->argv[arg->argn + gw_arg]); return -1; } } if (dest_default) ncprange_setdefault(&dest, ncpaddr_family(&gw)); if (rt_Set(arg->bundle, RTM_ADD, &dest, &gw, arg->cmd->args ? 1 : 0, ((addrs & ROUTE_GWHISADDR) || (addrs & ROUTE_GWHISADDR6)) ? 1 : 0) && addrs != ROUTE_STATIC) route_Add(&arg->bundle->ncp.route, addrs, &dest, &gw); return 0; } static int DeleteCommand(struct cmdargs const *arg) { struct ncprange dest; int addrs; if (arg->argc == arg->argn+1) { if(strcasecmp(arg->argv[arg->argn], "all") == 0) { route_IfDelete(arg->bundle, 0); route_DeleteAll(&arg->bundle->ncp.route); } else { addrs = 0; if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) { ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.my_ip); addrs = ROUTE_DSTMYADDR; #ifndef NOINET6 } else if (strcasecmp(arg->argv[arg->argn], "MYADDR6") == 0) { ncprange_sethost(&dest, &arg->bundle->ncp.ipv6cp.myaddr); addrs = ROUTE_DSTMYADDR6; #endif } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) { ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.peer_ip); addrs = ROUTE_DSTHISADDR; #ifndef NOINET6 } else if (strcasecmp(arg->argv[arg->argn], "HISADDR6") == 0) { ncprange_sethost(&dest, &arg->bundle->ncp.ipv6cp.hisaddr); addrs = ROUTE_DSTHISADDR6; #endif } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) { ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.ns.dns[0]); addrs = ROUTE_DSTDNS0; } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) { ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.ns.dns[1]); addrs = ROUTE_DSTDNS1; } else { ncprange_aton(&dest, &arg->bundle->ncp, arg->argv[arg->argn]); addrs = ROUTE_STATIC; } rt_Set(arg->bundle, RTM_DELETE, &dest, NULL, arg->cmd->args ? 1 : 0, 0); route_Delete(&arg->bundle->ncp.route, addrs, &dest); } } else return -1; return 0; } #ifndef NONAT static int NatEnable(struct cmdargs const *arg) { if (arg->argc == arg->argn+1) { if (strcasecmp(arg->argv[arg->argn], "yes") == 0) { if (!arg->bundle->NatEnabled) { if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED) PacketAliasSetAddress(arg->bundle->ncp.ipcp.my_ip); arg->bundle->NatEnabled = 1; } return 0; } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) { arg->bundle->NatEnabled = 0; arg->bundle->cfg.opt &= ~OPT_IFACEALIAS; /* Don't iface_Clear() - there may be manually configured addresses */ return 0; } } return -1; } static int NatOption(struct cmdargs const *arg) { long param = (long)arg->cmd->args; if (arg->argc == arg->argn+1) { if (strcasecmp(arg->argv[arg->argn], "yes") == 0) { if (arg->bundle->NatEnabled) { PacketAliasSetMode(param, param); return 0; } log_Printf(LogWARN, "nat not enabled\n"); } else if (strcmp(arg->argv[arg->argn], "no") == 0) { if (arg->bundle->NatEnabled) { PacketAliasSetMode(0, param); return 0; } log_Printf(LogWARN, "nat not enabled\n"); } } return -1; } #endif /* #ifndef NONAT */ static int LinkCommand(struct cmdargs const *arg) { if (arg->argc > arg->argn+1) { char namelist[LINE_LEN]; struct datalink *cx; char *name; int result = 0; if (!strcmp(arg->argv[arg->argn], "*")) { struct datalink *dl; cx = arg->bundle->links; while (cx) { /* Watch it, the command could be a ``remove'' */ dl = cx->next; FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv, arg->prompt, cx); for (cx = arg->bundle->links; cx; cx = cx->next) if (cx == dl) break; /* Pointer's still valid ! */ } } else { strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1); namelist[sizeof namelist - 1] = '\0'; for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) if (!bundle2datalink(arg->bundle, name)) { log_Printf(LogWARN, "link: %s: Invalid link name\n", name); return 1; } strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1); namelist[sizeof namelist - 1] = '\0'; for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) { cx = bundle2datalink(arg->bundle, name); if (cx) FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv, arg->prompt, cx); else { log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name); result++; } } } return result; } log_Printf(LogWARN, "usage: %s\n", arg->cmd->syntax); return 2; } struct link * command_ChooseLink(struct cmdargs const *arg) { if (arg->cx) return &arg->cx->physical->link; else if (!arg->bundle->ncp.mp.cfg.mrru) { struct datalink *dl = bundle2datalink(arg->bundle, NULL); if (dl) return &dl->physical->link; } return &arg->bundle->ncp.mp.link; } static const char * ident_cmd(const char *cmd, unsigned *keep, unsigned *add) { const char *result; switch (*cmd) { case 'A': case 'a': result = "accept"; *keep = NEG_MYMASK; *add = NEG_ACCEPTED; break; case 'D': case 'd': switch (cmd[1]) { case 'E': case 'e': result = "deny"; *keep = NEG_MYMASK; *add = 0; break; case 'I': case 'i': result = "disable"; *keep = NEG_HISMASK; *add = 0; break; default: return NULL; } break; case 'E': case 'e': result = "enable"; *keep = NEG_HISMASK; *add = NEG_ENABLED; break; default: return NULL; } return result; } static int OptSet(struct cmdargs const *arg) { int bit = (int)(long)arg->cmd->args; unsigned keep; /* Keep these bits */ unsigned add; /* Add these bits */ if (ident_cmd(arg->argv[arg->argn - 2], &keep, &add) == NULL) return 1; #ifndef NOINET6 if (add == NEG_ENABLED && bit == OPT_IPV6CP && !probe.ipv6_available) { log_Printf(LogWARN, "IPv6 is not available on this machine\n"); return 1; } #endif if (add) arg->bundle->cfg.opt |= bit; else arg->bundle->cfg.opt &= ~bit; return 0; } static int IfaceAliasOptSet(struct cmdargs const *arg) { unsigned save = arg->bundle->cfg.opt; int result = OptSet(arg); if (result == 0) if (Enabled(arg->bundle, OPT_IFACEALIAS) && !arg->bundle->NatEnabled) { arg->bundle->cfg.opt = save; log_Printf(LogWARN, "Cannot enable iface-alias without NAT\n"); result = 2; } return result; } static int NegotiateSet(struct cmdargs const *arg) { long param = (long)arg->cmd->args; struct link *l = command_ChooseLink(arg); /* LOCAL_CX_OPT uses this */ struct datalink *cx = arg->cx; /* LOCAL_CX uses this */ const char *cmd; unsigned keep; /* Keep these bits */ unsigned add; /* Add these bits */ if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL) return 1; if ((arg->cmd->lauth & LOCAL_CX) && !cx) { log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n", cmd, arg->cmd->name); return 2; } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) { log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n", cmd, arg->cmd->name, cx->name); cx = NULL; } switch (param) { case NEG_ACFCOMP: cx->physical->link.lcp.cfg.acfcomp &= keep; cx->physical->link.lcp.cfg.acfcomp |= add; break; case NEG_CHAP05: cx->physical->link.lcp.cfg.chap05 &= keep; cx->physical->link.lcp.cfg.chap05 |= add; break; #ifndef NODES case NEG_CHAP80: cx->physical->link.lcp.cfg.chap80nt &= keep; cx->physical->link.lcp.cfg.chap80nt |= add; break; case NEG_CHAP80LM: cx->physical->link.lcp.cfg.chap80lm &= keep; cx->physical->link.lcp.cfg.chap80lm |= add; break; case NEG_CHAP81: cx->physical->link.lcp.cfg.chap81 &= keep; cx->physical->link.lcp.cfg.chap81 |= add; break; case NEG_MPPE: l->ccp.cfg.neg[CCP_NEG_MPPE] &= keep; l->ccp.cfg.neg[CCP_NEG_MPPE] |= add; break; #endif case NEG_DEFLATE: l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep; l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add; break; case NEG_DNS: arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep; arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add; break; case NEG_ENDDISC: arg->bundle->ncp.mp.cfg.negenddisc &= keep; arg->bundle->ncp.mp.cfg.negenddisc |= add; break; case NEG_LQR: cx->physical->link.lcp.cfg.lqr &= keep; cx->physical->link.lcp.cfg.lqr |= add; break; case NEG_PAP: cx->physical->link.lcp.cfg.pap &= keep; cx->physical->link.lcp.cfg.pap |= add; break; case NEG_PPPDDEFLATE: l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep; l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add; break; case NEG_PRED1: l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep; l->ccp.cfg.neg[CCP_NEG_PRED1] |= add; break; case NEG_PROTOCOMP: cx->physical->link.lcp.cfg.protocomp &= keep; cx->physical->link.lcp.cfg.protocomp |= add; break; case NEG_SHORTSEQ: switch (bundle_Phase(arg->bundle)) { case PHASE_DEAD: break; case PHASE_ESTABLISH: /* Make sure none of our links are DATALINK_LCP or greater */ if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) { log_Printf(LogWARN, "shortseq: Only changable before" " LCP negotiations\n"); return 1; } break; default: log_Printf(LogWARN, "shortseq: Only changable at phase" " DEAD/ESTABLISH\n"); return 1; } arg->bundle->ncp.mp.cfg.shortseq &= keep; arg->bundle->ncp.mp.cfg.shortseq |= add; break; case NEG_VJCOMP: arg->bundle->ncp.ipcp.cfg.vj.neg &= keep; arg->bundle->ncp.ipcp.cfg.vj.neg |= add; break; } return 0; } static struct cmdtab const NegotiateCommands[] = { {"filter-decapsulation", NULL, OptSet, LOCAL_AUTH, "filter on PPPoUDP payloads", "disable|enable", (const void *)OPT_FILTERDECAP}, {"force-scripts", NULL, OptSet, LOCAL_AUTH, "Force execution of the configured chat scripts", "disable|enable", (const void *)OPT_FORCE_SCRIPTS}, {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids", "disable|enable", (const void *)OPT_IDCHECK}, {"iface-alias", NULL, IfaceAliasOptSet, LOCAL_AUTH, "retain interface addresses", "disable|enable", (const void *)OPT_IFACEALIAS}, #ifndef NOINET6 {"ipcp", NULL, OptSet, LOCAL_AUTH, "IP Network Control Protocol", "disable|enable", (const void *)OPT_IPCP}, {"ipv6cp", NULL, OptSet, LOCAL_AUTH, "IPv6 Network Control Protocol", "disable|enable", (const void *)OPT_IPV6CP}, #endif {"keep-session", NULL, OptSet, LOCAL_AUTH, "Retain device session leader", "disable|enable", (const void *)OPT_KEEPSESSION}, {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface", "disable|enable", (const void *)OPT_LOOPBACK}, {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file", "disable|enable", (const void *)OPT_PASSWDAUTH}, {"proxy", NULL, OptSet, LOCAL_AUTH, "Create a proxy ARP entry", "disable|enable", (const void *)OPT_PROXY}, {"proxyall", NULL, OptSet, LOCAL_AUTH, "Proxy ARP for all remote hosts", "disable|enable", (const void *)OPT_PROXYALL}, {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes", "disable|enable", (const void *)OPT_SROUTES}, {"tcpmssfixup", "mssfixup", OptSet, LOCAL_AUTH, "Modify MSS options", "disable|enable", (const void *)OPT_TCPMSSFIXUP}, {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput", "disable|enable", (const void *)OPT_THROUGHPUT}, {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp", "disable|enable", (const void *)OPT_UTMP}, #ifndef NOINET6 #define OPT_MAX 14 /* accept/deny allowed below and not above */ #else #define OPT_MAX 12 #endif {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, "Address & Control field compression", "accept|deny|disable|enable", (const void *)NEG_ACFCOMP}, {"chap", "chap05", NegotiateSet, LOCAL_AUTH | LOCAL_CX, "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable", (const void *)NEG_CHAP05}, #ifndef NODES {"mschap", "chap80nt", NegotiateSet, LOCAL_AUTH | LOCAL_CX, "Microsoft (NT) CHAP", "accept|deny|disable|enable", (const void *)NEG_CHAP80}, {"LANMan", "chap80lm", NegotiateSet, LOCAL_AUTH | LOCAL_CX, "Microsoft (NT) CHAP", "accept|deny|disable|enable", (const void *)NEG_CHAP80LM}, {"mschapv2", "chap81", NegotiateSet, LOCAL_AUTH | LOCAL_CX, "Microsoft CHAP v2", "accept|deny|disable|enable", (const void *)NEG_CHAP81}, {"mppe", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT, "MPPE encryption", "accept|deny|disable|enable", (const void *)NEG_MPPE}, #endif {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT, "Deflate compression", "accept|deny|disable|enable", (const void *)NEG_DEFLATE}, {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT, "Deflate (type 24) compression", "accept|deny|disable|enable", (const void *)NEG_PPPDDEFLATE}, {"dns", NULL, NegotiateSet, LOCAL_AUTH, "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS}, {"enddisc", NULL, NegotiateSet, LOCAL_AUTH, "ENDDISC negotiation", "accept|deny|disable|enable", (const void *)NEG_ENDDISC}, {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, "Link Quality Reports", "accept|deny|disable|enable", (const void *)NEG_LQR}, {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, "Password Authentication protocol", "accept|deny|disable|enable", (const void *)NEG_PAP}, {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT, "Predictor 1 compression", "accept|deny|disable|enable", (const void *)NEG_PRED1}, {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, "Protocol field compression", "accept|deny|disable|enable", (const void *)NEG_PROTOCOMP}, {"shortseq", NULL, NegotiateSet, LOCAL_AUTH, "MP Short Sequence Numbers", "accept|deny|disable|enable", (const void *)NEG_SHORTSEQ}, {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH, "Van Jacobson header compression", "accept|deny|disable|enable", (const void *)NEG_VJCOMP}, {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, "Display this message", "accept|deny|disable|enable help|? [value]", NegotiateCommands}, - {NULL, NULL, NULL}, + {NULL, NULL, NULL, 0, NULL, NULL, NULL}, }; static int NegotiateCommand(struct cmdargs const *arg) { if (arg->argc > arg->argn) { char const *argv[3]; unsigned keep, add; int n; if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL) return -1; argv[2] = NULL; for (n = arg->argn; n < arg->argc; n++) { argv[1] = arg->argv[n]; FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ? 0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx); } } else if (arg->prompt) prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n", arg->argv[arg->argn-1]); else log_Printf(LogWARN, "%s command must have arguments\n", arg->argv[arg->argn] ); return 0; } const char * command_ShowNegval(unsigned val) { switch (val&3) { case 1: return "disabled & accepted"; case 2: return "enabled & denied"; case 3: return "enabled & accepted"; } return "disabled & denied"; } static int ClearCommand(struct cmdargs const *arg) { struct pppThroughput *t; struct datalink *cx; int i, clear_type; if (arg->argc < arg->argn + 1) return -1; if (strcasecmp(arg->argv[arg->argn], "physical") == 0) { cx = arg->cx; if (!cx) cx = bundle2datalink(arg->bundle, NULL); if (!cx) { log_Printf(LogWARN, "A link must be specified for ``clear physical''\n"); return 1; } t = &cx->physical->link.stats.total; } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0) t = &arg->bundle->ncp.ipcp.throughput; #ifndef NOINET6 else if (strcasecmp(arg->argv[arg->argn], "ipv6cp") == 0) t = &arg->bundle->ncp.ipv6cp.throughput; #endif else return -1; if (arg->argc > arg->argn + 1) { clear_type = 0; for (i = arg->argn + 1; i < arg->argc; i++) if (strcasecmp(arg->argv[i], "overall") == 0) clear_type |= THROUGHPUT_OVERALL; else if (strcasecmp(arg->argv[i], "current") == 0) clear_type |= THROUGHPUT_CURRENT; else if (strcasecmp(arg->argv[i], "peak") == 0) clear_type |= THROUGHPUT_PEAK; else return -1; } else clear_type = THROUGHPUT_ALL; throughput_clear(t, clear_type, arg->prompt); return 0; } static int RunListCommand(struct cmdargs const *arg) { const char *cmd = arg->argc ? arg->argv[arg->argc - 1] : "???"; #ifndef NONAT if (arg->cmd->args == NatCommands && tolower(*arg->argv[arg->argn - 1]) == 'a') { if (arg->prompt) prompt_Printf(arg->prompt, "The alias command is deprecated\n"); else log_Printf(LogWARN, "The alias command is deprecated\n"); } #endif if (arg->argc > arg->argn) FindExec(arg->bundle, arg->cmd->args, arg->argc, arg->argn, arg->argv, arg->prompt, arg->cx); else if (arg->prompt) prompt_Printf(arg->prompt, "Use `%s help' to get a list or `%s help" "