summaryrefslogtreecommitdiff
path: root/user/ppp
diff options
context:
space:
mode:
Diffstat (limited to 'user/ppp')
-rw-r--r--user/ppp/02_all_make-vars.patch185
-rw-r--r--user/ppp/03_all_use_internal_logwtmp.patch22
-rw-r--r--user/ppp/04_all_mpls.patch427
-rw-r--r--user/ppp/06_all_killaddr-smarter.patch131
-rw-r--r--user/ppp/08_all_wait-children.patch76
-rw-r--r--user/ppp/10_all_defaultgateway.patch90
-rw-r--r--user/ppp/12_all_linkpidfile.patch93
-rw-r--r--user/ppp/16_all_auth-fail.patch138
-rw-r--r--user/ppp/18_all_defaultmetric.patch104
-rw-r--r--user/ppp/19_all_radius_pid_overflow.patch14
-rw-r--r--user/ppp/20_all_dev-ppp.patch20
-rw-r--r--user/ppp/21_all_custom_iface_names.patch144
-rw-r--r--user/ppp/24_all_passwordfd-read-early.patch84
-rw-r--r--user/ppp/26_all_pppd-usepeerwins.patch256
-rw-r--r--user/ppp/28_all_connect-errors.patch11
-rw-r--r--user/ppp/30_all_Makefile.patch37
-rw-r--r--user/ppp/32_all_pado-timeout.patch254
-rw-r--r--user/ppp/34_all_lcp-echo-adaptive.patch56
-rw-r--r--user/ppp/50_all_linux-headers.patch28
-rw-r--r--user/ppp/51_all_glibc-2.28.patch110
-rw-r--r--user/ppp/80_all_eaptls-mppe-1.101a.patch3233
-rw-r--r--user/ppp/85_all_dhcp-make-vars.patch19
-rw-r--r--user/ppp/86_all_dhcp-sys_error_to_strerror.patch128
-rw-r--r--user/ppp/APKBUILD125
-rw-r--r--user/ppp/adelie.patch88
-rw-r--r--user/ppp/dhcp.patch324
-rw-r--r--user/ppp/install-path.patch11
-rw-r--r--user/ppp/musl-fix-headers.patch137
-rw-r--r--user/ppp/ppp.mod10
-rw-r--r--user/ppp/ppp.pamd7
-rw-r--r--user/ppp/pppd.initd13
-rw-r--r--user/ppp/utmpx.patch142
32 files changed, 6517 insertions, 0 deletions
diff --git a/user/ppp/02_all_make-vars.patch b/user/ppp/02_all_make-vars.patch
new file mode 100644
index 000000000..7937d666e
--- /dev/null
+++ b/user/ppp/02_all_make-vars.patch
@@ -0,0 +1,185 @@
+--- ppp-2.4.5/chat/Makefile.linux
++++ ppp-2.4.5/chat/Makefile.linux
+@@ -10,7 +10,6 @@
+ CDEF4= -DFNDELAY=O_NDELAY # Old name value
+ CDEFS= $(CDEF1) $(CDEF2) $(CDEF3) $(CDEF4)
+
+-COPTS= -O2 -g -pipe
+ CFLAGS= $(COPTS) $(CDEFS)
+
+ INSTALL= install
+@@ -18,7 +17,7 @@
+ all: chat
+
+ chat: chat.o
+- $(CC) -o chat chat.o
++ $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $^
+
+ chat.o: chat.c
+ $(CC) -c $(CFLAGS) -o chat.o chat.c
+--- ppp-2.4.5/pppd/Makefile.linux
++++ ppp-2.4.5/pppd/Makefile.linux
+@@ -32,7 +32,7 @@
+
+ # CC = gcc
+ #
+-COPTS = -O2 -pipe -Wall -g
++COPTS+= -Wall
+ LIBS =
+
+ # Uncomment the next 2 lines to include support for Microsoft's
+--- ppp-2.4.5/pppd/plugins/Makefile.linux
++++ ppp-2.4.5/pppd/plugins/Makefile.linux
+@@ -1,7 +1,11 @@
+ #CC = gcc
+-COPTS = -O2 -g
+ CFLAGS = $(COPTS) -I.. -I../../include -fPIC
+-LDFLAGS = -shared
++LDFLAGS_PROG := $(LDFLAGS)
++export LDFLAGS LDFLAGS_PROG
++LDFLAGS += -shared
++# need the following option, otherwise linking plugins might fail with undef errors (Gentoo bug 210837)
++LDFLAGS += -Wl,--allow-shlib-undefined
++LIBS =
+ INSTALL = install
+
+ DESTDIR = $(INSTROOT)@DESTDIR@
+@@ -23,7 +27,7 @@
+ for d in $(SUBDIRS); do $(MAKE) $(MFLAGS) -C $$d all; done
+
+ %.so: %.c
+- $(CC) -o $@ $(LDFLAGS) $(CFLAGS) $^
++ $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $^ $(LIBS)
+
+ VERSION = $(shell awk -F '"' '/VERSION/ { print $$2; }' ../patchlevel.h)
+
+--- ppp-2.4.5/pppd/plugins/pppoatm/Makefile.linux
++++ ppp-2.4.5/pppd/plugins/pppoatm/Makefile.linux
+@@ -1,7 +1,5 @@
+ #CC = gcc
+-COPTS = -O2 -g
+ CFLAGS = $(COPTS) -I../.. -I../../../include -fPIC
+-LDFLAGS = -shared
+ INSTALL = install
+
+ #***********************************************************************
+@@ -33,7 +31,7 @@
+ all: $(PLUGIN)
+
+ $(PLUGIN): $(PLUGIN_OBJS)
+- $(CC) $(CFLAGS) -o $@ -shared $^ $(LIBS)
++ $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $^ $(LIBS)
+
+ install: all
+ $(INSTALL) -d -m 755 $(LIBDIR)
+--- ppp-2.4.5/pppd/plugins/pppol2tp/Makefile.linux
++++ ppp-2.4.5/pppd/plugins/pppol2tp/Makefile.linux
+@@ -1,7 +1,5 @@
+ #CC = gcc
+-COPTS = -O2 -g
+ CFLAGS = $(COPTS) -I. -I../.. -I../../../include -fPIC
+-LDFLAGS = -shared
+ INSTALL = install
+
+ #***********************************************************************
+@@ -16,7 +14,7 @@
+ all: $(PLUGINS)
+
+ %.so: %.o
+- $(CC) $(CFLAGS) -o $@ -shared $^ $(LIBS)
++ $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $^ $(LIBS)
+
+ install: all
+ $(INSTALL) -d -m 755 $(LIBDIR)
+--- ppp-2.4.5/pppd/plugins/radius/Makefile.linux
++++ ppp-2.4.5/pppd/plugins/radius/Makefile.linux
+@@ -12,7 +12,7 @@
+ INSTALL = install
+
+ PLUGIN=radius.so radattr.so radrealms.so
+-CFLAGS=-I. -I../.. -I../../../include -O2 -fPIC -DRC_LOG_FACILITY=LOG_DAEMON
++CFLAGS=$(COPTS) -I. -I../.. -I../../../include -fPIC -DRC_LOG_FACILITY=LOG_DAEMON
+
+ # Uncomment the next line to include support for Microsoft's
+ # MS-CHAP authentication protocol.
+@@ -43,13 +43,13 @@
+ $(INSTALL) -c -m 444 pppd-radattr.8 $(MANDIR)
+
+ radius.so: radius.o libradiusclient.a
+- $(CC) -o radius.so -shared radius.o libradiusclient.a
++ $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $^
+
+ radattr.so: radattr.o
+- $(CC) -o radattr.so -shared radattr.o
++ $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $^
+
+ radrealms.so: radrealms.o
+- $(CC) -o radrealms.so -shared radrealms.o
++ $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $^
+
+ CLIENTOBJS = avpair.o buildreq.o config.o dict.o ip_util.o \
+ clientid.o sendserver.o lock.o util.o md5.o
+--- ppp-2.4.5/pppd/plugins/rp-pppoe/Makefile.linux
++++ ppp-2.4.5/pppd/plugins/rp-pppoe/Makefile.linux
+@@ -25,12 +25,11 @@
+ # Version is set ONLY IN THE MAKEFILE! Don't delete this!
+ RP_VERSION=3.8p
+
+-COPTS=-O2 -g
+ CFLAGS=$(COPTS) -I../../../include '-DRP_VERSION="$(RP_VERSION)"'
+ all: rp-pppoe.so pppoe-discovery
+
+ pppoe-discovery: pppoe-discovery.o debug.o
+- $(CC) -o pppoe-discovery pppoe-discovery.o debug.o
++ $(CC) $(LDFLAGS_PROG) $(CFLAGS) -o pppoe-discovery pppoe-discovery.o debug.o
+
+ pppoe-discovery.o: pppoe-discovery.c
+ $(CC) $(CFLAGS) -c -o pppoe-discovery.o pppoe-discovery.c
+@@ -39,7 +38,7 @@
+ $(CC) $(CFLAGS) -c -o debug.o debug.c
+
+ rp-pppoe.so: plugin.o discovery.o if.o common.o
+- $(CC) -o rp-pppoe.so -shared plugin.o discovery.o if.o common.o
++ $(CC) $(LDFLAGS) $(CFLAGS) -o rp-pppoe.so plugin.o discovery.o if.o common.o
+
+ install: all
+ $(INSTALL) -d -m 755 $(LIBDIR)
+--- ppp-2.4.5/pppdump/Makefile.linux
++++ ppp-2.4.5/pppdump/Makefile.linux
+@@ -2,7 +2,7 @@
+ BINDIR = $(DESTDIR)/sbin
+ MANDIR = $(DESTDIR)/share/man/man8
+
+-CFLAGS= -O -I../include/net
++CFLAGS=$(COPTS) -I../include/net
+ OBJS = pppdump.o bsd-comp.o deflate.o zlib.o
+
+ INSTALL= install
+@@ -10,7 +10,7 @@
+ all: pppdump
+
+ pppdump: $(OBJS)
+- $(CC) -o pppdump $(OBJS)
++ $(CC) $(LDFLAGS) -o pppdump $(OBJS)
+
+ clean:
+ rm -f pppdump $(OBJS) *~
+--- ppp-2.4.5/pppstats/Makefile.linux
++++ ppp-2.4.5/pppstats/Makefile.linux
+@@ -10,7 +10,6 @@
+ PPPSTATOBJS = pppstats.o
+
+ #CC = gcc
+-COPTS = -O
+ COMPILE_FLAGS = -I../include
+ LIBS =
+
+@@ -26,7 +25,7 @@
+ $(INSTALL) -c -m 444 pppstats.8 $(MANDIR)
+
+ pppstats: $(PPPSTATSRCS)
+- $(CC) $(CFLAGS) -o pppstats pppstats.c $(LIBS)
++ $(CC) $(CFLAGS) $(LDFLAGS) -o pppstats pppstats.c $(LIBS)
+
+ clean:
+ rm -f pppstats *~ #* core
diff --git a/user/ppp/03_all_use_internal_logwtmp.patch b/user/ppp/03_all_use_internal_logwtmp.patch
new file mode 100644
index 000000000..d9ecddf25
--- /dev/null
+++ b/user/ppp/03_all_use_internal_logwtmp.patch
@@ -0,0 +1,22 @@
+Use internal implementation of logwtmp function to prevent
+utilities from sys-apps/coreutils to not detect authorized users
+
+Patch by: Sergey Popov <pinkbyte@gentoo.org>
+
+--- a/pppd/sys-linux.c
++++ b/pppd/sys-linux.c
+@@ -2196,7 +2197,6 @@
+ return ok;
+ }
+
+-#ifndef HAVE_LOGWTMP
+ /********************************************************************
+ *
+ * Update the wtmp file with the appropriate user name and tty device.
+@@ -2270,7 +2270,7 @@
+ }
+ #endif
+ }
+-#endif /* HAVE_LOGWTMP */
++
+
diff --git a/user/ppp/04_all_mpls.patch b/user/ppp/04_all_mpls.patch
new file mode 100644
index 000000000..54b79f7bd
--- /dev/null
+++ b/user/ppp/04_all_mpls.patch
@@ -0,0 +1,427 @@
+--- ppp-2.4.5/pppd/main.c
++++ ppp-2.4.5/pppd/main.c
+@@ -96,6 +96,9 @@
+ #include "fsm.h"
+ #include "lcp.h"
+ #include "ipcp.h"
++
++#include "mplscp.h"
++
+ #ifdef INET6
+ #include "ipv6cp.h"
+ #endif
+@@ -283,6 +286,7 @@
+ &cbcp_protent,
+ #endif
+ &ipcp_protent,
++ &mplscp_protent,
+ #ifdef INET6
+ &ipv6cp_protent,
+ #endif
+--- ppp-2.4.5/pppd/Makefile.linux
++++ ppp-2.4.5/pppd/Makefile.linux
+@@ -13,16 +13,16 @@
+
+ PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap-new.c md5.c ccp.c \
+ ecp.c ipxcp.c auth.c options.c sys-linux.c md4.c chap_ms.c \
+- demand.c utils.c tty.c eap.c chap-md5.c session.c
++ demand.c utils.c tty.c eap.c chap-md5.c session.c mplscp.c
+
+ HEADERS = ccp.h session.h chap-new.h ecp.h fsm.h ipcp.h \
+ ipxcp.h lcp.h magic.h md5.h patchlevel.h pathnames.h pppd.h \
+- upap.h eap.h
++ upap.h eap.h mplscp.h
+
+ MANPAGES = pppd.8
+ PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap-new.o md5.o ccp.o \
+ ecp.o auth.o options.o demand.o utils.o sys-linux.o ipxcp.o tty.o \
+- eap.o chap-md5.o session.o
++ eap.o chap-md5.o session.o mplscp.o
+
+ #
+ # include dependencies if present
+--- ppp-2.4.5/pppd/mplscp.c
++++ ppp-2.4.5/pppd/mplscp.c
+@@ -0,0 +1,371 @@
++
++/* MPLSCP - Serge.Krier@advalvas.be (C) 2001 */
++
++#include <stdio.h>
++#include <string.h>
++#include <netdb.h>
++#include <sys/param.h>
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <arpa/inet.h>
++
++#include "pppd.h"
++#include "fsm.h"
++#include "mplscp.h"
++
++
++/* local vars */
++/* static int mplscp_is_up; */ /* have called np_up() */
++
++/*
++ * Callbacks for fsm code. (CI = Configuration Information)
++ */
++static void mplscp_resetci __P((fsm *)); /* Reset our CI */
++static int mplscp_cilen __P((fsm *)); /* Return length of our CI */
++static void mplscp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
++static int mplscp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */
++static int mplscp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */
++static int mplscp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */
++static int mplscp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
++static void mplscp_up __P((fsm *)); /* We're UP */
++static void mplscp_down __P((fsm *)); /* We're DOWN */
++static void mplscp_finished __P((fsm *)); /* Don't need lower layer */
++
++fsm mplscp_fsm[NUM_PPP]; /* MPLSCP fsm structure */
++
++static fsm_callbacks mplscp_callbacks = { /* MPLSCP callback routines */
++ mplscp_resetci, /* Reset our Configuration Information */
++ mplscp_cilen, /* Length of our Configuration Information */
++ mplscp_addci, /* Add our Configuration Information */
++ mplscp_ackci, /* ACK our Configuration Information */
++ mplscp_nakci, /* NAK our Configuration Information */
++ mplscp_rejci, /* Reject our Configuration Information */
++ mplscp_reqci, /* Request peer's Configuration Information */
++ mplscp_up, /* Called when fsm reaches OPENED state */
++ mplscp_down, /* Called when fsm leaves OPENED state */
++ NULL, /* Called when we want the lower layer up */
++ mplscp_finished, /* Called when we want the lower layer down */
++ NULL, /* Called when Protocol-Reject received */
++ NULL, /* Retransmission is necessary */
++ NULL, /* Called to handle protocol-specific codes */
++ "MPLSCP" /* String name of protocol */
++};
++
++static option_t mplscp_option_list[] = {
++ { "mpls", o_bool, &mplscp_protent.enabled_flag,
++ "Enable MPLSCP (and MPLS)", 1 },
++ { NULL } };
++
++/*
++ * Protocol entry points from main code.
++ */
++
++static void mplscp_init __P((int));
++static void mplscp_open __P((int));
++static void mplscp_close __P((int, char *));
++static void mplscp_lowerup __P((int));
++static void mplscp_lowerdown __P((int));
++static void mplscp_input __P((int, u_char *, int));
++static void mplscp_protrej __P((int));
++static int mplscp_printpkt __P((u_char *, int,
++ void (*) __P((void *, char *, ...)), void *));
++
++struct protent mplscp_protent = {
++ PPP_MPLSCP,
++ mplscp_init,
++ mplscp_input,
++ mplscp_protrej,
++ mplscp_lowerup,
++ mplscp_lowerdown,
++ mplscp_open,
++ mplscp_close,
++ mplscp_printpkt,
++ NULL,
++ 0, /* MPLS not enabled by default */
++ "MPLSCP",
++ "MPLS",
++ mplscp_option_list,
++ NULL,
++ NULL,
++ NULL
++};
++
++/*
++ * mplscp_init - Initialize MPLSCP.
++ */
++static void
++mplscp_init(int unit) {
++
++ fsm *f = &mplscp_fsm[unit];
++
++ f->unit = unit;
++ f->protocol = PPP_MPLSCP;
++ f->callbacks = &mplscp_callbacks;
++ fsm_init(&mplscp_fsm[unit]);
++
++}
++
++/*
++ * mplscp_open - MPLSCP is allowed to come up.
++ */
++static void
++mplscp_open(int unit) {
++
++ fsm_open(&mplscp_fsm[unit]);
++
++}
++
++/*
++ * mplscp_close - Take MPLSCP down.
++ */
++static void
++mplscp_close(int unit, char *reason) {
++
++ fsm_close(&mplscp_fsm[unit], reason);
++
++}
++
++/*
++ * mplscp_lowerup - The lower layer is up.
++ */
++static void
++mplscp_lowerup(int unit) {
++
++ fsm_lowerup(&mplscp_fsm[unit]);
++}
++
++/*
++ * mplscp_lowerdown - The lower layer is down.
++ */
++static void
++mplscp_lowerdown(int unit) {
++
++ fsm_lowerdown(&mplscp_fsm[unit]);
++}
++
++/*
++ * mplscp_input - Input MPLSCP packet.
++ */
++static void
++mplscp_input(int unit, u_char *p, int len) {
++
++ fsm_input(&mplscp_fsm[unit], p, len);
++}
++
++/*
++ * mplscp_protrej - A Protocol-Reject was received for MPLSCP.
++ * Pretend the lower layer went down, so we shut up.
++ */
++static void
++mplscp_protrej(int unit) {
++
++ fsm_lowerdown(&mplscp_fsm[unit]);
++}
++
++/*
++ * mplscp_resetci - Reset our CI.
++ * Called by fsm_sconfreq, Send Configure Request.
++ */
++static void
++mplscp_resetci(fsm *f) {
++
++ return;
++}
++
++/*
++ * mplscp_cilen - Return length of our CI.
++ * Called by fsm_sconfreq, Send Configure Request.
++ */
++static int
++mplscp_cilen(fsm *f) {
++
++ return 0;
++}
++
++/*
++ * mplscp_addci - Add our desired CIs to a packet.
++ * Called by fsm_sconfreq, Send Configure Request.
++ */
++static void
++mplscp_addci(fsm *f, u_char *ucp, int *lenp) {
++
++}
++
++/*
++ * ipcp_ackci - Ack our CIs.
++ * Called by fsm_rconfack, Receive Configure ACK.
++ *
++ * Returns:
++ * 0 - Ack was bad.
++ * 1 - Ack was good.
++ */
++static int
++mplscp_ackci(fsm *f, u_char *p, int len) {
++
++ return 1;
++
++}
++
++/*
++ * mplscp_nakci - Peer has sent a NAK for some of our CIs.
++ * This should not modify any state if the Nak is bad
++ * or if MPLSCP is in the OPENED state.
++ * Calback from fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
++ *
++ * Returns:
++ * 0 - Nak was bad.
++ * 1 - Nak was good.
++ */
++static int
++mplscp_nakci(fsm *f, u_char *p, int len) {
++
++ return 1;
++}
++
++/*
++ * MPLSVP_rejci - Reject some of our CIs.
++ * Callback from fsm_rconfnakrej.
++ */
++static int
++mplscp_rejci(fsm *f, u_char *p, int len) {
++
++ return 1;
++
++}
++
++/*
++ * mplscp_reqci - Check the peer's requested CIs and send appropriate response.
++ * Callback from fsm_rconfreq, Receive Configure Request
++ *
++ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
++ * appropriately. If reject_if_disagree is non-zero, doesn't return
++ * CONFNAK; returns CONFREJ if it can't return CONFACK.
++ */
++static int
++mplscp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree) {
++
++
++ int rc = CONFACK; /* Final packet return code */
++
++ PUTCHAR(CONFACK,inp);
++
++ return rc;
++
++}
++
++static void
++mplscp_up(fsm *f) {
++
++ sifnpmode(f->unit, PPP_MPLS_UC, NPMODE_PASS);
++ /* sifnpmode(f->unit, PPP_MPLS_MC, NPMODE_PASS);*/
++
++ np_up(f->unit, PPP_MPLS_UC);
++ /* np_up(f->unit, PPP_MPLS_MC);*/
++ /* ipcp_is_up = 1;*/
++
++
++#if 1
++ printf("MPLSCP is OPENED\n");
++#endif
++
++}
++
++static void
++mplscp_down(fsm *f) {
++
++ sifnpmode(f->unit, PPP_MPLS_UC, NPMODE_DROP);
++ /* sifnpmode(f->unit, PPP_MPLS_MC, NPMODE_DROP);*/
++
++ sifdown(f->unit);
++
++#if 1
++ printf("MPLSCP is CLOSED\n");
++#endif
++
++
++}
++
++static void
++mplscp_finished(fsm *f) {
++
++ np_finished(f->unit, PPP_MPLS_UC);
++ /* np_finished(f->unit, PPP_MPLS_MC);*/
++
++}
++
++/*
++ * mpls_printpkt - print the contents of an MPLSCP packet.
++ */
++static char *mplscp_codenames[] = {
++ "ConfReq", "ConfAck", "ConfNak", "ConfRej",
++ "TermReq", "TermAck", "CodeRej"
++};
++
++static int
++mplscp_printpkt(u_char *p, int plen,
++ void (*printer) __P((void *, char *, ...)),
++ void *arg) {
++
++ int code, id, len, olen;
++ u_char *pstart, *optend;
++
++ if (plen < HEADERLEN)
++ return 0;
++ pstart = p;
++ GETCHAR(code, p);
++ GETCHAR(id, p);
++ GETSHORT(len, p);
++ if (len < HEADERLEN || len > plen)
++ return 0;
++
++ if (code >= 1 && code <= sizeof(mplscp_codenames) / sizeof(char *))
++ printer(arg, " %s", mplscp_codenames[code-1]);
++ else
++ printer(arg, " code=0x%x", code);
++ printer(arg, " id=0x%x", id);
++ len -= HEADERLEN;
++ switch (code) {
++ case CONFREQ:
++ case CONFACK:
++ case CONFNAK:
++ case CONFREJ:
++ /* print option list */
++ while (len >= 2) {
++ GETCHAR(code, p);
++ GETCHAR(olen, p);
++ p -= 2;
++ if (olen < 2 || olen > len) {
++ break;
++ }
++ printer(arg, " <");
++ len -= olen;
++ optend = p + olen;
++ while (p < optend) {
++ GETCHAR(code, p);
++ printer(arg, " %.2x", code);
++ }
++ printer(arg, ">");
++ }
++ break;
++
++ case TERMACK:
++ case TERMREQ:
++ if (len > 0 && *p >= ' ' && *p < 0x7f) {
++ printer(arg, " ");
++ print_string((char *)p, len, printer, arg);
++ p += len;
++ len = 0;
++ }
++ break;
++ }
++
++ /* print the rest of the bytes in the packet */
++ for (; len > 0; --len) {
++ GETCHAR(code, p);
++ printer(arg, " %.2x", code);
++ }
++
++ return p - pstart;
++
++}
+--- ppp-2.4.5/pppd/mplscp.h
++++ ppp-2.4.5/pppd/mplscp.h
+@@ -0,0 +1,8 @@
++
++/* MPLSCP - Serge.Krier@advalvas.be (C) 2001 */
++
++#define PPP_MPLSCP 0x8281
++#define PPP_MPLS_UC 0x0281
++#define PPP_MPLS_MC 0x0283
++
++extern struct protent mplscp_protent;
diff --git a/user/ppp/06_all_killaddr-smarter.patch b/user/ppp/06_all_killaddr-smarter.patch
new file mode 100644
index 000000000..d86534843
--- /dev/null
+++ b/user/ppp/06_all_killaddr-smarter.patch
@@ -0,0 +1,131 @@
+--- ppp-2.4.5/pppd/options.c
++++ ppp-2.4.5/pppd/options.c
+@@ -100,6 +100,9 @@
+ char user[MAXNAMELEN]; /* Username for PAP */
+ char passwd[MAXSECRETLEN]; /* Password for PAP */
+ bool persist = 0; /* Reopen link after it goes down */
++bool killoldaddr = 0; /* If our IP is reassigned on
++ reconnect, kill active TCP
++ connections using the old IP. */
+ char our_name[MAXNAMELEN]; /* Our name for authentication purposes */
+ bool demand = 0; /* do dial-on-demand */
+ char *ipparam = NULL; /* Extra parameter for ip up/down scripts */
+@@ -231,6 +234,11 @@
+ { "demand", o_bool, &demand,
+ "Dial on demand", OPT_INITONLY | 1, &persist },
+
++ { "killoldaddr", o_bool, &killoldaddr,
++ "Kill connections from an old source address", 1},
++ { "nokilloldaddr", o_bool,&killoldaddr,
++ "Don't kill connections from an old source address" },
++
+ { "--version", o_special_noarg, (void *)showversion,
+ "Show version number" },
+ { "--help", o_special_noarg, (void *)showhelp,
+--- ppp-2.4.5/pppd/pppd.h
++++ ppp-2.4.5/pppd/pppd.h
+@@ -298,6 +298,9 @@
+ extern char remote_name[MAXNAMELEN]; /* Peer's name for authentication */
+ extern bool explicit_remote;/* remote_name specified with remotename opt */
+ extern bool demand; /* Do dial-on-demand */
++extern bool killoldaddr; /* If our IP is reassigned on
++ reconnect, kill active TCP
++ connections using the old IP. */
+ extern char *ipparam; /* Extra parameter for ip up/down scripts */
+ extern bool cryptpap; /* Others' PAP passwords are encrypted */
+ extern int idle_time_limit;/* Shut down link if idle for this long */
+--- ppp-2.4.5/pppd/sys-linux.c
++++ ppp-2.4.5/pppd/sys-linux.c
+@@ -165,6 +165,10 @@
+
+ #endif /* INET6 */
+
++#ifndef SIOCKILLADDR
++#define SIOCKILLADDR 0x8939
++#endif
++
+ /* We can get an EIO error on an ioctl if the modem has hung up */
+ #define ok_error(num) ((num)==EIO)
+
+@@ -209,6 +213,7 @@
+ static u_int32_t proxy_arp_addr; /* Addr for proxy arp entry added */
+ static char proxy_arp_dev[16]; /* Device for proxy arp entry */
+ static u_int32_t our_old_addr; /* for detecting address changes */
++static u_int32_t our_current_addr;
+ static int dynaddr_set; /* 1 if ip_dynaddr set */
+ static int looped; /* 1 if using loop */
+ static int link_mtu; /* mtu for the link (not bundle) */
+@@ -537,6 +542,27 @@
+ return -1;
+ }
+
++static void do_killaddr(u_int32_t oldaddr)
++{
++ struct ifreq ifr;
++
++ memset(&ifr,0,sizeof ifr);
++
++ SET_SA_FAMILY (ifr.ifr_addr, AF_INET);
++ SET_SA_FAMILY (ifr.ifr_dstaddr, AF_INET);
++ SET_SA_FAMILY (ifr.ifr_netmask, AF_INET);
++
++ SIN_ADDR(ifr.ifr_addr) = oldaddr;
++
++ strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
++
++ if(ioctl(sock_fd,SIOCKILLADDR,&ifr) < 0) {
++ if (!ok_error (errno))
++ error("ioctl(SIOCKILLADDR): %m(%d)", errno);
++ return;
++ }
++}
++
+ /********************************************************************
+ *
+ * tty_disestablish_ppp - Restore the serial port to normal operation.
+@@ -2385,21 +2411,29 @@
+ }
+ }
+
+- /* set ip_dynaddr in demand mode if address changes */
+- if (demand && tune_kernel && !dynaddr_set
+- && our_old_addr && our_old_addr != our_adr) {
++ if(persist && our_old_addr && our_old_addr != our_adr) {
++
++ if(killoldaddr)
++ do_killaddr(our_old_addr);
++
++
++ /* set ip_dynaddr in persist mode if address changes */
++ if (tune_kernel && !dynaddr_set) {
+ /* set ip_dynaddr if possible */
+ char *path;
+ int fd;
+
+ path = path_to_procfs("/sys/net/ipv4/ip_dynaddr");
+ if (path != 0 && (fd = open(path, O_WRONLY)) >= 0) {
+- if (write(fd, "1", 1) != 1)
+- error("Couldn't enable dynamic IP addressing: %m");
+- close(fd);
++ if (write(fd, "1", 1) != 1)
++ error("Couldn't enable dynamic IP addressing: %m");
++ close(fd);
+ }
+ dynaddr_set = 1; /* only 1 attempt */
++ }
+ }
++
++ our_current_addr = our_adr;
+ our_old_addr = 0;
+
+ return 1;
+@@ -2455,7 +2489,8 @@
+ }
+
+ our_old_addr = our_adr;
+-
++ our_current_addr = 0;
++
+ return 1;
+ }
+
diff --git a/user/ppp/08_all_wait-children.patch b/user/ppp/08_all_wait-children.patch
new file mode 100644
index 000000000..708cf04d6
--- /dev/null
+++ b/user/ppp/08_all_wait-children.patch
@@ -0,0 +1,76 @@
+--- ppp-2.4.5/pppd/main.c
++++ ppp-2.4.5/pppd/main.c
+@@ -249,6 +249,7 @@
+ static void forget_child __P((int pid, int status));
+ static int reap_kids __P((void));
+ static void childwait_end __P((void *));
++static void wait_children __P((void));
+
+ #ifdef USE_TDB
+ static void update_db_entry __P((void));
+@@ -580,25 +581,11 @@
+ if (!persist)
+ break;
+ }
++
++ wait_children();
+ }
+
+- /* Wait for scripts to finish */
+- reap_kids();
+- if (n_children > 0) {
+- if (child_wait > 0)
+- TIMEOUT(childwait_end, NULL, child_wait);
+- if (debug) {
+- struct subprocess *chp;
+- dbglog("Waiting for %d child processes...", n_children);
+- for (chp = children; chp != NULL; chp = chp->next)
+- dbglog(" script %s, pid %d", chp->prog, chp->pid);
+- }
+- while (n_children > 0 && !childwait_done) {
+- handle_events();
+- if (kill_link && !childwait_done)
+- childwait_end(NULL);
+- }
+- }
++ wait_children();
+
+ die(status);
+ return 0;
+@@ -1794,6 +1781,36 @@
+ }
+
+ /*
++ * wait_children - wait for scripts to finish.
++ * if child_wait is 0, wait indefinitely.
++ * else, kill'em all at the end of timeout
++ */
++static void
++wait_children()
++{
++ /* Wait for scripts to finish */
++ reap_kids();
++ if (n_children > 0) {
++ childwait_done = 0;
++ if (child_wait > 0)
++ TIMEOUT(childwait_end, NULL, child_wait);
++ if (debug) {
++ struct subprocess *chp;
++ dbglog("Waiting for %d child processes...", n_children);
++ for (chp = children; chp != NULL; chp = chp->next)
++ dbglog(" script %s, pid %d", chp->prog, chp->pid);
++ }
++ while (n_children > 0 && !childwait_done) {
++ handle_events();
++ if (asked_to_quit && !childwait_done)
++ childwait_end(NULL);
++ }
++ if (child_wait > 0)
++ UNTIMEOUT(childwait_end, NULL);
++ }
++}
++
++/*
+ * childwait_end - we got fed up waiting for the child processes to
+ * exit, send them all a SIGTERM.
+ */
diff --git a/user/ppp/10_all_defaultgateway.patch b/user/ppp/10_all_defaultgateway.patch
new file mode 100644
index 000000000..1b7ae6396
--- /dev/null
+++ b/user/ppp/10_all_defaultgateway.patch
@@ -0,0 +1,90 @@
+This patch reverses revision 1.114 of the pppd/sys-linux.c file.
+The default gateway is needed by the openswan's %defaultroute.
+
+--- ppp-2.4.7/pppd/sys-linux.c
++++ ppp-2.4.7/pppd/sys-linux.c
+@@ -206,7 +206,7 @@
+
+ static int if_is_up; /* Interface has been marked up */
+ static int if6_is_up; /* Interface has been marked up for IPv6, to help differentiate */
+-static int have_default_route; /* Gateway for default route added */
++static u_int32_t default_route_gateway; /* Gateway for default route added */
+ static u_int32_t proxy_arp_addr; /* Addr for proxy arp entry added */
+ static char proxy_arp_dev[16]; /* Device for proxy arp entry */
+ static u_int32_t our_old_addr; /* for detecting address changes */
+@@ -346,8 +346,8 @@
+ /*
+ * Delete any routes through the device.
+ */
+- if (have_default_route)
+- cifdefaultroute(0, 0, 0);
++ if (default_route_gateway != 0)
++ cifdefaultroute(0, 0, default_route_gateway);
+
+ if (has_proxy_arp)
+ cifproxyarp(0, proxy_arp_addr);
+@@ -1621,17 +1621,17 @@
+ struct rtentry rt;
+
+ if (defaultroute_exists(&rt) && strcmp(rt.rt_dev, ifname) != 0) {
+- if (rt.rt_flags & RTF_GATEWAY)
+- error("not replacing existing default route via %I",
+- SIN_ADDR(rt.rt_gateway));
+- else
+- error("not replacing existing default route through %s",
+- rt.rt_dev);
++ u_int32_t old_gateway = SIN_ADDR(rt.rt_gateway);
++
++ if (old_gateway != gateway)
++ error("not replacing existing default route to %s [%I]",
++ rt.rt_dev, old_gateway);
+ return 0;
+ }
+
+- memset (&rt, 0, sizeof (rt));
+- SET_SA_FAMILY (rt.rt_dst, AF_INET);
++ memset (&rt, '\0', sizeof (rt));
++ SET_SA_FAMILY (rt.rt_dst, AF_INET);
++ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
+
+ rt.rt_dev = ifname;
+
+@@ -1640,14 +1640,16 @@
+ SIN_ADDR(rt.rt_genmask) = 0L;
+ }
+
+- rt.rt_flags = RTF_UP;
++ SIN_ADDR(rt.rt_gateway) = gateway;
++
++ rt.rt_flags = RTF_UP | RTF_GATEWAY;
+ if (ioctl(sock_fd, SIOCADDRT, &rt) < 0) {
+ if ( ! ok_error ( errno ))
+ error("default route ioctl(SIOCADDRT): %m");
+ return 0;
+ }
+
+- have_default_route = 1;
++ default_route_gateway = gateway;
+ return 1;
+ }
+
+@@ -1660,7 +1662,7 @@
+ {
+ struct rtentry rt;
+
+- have_default_route = 0;
++ default_route_gateway = 0;
+
+ memset (&rt, '\0', sizeof (rt));
+ SET_SA_FAMILY (rt.rt_dst, AF_INET);
+@@ -1673,7 +1675,9 @@
+ SIN_ADDR(rt.rt_genmask) = 0L;
+ }
+
+- rt.rt_flags = RTF_UP;
++ SIN_ADDR(rt.rt_gateway) = gateway;
++
++ rt.rt_flags = RTF_UP | RTF_GATEWAY;
+ if (ioctl(sock_fd, SIOCDELRT, &rt) < 0 && errno != ESRCH) {
+ if (still_ppp()) {
+ if ( ! ok_error ( errno ))
diff --git a/user/ppp/12_all_linkpidfile.patch b/user/ppp/12_all_linkpidfile.patch
new file mode 100644
index 000000000..9c5769c8f
--- /dev/null
+++ b/user/ppp/12_all_linkpidfile.patch
@@ -0,0 +1,93 @@
+--- ppp-2.4.5/pppd/auth.c
++++ ppp-2.4.5/pppd/auth.c
+@@ -637,7 +637,7 @@
+ * we delete its pid file.
+ */
+ if (!doing_multilink && !demand)
+- remove_pidfiles();
++ remove_pidfile(pidfilename);
+
+ /*
+ * If we may want to bring the link up again, transfer
+--- ppp-2.4.5/pppd/main.c
++++ ppp-2.4.5/pppd/main.c
+@@ -134,7 +134,7 @@
+
+ char *progname; /* Name of this program */
+ char hostname[MAXNAMELEN]; /* Our hostname */
+-static char pidfilename[MAXPATHLEN]; /* name of pid file */
++char pidfilename[MAXPATHLEN]; /* name of pid file */
+ static char linkpidfile[MAXPATHLEN]; /* name of linkname pid file */
+ char ppp_devnam[MAXPATHLEN]; /* name of PPP tty (maybe ttypx) */
+ uid_t uid; /* Our real user-id */
+@@ -245,6 +245,7 @@
+ static void toggle_debug __P((int));
+ static void open_ccp __P((int));
+ static void bad_signal __P((int));
++static void remove_pidfilenames __P((void));
+ static void holdoff_end __P((void *));
+ static void forget_child __P((int pid, int status));
+ static int reap_kids __P((void));
+@@ -835,16 +836,24 @@
+ }
+
+ /*
+- * remove_pidfile - remove our pid files
++ * remove_pidfile - remove one of the 2 pidfiles (pidfilename or linkpidfile)
+ */
+-void remove_pidfiles()
++void
++remove_pidfile(filename)
++ char* filename;
+ {
+- if (pidfilename[0] != 0 && unlink(pidfilename) < 0 && errno != ENOENT)
+- warn("unable to delete pid file %s: %m", pidfilename);
+- pidfilename[0] = 0;
+- if (linkpidfile[0] != 0 && unlink(linkpidfile) < 0 && errno != ENOENT)
+- warn("unable to delete pid file %s: %m", linkpidfile);
+- linkpidfile[0] = 0;
++ if (filename[0] != 0 && unlink(filename) < 0 && errno != ENOENT)
++ warn("unable to delete pid file %s: %m", filename);
++ filename[0] = 0;
++}
++
++/*
++ * remove_pidfiles - remove our pid files
++ */
++static void remove_pidfiles()
++{
++ remove_pidfile(pidfilename);
++ remove_pidfile(linkpidfile);
+ }
+
+ /*
+--- ppp-2.4.5/pppd/multilink.c
++++ ppp-2.4.5/pppd/multilink.c
+@@ -267,7 +267,7 @@
+ notice("Connection terminated.");
+ print_link_stats();
+ if (!demand) {
+- remove_pidfiles();
++ remove_pidfile(pidfilename);
+ script_unsetenv("IFNAME");
+ }
+
+--- ppp-2.4.5/pppd/pppd.h
++++ ppp-2.4.5/pppd/pppd.h
+@@ -214,6 +214,7 @@
+ extern int ifunit; /* Interface unit number */
+ extern char ifname[]; /* Interface name */
+ extern char hostname[]; /* Our hostname */
++extern char pidfilename[]; /* name of pid file */
+ extern u_char outpacket_buf[]; /* Buffer for outgoing packets */
+ extern int devfd; /* fd of underlying device */
+ extern int fd_ppp; /* fd for talking PPP */
+@@ -497,7 +498,7 @@
+ int ppp_send_config __P((int, int, u_int32_t, int, int));
+ int ppp_recv_config __P((int, int, u_int32_t, int, int));
+ const char *protocol_name __P((int));
+-void remove_pidfiles __P((void));
++void remove_pidfile __P((char *));
+ void lock_db __P((void));
+ void unlock_db __P((void));
+
diff --git a/user/ppp/16_all_auth-fail.patch b/user/ppp/16_all_auth-fail.patch
new file mode 100644
index 000000000..8ae238035
--- /dev/null
+++ b/user/ppp/16_all_auth-fail.patch
@@ -0,0 +1,138 @@
+--- ppp-2.4.5/pppd/auth.c
++++ ppp-2.4.5/pppd/auth.c
+@@ -259,7 +259,7 @@
+ struct wordlist **, struct wordlist **,
+ char *, int));
+ static void free_wordlist __P((struct wordlist *));
+-static void auth_script __P((char *));
++static void auth_script __P((char *, int));
+ static void auth_script_done __P((void *));
+ static void set_allowed_addrs __P((int, struct wordlist *, struct wordlist *));
+ static int some_ip_ok __P((struct wordlist *));
+@@ -690,7 +690,7 @@
+ if (auth_script_state == s_up && auth_script_pid == 0) {
+ update_link_stats(unit);
+ auth_script_state = s_down;
+- auth_script(_PATH_AUTHDOWN);
++ auth_script(_PATH_AUTHDOWN, 0);
+ }
+ }
+ if (!doing_multilink) {
+@@ -822,7 +822,7 @@
+ auth_state = s_up;
+ if (auth_script_state == s_down && auth_script_pid == 0) {
+ auth_script_state = s_up;
+- auth_script(_PATH_AUTHUP);
++ auth_script(_PATH_AUTHUP, 0);
+ }
+ }
+
+@@ -923,6 +923,7 @@
+ * Authentication failure: take the link down
+ */
+ status = EXIT_PEER_AUTH_FAILED;
++ auth_script(_PATH_AUTHFAIL, 1);
+ lcp_close(unit, "Authentication failed");
+ }
+
+@@ -1001,6 +1002,7 @@
+ * authentication secrets.
+ */
+ status = EXIT_AUTH_TOPEER_FAILED;
++ auth_script(_PATH_AUTHFAIL, 1);
+ lcp_close(unit, "Failed to authenticate ourselves to peer");
+ }
+
+@@ -1233,6 +1235,8 @@
+ if (user[0] == 0 && !explicit_user)
+ strlcpy(user, our_name, sizeof(user));
+
++ script_setenv("LOCALNAME", user, 0);
++
+ /*
+ * If we have a default route, require the peer to authenticate
+ * unless the noauth option was given or the real user is root.
+@@ -2314,13 +2318,13 @@
+ case s_up:
+ if (auth_state == s_down) {
+ auth_script_state = s_down;
+- auth_script(_PATH_AUTHDOWN);
++ auth_script(_PATH_AUTHDOWN, 0);
+ }
+ break;
+ case s_down:
+ if (auth_state == s_up) {
+ auth_script_state = s_up;
+- auth_script(_PATH_AUTHUP);
++ auth_script(_PATH_AUTHUP, 0);
+ }
+ break;
+ }
+@@ -2331,8 +2335,9 @@
+ * interface-name peer-name real-user tty speed
+ */
+ static void
+-auth_script(script)
++auth_script(script, wait)
+ char *script;
++ int wait;
+ {
+ char strspeed[32];
+ struct passwd *pw;
+@@ -2356,5 +2361,8 @@
+ argv[5] = strspeed;
+ argv[6] = NULL;
+
+- auth_script_pid = run_program(script, argv, 0, auth_script_done, NULL, 0);
++ if (wait)
++ run_program(script, argv, 0, NULL, NULL, 1);
++ else
++ auth_script_pid = run_program(script, argv, 0, auth_script_done, NULL, 0);
+ }
+--- ppp-2.4.5/pppd/pathnames.h
++++ ppp-2.4.5/pppd/pathnames.h
+@@ -27,6 +27,7 @@
+ #define _PATH_IPPREUP _ROOT_PATH "/etc/ppp/ip-pre-up"
+ #define _PATH_AUTHUP _ROOT_PATH "/etc/ppp/auth-up"
+ #define _PATH_AUTHDOWN _ROOT_PATH "/etc/ppp/auth-down"
++#define _PATH_AUTHFAIL _ROOT_PATH "/etc/ppp/auth-fail"
+ #define _PATH_TTYOPT _ROOT_PATH "/etc/ppp/options."
+ #define _PATH_CONNERRS _ROOT_PATH "/etc/ppp/connect-errors"
+ #define _PATH_PEERFILES _ROOT_PATH "/etc/ppp/peers/"
+--- ppp-2.4.5/pppd/pppd.8
++++ ppp-2.4.5/pppd/pppd.8
+@@ -1553,8 +1553,8 @@
+ Pppd invokes scripts at various stages in its processing which can be
+ used to perform site-specific ancillary processing. These scripts are
+ usually shell scripts, but could be executable code files instead.
+-Pppd does not wait for the scripts to finish (except for the ip-pre-up
+-script). The scripts are
++Pppd does not wait for the scripts to finish (except for the ip-pre-up,
++and auth-fail scripts). The scripts are
+ executed as root (with the real and effective user-id set to 0), so
+ that they can do things such as update routing tables or run
+ privileged daemons. Be careful that the contents of these scripts do
+@@ -1582,6 +1582,11 @@
+ The authenticated name of the peer. This is only set if the peer
+ authenticates itself.
+ .TP
++.B LOCALNAME
++The username passed to the user option of the pppd daemon. This is
++handy to identify which account was used for authentication purposes
++when multiple accounts are available.
++.TP
+ .B SPEED
+ The baud rate of the tty device.
+ .TP
+@@ -1634,6 +1639,11 @@
+ /etc/ppp/auth\-up was previously executed. It is executed in the same
+ manner with the same parameters as /etc/ppp/auth\-up.
+ .TP
++.B /etc/ppp/auth\-fail
++A program or script which is executed should authentication fail. pppd
++waits for this script to finish. It is executed in the same manner, with
++the same parameters as /etc/ppp/auth\-up.
++.TP
+ .B /etc/ppp/ip\-pre\-up
+ A program or script which is executed just before the ppp network
+ interface is brought up. It is executed with the same parameters as
diff --git a/user/ppp/18_all_defaultmetric.patch b/user/ppp/18_all_defaultmetric.patch
new file mode 100644
index 000000000..fba787005
--- /dev/null
+++ b/user/ppp/18_all_defaultmetric.patch
@@ -0,0 +1,104 @@
+--- ppp-2.4.5/pppd/options.c
++++ ppp-2.4.5/pppd/options.c
+@@ -94,6 +94,7 @@
+ int kdebugflag = 0; /* Tell kernel to print debug messages */
+ int default_device = 1; /* Using /dev/tty or equivalent */
+ char devnam[MAXPATHLEN]; /* Device name */
++int defaultmetric = 0; /* Metric of the default route */
+ bool nodetach = 0; /* Don't detach from controlling tty */
+ bool updetach = 0; /* Detach once link is up */
+ int maxconnect = 0; /* Maximum connect time */
+@@ -289,6 +290,10 @@
+ "Number of seconds to wait for child processes at exit",
+ OPT_PRIO },
+
++ { "defaultmetric", o_int, &defaultmetric,
++ "The metric of the default route",
++ OPT_LIMITS, 0, 32766 },
++
+ #ifdef HAVE_MULTILINK
+ { "multilink", o_bool, &multilink,
+ "Enable multilink operation", OPT_PRIO | 1 },
+--- ppp-2.4.5/pppd/pppd.8
++++ ppp-2.4.5/pppd/pppd.8
+@@ -121,6 +121,9 @@
+ This entry is removed when the PPP connection is broken. This option
+ is privileged if the \fInodefaultroute\fR option has been specified.
+ .TP
++.B defaultmetric \fIn
++The metric of the default route configured by pppd; default is 0.
++.TP
+ .B disconnect \fIscript
+ Execute the command specified by \fIscript\fR, by passing it to a
+ shell, after
+--- ppp-2.4.5/pppd/pppd.h
++++ ppp-2.4.5/pppd/pppd.h
+@@ -276,6 +276,7 @@
+ extern int kdebugflag; /* Tell kernel to print debug messages */
+ extern int default_device; /* Using /dev/tty or equivalent */
+ extern char devnam[MAXPATHLEN]; /* Device name */
++extern int defaultmetric; /* Metric of the default route */
+ extern int crtscts; /* Use hardware flow control */
+ extern bool modem; /* Use modem control lines */
+ extern int inspeed; /* Input/Output speed requested */
+--- ppp-2.4.5/pppd/sys-linux.c
++++ ppp-2.4.5/pppd/sys-linux.c
+@@ -1465,7 +1465,7 @@
+ FILE *route_fd = (FILE *) 0;
+ static char route_buffer[512];
+ static int route_dev_col, route_dest_col, route_gw_col;
+-static int route_flags_col, route_mask_col;
++static int route_flags_col, route_mask_col, route_metric_col;
+ static int route_num_cols;
+
+ static int open_route_table (void);
+@@ -1508,6 +1508,7 @@
+ route_dest_col = 1;
+ route_gw_col = 2;
+ route_flags_col = 3;
++ route_metric_col = 6;
+ route_mask_col = 7;
+ route_num_cols = 8;
+
+@@ -1527,6 +1528,8 @@
+ route_gw_col = col;
+ else if (strcasecmp(q, "flags") == 0)
+ route_flags_col = col;
++ else if (strcasecmp(q, "metric") == 0)
++ route_metric_col = col;
+ else if (strcasecmp(q, "mask") == 0)
+ route_mask_col = col;
+ else
+@@ -1569,6 +1572,7 @@
+
+ rt->rt_flags = (short) strtoul(cols[route_flags_col], NULL, 16);
+ rt->rt_dev = cols[route_dev_col];
++ rt->rt_metric = (short) strtoul(cols[route_metric_col], NULL, 16);
+
+ return 1;
+ }
+@@ -1591,6 +1595,8 @@
+
+ if (kernel_version > KVERSION(2,1,0) && SIN_ADDR(rt->rt_genmask) != 0)
+ continue;
++ if (rt->rt_metric != defaultmetric) /* consider only routes with the same metric */
++ continue;
+ if (SIN_ADDR(rt->rt_dst) == 0L) {
+ result = 1;
+ break;
+@@ -1661,6 +1667,7 @@
+ SIN_ADDR(rt.rt_gateway) = gateway;
+
+ rt.rt_flags = RTF_UP | RTF_GATEWAY;
++ rt.rt_metric = defaultmetric + 1; /* +1 for binary compatibility */
+ if (ioctl(sock_fd, SIOCADDRT, &rt) < 0) {
+ if ( ! ok_error ( errno ))
+ error("default route ioctl(SIOCADDRT): %m");
+@@ -1696,6 +1703,7 @@
+ SIN_ADDR(rt.rt_gateway) = gateway;
+
+ rt.rt_flags = RTF_UP | RTF_GATEWAY;
++ rt.rt_metric = defaultmetric + 1; /* +1 for binary compatibility */
+ if (ioctl(sock_fd, SIOCDELRT, &rt) < 0 && errno != ESRCH) {
+ if (still_ppp()) {
+ if ( ! ok_error ( errno ))
diff --git a/user/ppp/19_all_radius_pid_overflow.patch b/user/ppp/19_all_radius_pid_overflow.patch
new file mode 100644
index 000000000..b5078bdb9
--- /dev/null
+++ b/user/ppp/19_all_radius_pid_overflow.patch
@@ -0,0 +1,14 @@
+https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=782450
+https://bugs.gentoo.org/546554
+
+--- ppp-2.4.7/pppd/plugins/radius/util.c
++++ ppp-2.4.7/pppd/plugins/radius/util.c
+@@ -77,7 +77,7 @@
+ static unsigned short int cnt = 0;
+ sprintf (buf, "%08lX%04X%02hX",
+ (unsigned long int) time (NULL),
+- (unsigned int) getpid (),
++ (unsigned int) getpid () % 65535,
+ cnt & 0xFF);
+ cnt++;
+ return buf;
diff --git a/user/ppp/20_all_dev-ppp.patch b/user/ppp/20_all_dev-ppp.patch
new file mode 100644
index 000000000..eff3e37f0
--- /dev/null
+++ b/user/ppp/20_all_dev-ppp.patch
@@ -0,0 +1,20 @@
+--- ppp-2.4.6/pppd/sys-linux.c
++++ ppp-2.4.6/pppd/sys-linux.c
+@@ -2031,6 +2031,17 @@
+ kernel_version = KVERSION(osmaj, osmin, ospatch);
+
+ fd = open("/dev/ppp", O_RDWR);
++ if (fd < 0) {
++ /* try making it and see if that helps. */
++ if (errno == ENOENT && mknod("/dev/ppp", S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
++ makedev(108, 0)) >= 0) {
++ fd = open("/dev/ppp", O_RDWR);
++ if (fd >= 0)
++ info("Created /dev/ppp device node");
++ else
++ unlink("/dev/ppp"); /* didn't work, undo the mknod */
++ }
++ }
+ if (fd >= 0) {
+ new_style_driver = 1;
+
diff --git a/user/ppp/21_all_custom_iface_names.patch b/user/ppp/21_all_custom_iface_names.patch
new file mode 100644
index 000000000..5d3f7b94b
--- /dev/null
+++ b/user/ppp/21_all_custom_iface_names.patch
@@ -0,0 +1,144 @@
+pppd: Support arbitrary interface names
+
+This patch implements a new string option "ifname" which allows to specify
+fully custom PPP interface names on Linux. It does so by renaming the
+allocated pppX device immediately after it has been created to the requested
+interface name.
+
+Originally written by Suse. Used by openwrt, debian, ubuntu.
+
+Reference:
+
+https://dev.openwrt.org/browser/trunk/package/network/services/ppp/patches/320-custom_iface_names.patch
+
+diff -purN ppp-2.4.7.orig/pppd/main.c ppp-2.4.7/pppd/main.c
+--- ppp-2.4.7.orig/pppd/main.c 2016-08-25 15:52:52.032202044 +0200
++++ ppp-2.4.7/pppd/main.c 2016-08-25 16:22:25.740299940 +0200
+@@ -729,8 +729,11 @@ void
+ set_ifunit(iskey)
+ int iskey;
+ {
+- info("Using interface %s%d", PPP_DRV_NAME, ifunit);
+- slprintf(ifname, sizeof(ifname), "%s%d", PPP_DRV_NAME, ifunit);
++ if (use_ifname[0] == 0)
++ slprintf(ifname, sizeof(ifname), "%s%d", PPP_DRV_NAME, ifunit);
++ else
++ slprintf(ifname, sizeof(ifname), "%s", use_ifname);
++ info("Using interface %s", ifname);
+ script_setenv("IFNAME", ifname, iskey);
+ if (iskey) {
+ create_pidfile(getpid()); /* write pid to file */
+diff -purN ppp-2.4.7.orig/pppd/options.c ppp-2.4.7/pppd/options.c
+--- ppp-2.4.7.orig/pppd/options.c 2016-08-25 15:52:52.191194523 +0200
++++ ppp-2.4.7/pppd/options.c 2016-08-25 16:04:23.335501924 +0200
+@@ -115,6 +115,7 @@ int log_to_fd = 1; /* send log messages
+ bool log_default = 1; /* log_to_fd is default (stdout) */
+ int maxfail = 10; /* max # of unsuccessful connection attempts */
+ char linkname[MAXPATHLEN]; /* logical name for link */
++char use_ifname[IFNAMSIZ]; /* physical name for PPP link */
+ bool tune_kernel; /* may alter kernel settings */
+ int connect_delay = 1000; /* wait this many ms after connect script */
+ int req_unit = -1; /* requested interface unit */
+@@ -274,6 +275,9 @@ option_t general_options[] = {
+ { "linkname", o_string, linkname,
+ "Set logical name for link",
+ OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, MAXPATHLEN },
++ { "ifname", o_string, use_ifname,
++ "Set physical name for PPP interface",
++ OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, IFNAMSIZ },
+
+ { "maxfail", o_int, &maxfail,
+ "Maximum number of unsuccessful connection attempts to allow",
+diff -purN ppp-2.4.7.orig/pppd/pppd.h ppp-2.4.7/pppd/pppd.h
+--- ppp-2.4.7.orig/pppd/pppd.h 2016-08-25 15:52:52.829164346 +0200
++++ ppp-2.4.7/pppd/pppd.h 2016-08-25 16:07:12.024522417 +0200
+@@ -71,6 +71,10 @@
+ #include "eui64.h"
+ #endif
+
++#ifndef IFNAMSIZ
++#define IFNAMSIZ 16
++#endif
++
+ /*
+ * Limits.
+ */
+@@ -319,6 +323,7 @@ extern char *record_file; /* File to rec
+ extern bool sync_serial; /* Device is synchronous serial device */
+ extern int maxfail; /* Max # of unsuccessful connection attempts */
+ extern char linkname[MAXPATHLEN]; /* logical name for link */
++extern char use_ifname[IFNAMSIZ]; /* physical name for PPP interface */
+ extern bool tune_kernel; /* May alter kernel settings as necessary */
+ extern int connect_delay; /* Time to delay after connect script */
+ extern int max_data_rate; /* max bytes/sec through charshunt */
+diff -purN ppp-2.4.7.orig/pppd/sys-linux.c ppp-2.4.7/pppd/sys-linux.c
+--- ppp-2.4.7.orig/pppd/sys-linux.c 2016-08-25 15:52:52.268190881 +0200
++++ ppp-2.4.7/pppd/sys-linux.c 2016-08-25 16:12:13.905242396 +0200
+@@ -172,6 +172,10 @@ struct in6_ifreq {
+ /* We can get an EIO error on an ioctl if the modem has hung up */
+ #define ok_error(num) ((num)==EIO)
+
++#if !defined(PPP_DRV_NAME)
++#define PPP_DRV_NAME "ppp"
++#endif /* !defined(PPP_DRV_NAME) */
++
+ static int tty_disc = N_TTY; /* The TTY discipline */
+ static int ppp_disc = N_PPP; /* The PPP discpline */
+ static int initfdflags = -1; /* Initial file descriptor flags for fd */
+@@ -644,7 +648,8 @@ void generic_disestablish_ppp(int dev_fd
+ */
+ static int make_ppp_unit()
+ {
+- int x, flags;
++ struct ifreq ifr;
++ int x, flags, s;
+
+ if (ppp_dev_fd >= 0) {
+ dbglog("in make_ppp_unit, already had /dev/ppp open?");
+@@ -667,6 +672,30 @@ static int make_ppp_unit()
+ }
+ if (x < 0)
+ error("Couldn't create new ppp unit: %m");
++
++ if (use_ifname[0] != 0) {
++ s = socket(PF_INET, SOCK_DGRAM, 0);
++ if (s < 0)
++ s = socket(PF_PACKET, SOCK_DGRAM, 0);
++ if (s < 0)
++ s = socket(PF_INET6, SOCK_DGRAM, 0);
++ if (s < 0)
++ s = socket(PF_UNIX, SOCK_DGRAM, 0);
++ if (s >= 0) {
++ slprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", PPP_DRV_NAME, ifunit);
++ slprintf(ifr.ifr_newname, sizeof(ifr.ifr_newname), "%s", use_ifname);
++ x = ioctl(s, SIOCSIFNAME, &ifr);
++ close(s);
++ } else {
++ x = s;
++ }
++ if (x < 0) {
++ error("Couldn't rename %s to %s", ifr.ifr_name, ifr.ifr_newname);
++ close(ppp_dev_fd);
++ ppp_dev_fd = -1;
++ }
++ }
++
+ return x;
+ }
+
+diff -purN ppp-2.4.7.orig/pppstats/pppstats.c ppp-2.4.7/pppstats/pppstats.c
+--- ppp-2.4.7.orig/pppstats/pppstats.c 2014-08-09 14:31:39.000000000 +0200
++++ ppp-2.4.7/pppstats/pppstats.c 2016-08-25 16:13:52.623572634 +0200
+@@ -506,10 +506,12 @@ main(argc, argv)
+ if (argc > 0)
+ interface = argv[0];
+
++#if 0
+ if (sscanf(interface, PPP_DRV_NAME "%d", &unit) != 1) {
+ fprintf(stderr, "%s: invalid interface '%s' specified\n",
+ progname, interface);
+ }
++#endif
+
+ #ifndef STREAMS
+ {
diff --git a/user/ppp/24_all_passwordfd-read-early.patch b/user/ppp/24_all_passwordfd-read-early.patch
new file mode 100644
index 000000000..f549540dc
--- /dev/null
+++ b/user/ppp/24_all_passwordfd-read-early.patch
@@ -0,0 +1,84 @@
+--- ppp-2.4.5/pppd/plugins/passwordfd.c
++++ ppp-2.4.5/pppd/plugins/passwordfd.c
+@@ -16,11 +16,11 @@
+
+ char pppd_version[] = VERSION;
+
+-static int passwdfd = -1;
+ static char save_passwd[MAXSECRETLEN];
+
++static int readpassword __P((char **));
+ static option_t options[] = {
+- { "passwordfd", o_int, &passwdfd,
++ { "passwordfd", o_special, (void *)readpassword,
+ "Receive password on this file descriptor" },
+ { NULL }
+ };
+@@ -30,43 +30,39 @@
+ return 1;
+ }
+
+-static int pwfd_passwd (char *user, char *passwd)
++static int readpassword(char **argv)
+ {
+- int readgood, red;
+-
+- if (passwdfd == -1)
+- return -1;
+-
+- if (passwd == NULL)
+- return 1;
+-
+- if (passwdfd == -2) {
+- strcpy (passwd, save_passwd);
+- return 1;
++ char *arg = *argv;
++ int passwdfd = -1;
++ int chunk, len;
++
++ if (sscanf(arg, "%d", &passwdfd) != 1 || passwdfd < 0)
++ {
++ error ("\"%s\" is not a valid file descriptor number", arg);
++ return 0;
+ }
+
+- readgood = 0;
++ len = 0;
+ do {
+- red = read (passwdfd, passwd + readgood, MAXSECRETLEN - 1 - readgood);
+- if (red == 0)
+- break;
+- if (red < 0) {
+- error ("Can't read secret from fd\n");
+- readgood = -1;
++ chunk = read (passwdfd, save_passwd + len, MAXSECRETLEN - 1 - len);
++ if (chunk == 0)
+ break;
++ if (chunk < 0) {
++ error ("Can't read secret from fd %d", passwdfd);
++ return 0;
+ }
+- readgood += red;
+- } while (readgood < MAXSECRETLEN - 1);
+-
++ len += chunk;
++ } while (len < MAXSECRETLEN - 1);
++ save_passwd[len] = 0;
+ close (passwdfd);
+
+- if (readgood < 0)
+- return 0;
+-
+- passwd[readgood] = 0;
+- strcpy (save_passwd, passwd);
+- passwdfd = -2;
++ return 1;
++}
+
++static int pwfd_passwd (char *user, char *passwd)
++{
++ if (passwd != NULL)
++ strcpy (passwd, save_passwd);
+ return 1;
+ }
+
diff --git a/user/ppp/26_all_pppd-usepeerwins.patch b/user/ppp/26_all_pppd-usepeerwins.patch
new file mode 100644
index 000000000..d66fbe0b1
--- /dev/null
+++ b/user/ppp/26_all_pppd-usepeerwins.patch
@@ -0,0 +1,256 @@
+--- ppp-2.4.6/pppd/ipcp.c
++++ ppp-2.4.6/pppd/ipcp.c
+@@ -91,6 +91,7 @@
+ static int default_route_set[NUM_PPP]; /* Have set up a default route */
+ static int proxy_arp_set[NUM_PPP]; /* Have created proxy arp entry */
+ static bool usepeerdns; /* Ask peer for DNS addrs */
++static bool usepeerwins; /* Ask peer for WINS addrs */
+ static int ipcp_is_up; /* have called np_up() */
+ static int ipcp_is_open; /* haven't called np_finished() */
+ static bool ask_for_local; /* request our address from peer */
+@@ -210,6 +211,9 @@
+ { "usepeerdns", o_bool, &usepeerdns,
+ "Ask peer for DNS address(es)", 1 },
+
++ { "usepeerwins", o_bool, &usepeerwins,
++ "Ask peer for WINS address(es)", 1 },
++
+ { "netmask", o_special, (void *)setnetmask,
+ "set netmask", OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, netmask_str },
+
+@@ -703,6 +707,8 @@
+ wo->accept_remote = 1;
+ wo->req_dns1 = usepeerdns; /* Request DNS addresses from the peer */
+ wo->req_dns2 = usepeerdns;
++ wo->req_wins1 = usepeerwins; /* Request WINS addresses from the peer */
++ wo->req_wins2 = usepeerwins;
+ *go = *wo;
+ if (!ask_for_local)
+ go->ouraddr = 0;
+@@ -755,8 +761,8 @@
+ LENCIADDR(go->neg_addr) +
+ LENCIDNS(go->req_dns1) +
+ LENCIDNS(go->req_dns2) +
+- LENCIWINS(go->winsaddr[0]) +
+- LENCIWINS(go->winsaddr[1])) ;
++ LENCIWINS(go->req_wins1) +
++ LENCIWINS(go->req_wins2)) ;
+ }
+
+
+@@ -830,8 +836,8 @@
+ neg = 0; \
+ }
+
+-#define ADDCIWINS(opt, addr) \
+- if (addr) { \
++#define ADDCIWINS(opt, neg, addr) \
++ if (neg) { \
+ if (len >= CILEN_ADDR) { \
+ u_int32_t l; \
+ PUTCHAR(opt, ucp); \
+@@ -840,7 +846,7 @@
+ PUTLONG(l, ucp); \
+ len -= CILEN_ADDR; \
+ } else \
+- addr = 0; \
++ neg = 0; \
+ }
+
+ ADDCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, go->ouraddr,
+@@ -855,9 +861,9 @@
+
+ ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);
+
+- ADDCIWINS(CI_MS_WINS1, go->winsaddr[0]);
++ ADDCIWINS(CI_MS_WINS1, go->req_wins1, go->winsaddr[0]);
+
+- ADDCIWINS(CI_MS_WINS2, go->winsaddr[1]);
++ ADDCIWINS(CI_MS_WINS2, go->req_wins2, go->winsaddr[1]);
+
+ *lenp -= len;
+ }
+@@ -962,8 +968,8 @@
+ goto bad; \
+ }
+
+-#define ACKCIWINS(opt, addr) \
+- if (addr) { \
++#define ACKCIWINS(opt, neg, addr) \
++ if (neg) { \
+ u_int32_t l; \
+ if ((len -= CILEN_ADDR) < 0) \
+ goto bad; \
+@@ -989,9 +995,9 @@
+
+ ACKCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);
+
+- ACKCIWINS(CI_MS_WINS1, go->winsaddr[0]);
++ ACKCIWINS(CI_MS_WINS1, go->req_wins1, go->winsaddr[0]);
+
+- ACKCIWINS(CI_MS_WINS2, go->winsaddr[1]);
++ ACKCIWINS(CI_MS_WINS2, go->req_wins2, go->winsaddr[1]);
+
+ /*
+ * If there are any remaining CIs, then this packet is bad.
+@@ -1026,7 +1032,7 @@
+ u_char cimaxslotindex, cicflag;
+ u_char citype, cilen, *next;
+ u_short cishort;
+- u_int32_t ciaddr1, ciaddr2, l, cidnsaddr;
++ u_int32_t ciaddr1, ciaddr2, l, cidnsaddr, ciwinsaddr;
+ ipcp_options no; /* options we've seen Naks for */
+ ipcp_options try; /* options to request next time */
+
+@@ -1091,6 +1097,19 @@
+ code \
+ }
+
++#define NAKCIWINS(opt, neg, code) \
++ if (go->neg && \
++ ((cilen = p[1]) == CILEN_ADDR) && \
++ len >= cilen && \
++ p[0] == opt) { \
++ len -= cilen; \
++ INCPTR(2, p); \
++ GETLONG(l, p); \
++ ciwinsaddr = htonl(l); \
++ no.neg = 1; \
++ code \
++ }
++
+ /*
+ * Accept the peer's idea of {our,his} address, if different
+ * from our idea, only if the accept_{local,remote} flag is set.
+@@ -1167,6 +1186,22 @@
+ }
+ );
+
++ NAKCIWINS(CI_MS_WINS1, req_wins1,
++ if (treat_as_reject) {
++ try.req_wins1 = 0;
++ } else {
++ try.winsaddr[0] = ciwinsaddr;
++ }
++ );
++
++ NAKCIWINS(CI_MS_WINS2, req_wins2,
++ if (treat_as_reject) {
++ try.req_wins2 = 0;
++ } else {
++ try.winsaddr[1] = ciwinsaddr;
++ }
++ );
++
+ /*
+ * There may be remaining CIs, if the peer is requesting negotiation
+ * on an option that we didn't include in our request packet.
+@@ -1259,7 +1294,6 @@
+ return 0;
+ }
+
+-
+ /*
+ * ipcp_rejci - Reject some of our CIs.
+ * Callback from fsm_rconfnakrej.
+@@ -1357,8 +1391,8 @@
+ try.neg = 0; \
+ }
+
+-#define REJCIWINS(opt, addr) \
+- if (addr && \
++#define REJCIWINS(opt, neg, addr) \
++ if (go->neg && \
+ ((cilen = p[1]) == CILEN_ADDR) && \
+ len >= cilen && \
+ p[0] == opt) { \
+@@ -1370,7 +1404,7 @@
+ /* Check rejected value. */ \
+ if (cilong != addr) \
+ goto bad; \
+- try.winsaddr[opt == CI_MS_WINS2] = 0; \
++ try.neg = 0; \
+ }
+
+ REJCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs,
+@@ -1385,9 +1419,9 @@
+
+ REJCIDNS(CI_MS_DNS2, req_dns2, go->dnsaddr[1]);
+
+- REJCIWINS(CI_MS_WINS1, go->winsaddr[0]);
++ REJCIWINS(CI_MS_WINS1, req_wins1, go->winsaddr[0]);
+
+- REJCIWINS(CI_MS_WINS2, go->winsaddr[1]);
++ REJCIWINS(CI_MS_WINS2, req_wins2, go->winsaddr[1]);
+
+ /*
+ * If there are any remaining CIs, then this packet is bad.
+@@ -1581,7 +1615,7 @@
+ /* Microsoft primary or secondary WINS request */
+ d = citype == CI_MS_WINS2;
+
+- /* If we do not have a DNS address then we cannot send it */
++ /* If we do not have a WINS address then we cannot send it */
+ if (ao->winsaddr[d] == 0 ||
+ cilen != CILEN_ADDR) { /* Check CI length */
+ orc = CONFREJ; /* Reject CI */
+@@ -1830,6 +1864,13 @@
+ create_resolv(go->dnsaddr[0], go->dnsaddr[1]);
+ }
+
++ if (go->winsaddr[0])
++ script_setenv("WINS1", ip_ntoa(go->winsaddr[0]), 0);
++ if (go->winsaddr[1])
++ script_setenv("WINS2", ip_ntoa(go->winsaddr[1]), 0);
++ if (usepeerwins && (go->winsaddr[0] || go->winsaddr[1]))
++ script_setenv("USEPEERWINS", "1", 0);
++
+ /*
+ * Check that the peer is allowed to use the IP address it wants.
+ */
+--- ppp-2.4.6/pppd/ipcp.h
++++ ppp-2.4.6/pppd/ipcp.h
+@@ -77,6 +77,8 @@
+ bool accept_remote; /* accept peer's value for hisaddr */
+ bool req_dns1; /* Ask peer to send primary DNS address? */
+ bool req_dns2; /* Ask peer to send secondary DNS address? */
++ bool req_wins1; /* Ask peer to send primary WINS address? */
++ bool req_wins2; /* Ask peer to send secondary WINS address? */
+ int vj_protocol; /* protocol value to use in VJ option */
+ int maxslotindex; /* values for RFC1332 VJ compression neg. */
+ bool cflag;
+--- ppp-2.4.6/pppd/pppd.8
++++ ppp-2.4.6/pppd/pppd.8
+@@ -1102,6 +1102,16 @@
+ /etc/ppp/resolv.conf file containing one or two nameserver lines with
+ the address(es) supplied by the peer.
+ .TP
++.B usepeerwins
++Ask the peer for up to 2 WINS server addresses. The addresses supplied
++by the peer (if any) are passed to the /etc/ppp/ip\-up script in the
++environment variables WINS1 and WINS2, and the environment variable
++USEPEERWINS will be set to 1.
++.LP
++Please note that some modems (like the Huawei E220) requires this option in
++order to avoid a race condition that results in the incorrect DNS servers
++being assigned.
++.TP
+ .B user \fIname
+ Sets the name used for authenticating the local system to the peer to
+ \fIname\fR.
+@@ -1650,6 +1660,15 @@
+ If the peer supplies DNS server addresses, this variable is set to the
+ second DNS server address supplied (whether or not the usepeerdns
+ option was given).
++.TP
++.B WINS1
++If the peer supplies WINS server addresses, this variable is set to the
++first WINS server address supplied.
++.TP
++.B WINS2
++If the peer supplies WINS server addresses, this variable is set to the
++second WINS server address supplied.
++.P
+ .P
+ Pppd invokes the following scripts, if they exist. It is not an error
+ if they don't exist.
diff --git a/user/ppp/28_all_connect-errors.patch b/user/ppp/28_all_connect-errors.patch
new file mode 100644
index 000000000..b87acef5d
--- /dev/null
+++ b/user/ppp/28_all_connect-errors.patch
@@ -0,0 +1,11 @@
+--- ppp-2.4.5/pppd/pathnames.h
++++ ppp-2.4.5/pppd/pathnames.h
+@@ -29,7 +29,7 @@
+ #define _PATH_AUTHDOWN _ROOT_PATH "/etc/ppp/auth-down"
+ #define _PATH_AUTHFAIL _ROOT_PATH "/etc/ppp/auth-fail"
+ #define _PATH_TTYOPT _ROOT_PATH "/etc/ppp/options."
+-#define _PATH_CONNERRS _ROOT_PATH "/etc/ppp/connect-errors"
++#define _PATH_CONNERRS _ROOT_PATH "/var/log/ppp-connect-errors"
+ #define _PATH_PEERFILES _ROOT_PATH "/etc/ppp/peers/"
+ #define _PATH_RESOLV _ROOT_PATH "/etc/ppp/resolv.conf"
+
diff --git a/user/ppp/30_all_Makefile.patch b/user/ppp/30_all_Makefile.patch
new file mode 100644
index 000000000..165fc7b22
--- /dev/null
+++ b/user/ppp/30_all_Makefile.patch
@@ -0,0 +1,37 @@
+Ensure that the build process aborts if there is an error in one of
+the plugin subdirectories.
+
+2010-09-01 Martin von Gagern
+
+References:
+http://bugs.gentoo.org/334727
+
+Index: ppp-2.4.5/pppd/plugins/Makefile.linux
+===================================================================
+--- ppp-2.4.5/pppd/plugins/Makefile.linux
++++ ppp-2.4.5/pppd/plugins/Makefile.linux
+@@ -20,7 +20,7 @@ include .depend
+ endif
+
+ all: $(PLUGINS)
+- for d in $(SUBDIRS); do $(MAKE) $(MFLAGS) -C $$d all; done
++ for d in $(SUBDIRS); do $(MAKE) $(MFLAGS) -C $$d all || exit $?; done
+
+ %.so: %.c
+ $(CC) -o $@ $(LDFLAGS) $(CFLAGS) $^
+@@ -30,12 +30,12 @@ VERSION = $(shell awk -F '"' '/VERSION/
+ install: $(PLUGINS)
+ $(INSTALL) -d $(LIBDIR)
+ $(INSTALL) $? $(LIBDIR)
+- for d in $(SUBDIRS); do $(MAKE) $(MFLAGS) -C $$d install; done
++ for d in $(SUBDIRS); do $(MAKE) $(MFLAGS) -C $$d install || exit $?; done
+
+ clean:
+ rm -f *.o *.so *.a
+- for d in $(SUBDIRS); do $(MAKE) $(MFLAGS) -C $$d clean; done
++ for d in $(SUBDIRS); do $(MAKE) $(MFLAGS) -C $$d clean || exit $?; done
+
+ depend:
+ $(CPP) -M $(CFLAGS) *.c >.depend
+- for d in $(SUBDIRS); do $(MAKE) $(MFLAGS) -C $$d depend; done
++ for d in $(SUBDIRS); do $(MAKE) $(MFLAGS) -C $$d depend || exit $?; done
diff --git a/user/ppp/32_all_pado-timeout.patch b/user/ppp/32_all_pado-timeout.patch
new file mode 100644
index 000000000..72f1adbb1
--- /dev/null
+++ b/user/ppp/32_all_pado-timeout.patch
@@ -0,0 +1,254 @@
+--- ppp-2.4.6/pppd/plugins/rp-pppoe/discovery.c
++++ ppp-2.4.6/pppd/plugins/rp-pppoe/discovery.c
+@@ -39,6 +39,7 @@
+ #endif
+
+ #include <signal.h>
++#include <time.h>
+
+ /* Calculate time remaining until *exp, return 0 if now >= *exp */
+ static int time_left(struct timeval *diff, struct timeval *exp)
+@@ -251,6 +252,80 @@
+ }
+
+ /***********************************************************************
++*%FUNCTION: recvPacketForMe
++*%ARGUMENTS:
++* packet -- output parameter
++* len -- output parameter length
++* conn -- connection
++* start -- operation startup timestamp
++* timeout -- how long to wait (in seconds)
++*%RETURNS:
++* -1: error
++* 0: timed out
++* 1: packet received
++*%DESCRIPTION:
++* receive and filter junk packets
++***********************************************************************/
++
++static int
++recvPacketForMe(PPPoEPacket *packet, int *len, PPPoEConnection *conn, time_t start, int timeout)
++{
++ fd_set readable;
++ int r;
++ struct timeval tv;
++ time_t now;
++ int time_remain;
++
++ do {
++ time(&now);
++ time_remain = timeout - (int)difftime(now, start);
++ if (time_remain <= 0) return 0; /* Timed out */
++
++ if (BPF_BUFFER_IS_EMPTY) {
++ tv.tv_sec = time_remain;
++ tv.tv_usec = 0;
++
++ FD_ZERO(&readable);
++ FD_SET(conn->discoverySocket, &readable);
++
++ r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
++ if (r < 0)
++ {
++ if (errno == EINTR)
++ {
++ continue; /* interrupted, so retry */
++ }else
++ {
++ error("pppoe: recvPacketForMe: select: %m");
++ return -1;
++ }
++ }
++
++ if (r == 0) return 0; /* Timed out */
++ }
++
++ /* Get the packet */
++ receivePacket(conn->discoverySocket, packet, len);
++
++ /* Check length */
++ if (ntohs(packet->length) + HDR_SIZE > *len) {
++ error("Bogus PPPoE length field (%u)",
++ (unsigned int) ntohs(packet->length));
++ continue;
++ }
++
++#ifdef USE_BPF
++ /* If it's not a Discovery packet, loop again */
++ if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
++#endif
++ /* If it's not for us, loop again */
++ }while ( ! packetIsForMe(conn, packet));
++
++ return 1;
++}
++
++
++/***********************************************************************
+ *%FUNCTION: sendPADI
+ *%ARGUMENTS:
+ * conn -- PPPoEConnection structure
+@@ -344,13 +419,12 @@
+ void
+ waitForPADO(PPPoEConnection *conn, int timeout)
+ {
+- fd_set readable;
+ int r;
+- struct timeval tv;
+ struct timeval expire_at;
+
+ PPPoEPacket packet;
+ int len;
++ time_t start;
+
+ struct PacketCriteria pc;
+ pc.conn = conn;
+@@ -367,43 +441,10 @@
+ }
+ expire_at.tv_sec += timeout;
+
++ time(&start);
+ do {
+- if (BPF_BUFFER_IS_EMPTY) {
+- if (!time_left(&tv, &expire_at))
+- return; /* Timed out */
+-
+- FD_ZERO(&readable);
+- FD_SET(conn->discoverySocket, &readable);
+-
+- while(1) {
+- r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
+- if (r >= 0 || errno != EINTR) break;
+- }
+- if (r < 0) {
+- error("select (waitForPADO): %m");
+- return;
+- }
+- if (r == 0)
+- return; /* Timed out */
+- }
+-
+- /* Get the packet */
+- receivePacket(conn->discoverySocket, &packet, &len);
+-
+- /* Check length */
+- if (ntohs(packet.length) + HDR_SIZE > len) {
+- error("Bogus PPPoE length field (%u)",
+- (unsigned int) ntohs(packet.length));
+- continue;
+- }
+-
+-#ifdef USE_BPF
+- /* If it's not a Discovery packet, loop again */
+- if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
+-#endif
+-
+- /* If it's not for us, loop again */
+- if (!packetIsForMe(conn, &packet)) continue;
++ r = recvPacketForMe(&packet, &len, conn, start, timeout);
++ if (r<=0) return; /* Timed out or error */
+
+ if (packet.code == CODE_PADO) {
+ if (NOT_UNICAST(packet.ethHdr.h_source)) {
+@@ -537,13 +578,12 @@
+ static void
+ waitForPADS(PPPoEConnection *conn, int timeout)
+ {
+- fd_set readable;
+ int r;
+- struct timeval tv;
+ struct timeval expire_at;
+
+ PPPoEPacket packet;
+ int len;
++ time_t start;
+
+ if (gettimeofday(&expire_at, NULL) < 0) {
+ error("gettimeofday (waitForPADS): %m");
+@@ -551,48 +591,15 @@
+ }
+ expire_at.tv_sec += timeout;
+
++ time(&start);
+ conn->error = 0;
+ do {
+- if (BPF_BUFFER_IS_EMPTY) {
+- if (!time_left(&tv, &expire_at))
+- return; /* Timed out */
+-
+- FD_ZERO(&readable);
+- FD_SET(conn->discoverySocket, &readable);
+-
+- while(1) {
+- r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
+- if (r >= 0 || errno != EINTR) break;
+- }
+- if (r < 0) {
+- error("select (waitForPADS): %m");
+- return;
+- }
+- if (r == 0)
+- return; /* Timed out */
+- }
+-
+- /* Get the packet */
+- receivePacket(conn->discoverySocket, &packet, &len);
+-
+- /* Check length */
+- if (ntohs(packet.length) + HDR_SIZE > len) {
+- error("Bogus PPPoE length field (%u)",
+- (unsigned int) ntohs(packet.length));
+- continue;
+- }
+-
+-#ifdef USE_BPF
+- /* If it's not a Discovery packet, loop again */
+- if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
+-#endif
++ r = recvPacketForMe(&packet, &len, conn, start, timeout);
++ if (r<=0) return; /* Timed out or error */
+
+ /* If it's not from the AC, it's not for me */
+ if (memcmp(packet.ethHdr.h_source, conn->peerEth, ETH_ALEN)) continue;
+
+- /* If it's not for us, loop again */
+- if (!packetIsForMe(conn, &packet)) continue;
+-
+ /* Is it PADS? */
+ if (packet.code == CODE_PADS) {
+ /* Parse for goodies */
+--- ppp-2.4.6/pppd/plugins/rp-pppoe/pppoe-discovery.c
++++ ppp-2.4.6/pppd/plugins/rp-pppoe/pppoe-discovery.c
+@@ -14,6 +14,7 @@
+ #include <unistd.h>
+ #include <errno.h>
+ #include <string.h>
++#include <time.h>
+
+ #include "pppoe.h"
+
+@@ -513,6 +514,8 @@
+ struct timeval tv;
+ PPPoEPacket packet;
+ int len;
++ time_t start, now;
++ int time_remain;
+
+ struct PacketCriteria pc;
+ pc.conn = conn;
+@@ -522,9 +525,13 @@
+ pc.seenServiceName = 0;
+ conn->error = 0;
+
++ time(&start);
+ do {
++ time(&now);
++ time_remain = timeout - (int)difftime(now, start);
++ if (time_remain <= 0) return; /* Timed out */
+ if (BPF_BUFFER_IS_EMPTY) {
+- tv.tv_sec = timeout;
++ tv.tv_sec = time_remain;
+ tv.tv_usec = 0;
+
+ FD_ZERO(&readable);
diff --git a/user/ppp/34_all_lcp-echo-adaptive.patch b/user/ppp/34_all_lcp-echo-adaptive.patch
new file mode 100644
index 000000000..6faf19a27
--- /dev/null
+++ b/user/ppp/34_all_lcp-echo-adaptive.patch
@@ -0,0 +1,56 @@
+--- ppp-2.4.5/pppd/lcp.c
++++ ppp-2.4.5/pppd/lcp.c
+@@ -73,6 +73,7 @@
+ */
+ int lcp_echo_interval = 0; /* Interval between LCP echo-requests */
+ int lcp_echo_fails = 0; /* Tolerance to unanswered echo-requests */
++bool lcp_echo_adaptive = 0; /* request echo only if the link was idle */
+ bool lax_recv = 0; /* accept control chars in asyncmap */
+ bool noendpoint = 0; /* don't send/accept endpoint discriminator */
+
+@@ -151,6 +152,8 @@
+ OPT_PRIO },
+ { "lcp-echo-interval", o_int, &lcp_echo_interval,
+ "Set time in seconds between LCP echo requests", OPT_PRIO },
++ { "lcp-echo-adaptive", o_bool, &lcp_echo_adaptive,
++ "Suppress LCP echo requests if traffic was received", 1 },
+ { "lcp-restart", o_int, &lcp_fsm[0].timeouttime,
+ "Set time in seconds between LCP retransmissions", OPT_PRIO },
+ { "lcp-max-terminate", o_int, &lcp_fsm[0].maxtermtransmits,
+@@ -2322,6 +2325,22 @@
+ }
+
+ /*
++ * If adaptive echos have been enabled, only send the echo request if
++ * no traffic was received since the last one.
++ */
++ if (lcp_echo_adaptive) {
++ static unsigned int last_pkts_in = 0;
++
++ update_link_stats(f->unit);
++ link_stats_valid = 0;
++
++ if (link_stats.pkts_in != last_pkts_in) {
++ last_pkts_in = link_stats.pkts_in;
++ return;
++ }
++ }
++
++ /*
+ * Make and send the echo request frame.
+ */
+ if (f->state == OPENED) {
+--- ppp-2.4.5/pppd/pppd.8
++++ ppp-2.4.5/pppd/pppd.8
+@@ -549,6 +549,11 @@
+ dynamic IP address option (i.e. set /proc/sys/net/ipv4/ip_dynaddr to
+ 1) in demand mode if the local address changes.
+ .TP
++.B lcp\-echo\-adaptive
++If this option is used with the \fIlcp\-echo\-failure\fR option then
++pppd will send LCP echo\-request frames only if no traffic was received
++from the peer since the last echo\-request was sent.
++.TP
+ .B lcp\-echo\-failure \fIn
+ If this option is given, pppd will presume the peer to be dead
+ if \fIn\fR LCP echo\-requests are sent without receiving a valid LCP
diff --git a/user/ppp/50_all_linux-headers.patch b/user/ppp/50_all_linux-headers.patch
new file mode 100644
index 000000000..cd2adbead
--- /dev/null
+++ b/user/ppp/50_all_linux-headers.patch
@@ -0,0 +1,28 @@
+the linux headers have started adding shims to not define types or structs
+when C lib headers are active, but in order to work, the C lib headers have
+to be included before the linux headers.
+
+move the netinet/in.h include up above the linux/ includes.
+
+Mike Frysinger <vapier@gentoo.org>
+
+--- a/pppd/plugins/rp-pppoe/pppoe.h
++++ b/pppd/plugins/rp-pppoe/pppoe.h
+@@ -47,6 +47,8 @@
+ #include <sys/socket.h>
+ #endif
+
++#include <netinet/in.h>
++
+ /* Ugly header files on some Linux boxes... */
+ #if defined(HAVE_LINUX_IF_H)
+ #include <linux/if.h>
+@@ -84,8 +86,6 @@ typedef unsigned long UINT32_t;
+ #include <linux/if_ether.h>
+ #endif
+
+-#include <netinet/in.h>
+-
+ #ifdef HAVE_NETINET_IF_ETHER_H
+ #include <sys/types.h>
+
diff --git a/user/ppp/51_all_glibc-2.28.patch b/user/ppp/51_all_glibc-2.28.patch
new file mode 100644
index 000000000..cbb5857a7
--- /dev/null
+++ b/user/ppp/51_all_glibc-2.28.patch
@@ -0,0 +1,110 @@
+From 3c7b86229f7bd2600d74db14b1fe5b3896be3875 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jaroslav=20=C5=A0karvada?= <jskarvad@redhat.com>
+Date: Fri, 6 Apr 2018 14:27:18 +0200
+Subject: [PATCH] pppd: Use openssl for the DES instead of the libcrypt / glibc
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+It seems the latest glibc (in Fedora glibc-2.27.9000-12.fc29) dropped
+libcrypt. The libxcrypt standalone package can be used instead, but
+it dropped the old setkey/encrypt API which ppp uses for DES. There
+is support for using openssl in pppcrypt.c, but it contains typos
+preventing it from compiling and seems to be written for an ancient
+openssl version.
+
+This updates the code to use current openssl.
+
+[paulus@ozlabs.org - wrote the commit description, fixed comment in
+ Makefile.linux.]
+
+Signed-off-by: Jaroslav Škarvada <jskarvad@redhat.com>
+Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
+---
+ pppd/Makefile.linux | 7 ++++---
+ pppd/pppcrypt.c | 18 +++++++++---------
+ 2 files changed, 13 insertions(+), 12 deletions(-)
+
+diff --git a/pppd/Makefile.linux b/pppd/Makefile.linux
+index 36d2b036..8d5ce99d 100644
+--- a/pppd/Makefile.linux
++++ b/pppd/Makefile.linux
+@@ -35,10 +35,10 @@ endif
+ COPTS = -O2 -pipe -Wall -g
+ LIBS =
+
+-# Uncomment the next 2 lines to include support for Microsoft's
++# Uncomment the next line to include support for Microsoft's
+ # MS-CHAP authentication protocol. Also, edit plugins/radius/Makefile.linux.
+ CHAPMS=y
+-USE_CRYPT=y
++#USE_CRYPT=y
+ # Don't use MSLANMAN unless you really know what you're doing.
+ #MSLANMAN=y
+ # Uncomment the next line to include support for MPPE. CHAPMS (above) must
+@@ -137,7 +137,8 @@ endif
+
+ ifdef NEEDDES
+ ifndef USE_CRYPT
+-LIBS += -ldes $(LIBS)
++CFLAGS += -I/usr/include/openssl
++LIBS += -lcrypto
+ else
+ CFLAGS += -DUSE_CRYPT=1
+ endif
+diff --git a/pppd/pppcrypt.c b/pppd/pppcrypt.c
+index 8b85b132..6b35375e 100644
+--- a/pppd/pppcrypt.c
++++ b/pppd/pppcrypt.c
+@@ -64,7 +64,7 @@ u_char *des_key; /* OUT 64 bit DES key with parity bits added */
+ des_key[7] = Get7Bits(key, 49);
+
+ #ifndef USE_CRYPT
+- des_set_odd_parity((des_cblock *)des_key);
++ DES_set_odd_parity((DES_cblock *)des_key);
+ #endif
+ }
+
+@@ -158,25 +158,25 @@ u_char *clear; /* OUT 8 octets */
+ }
+
+ #else /* USE_CRYPT */
+-static des_key_schedule key_schedule;
++static DES_key_schedule key_schedule;
+
+ bool
+ DesSetkey(key)
+ u_char *key;
+ {
+- des_cblock des_key;
++ DES_cblock des_key;
+ MakeKey(key, des_key);
+- des_set_key(&des_key, key_schedule);
++ DES_set_key(&des_key, &key_schedule);
+ return (1);
+ }
+
+ bool
+-DesEncrypt(clear, key, cipher)
++DesEncrypt(clear, cipher)
+ u_char *clear; /* IN 8 octets */
+ u_char *cipher; /* OUT 8 octets */
+ {
+- des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher,
+- key_schedule, 1);
++ DES_ecb_encrypt((DES_cblock *)clear, (DES_cblock *)cipher,
++ &key_schedule, 1);
+ return (1);
+ }
+
+@@ -185,8 +185,8 @@ DesDecrypt(cipher, clear)
+ u_char *cipher; /* IN 8 octets */
+ u_char *clear; /* OUT 8 octets */
+ {
+- des_ecb_encrypt((des_cblock *)cipher, (des_cblock *)clear,
+- key_schedule, 0);
++ DES_ecb_encrypt((DES_cblock *)cipher, (DES_cblock *)clear,
++ &key_schedule, 0);
+ return (1);
+ }
+
diff --git a/user/ppp/80_all_eaptls-mppe-1.101a.patch b/user/ppp/80_all_eaptls-mppe-1.101a.patch
new file mode 100644
index 000000000..f22b63a86
--- /dev/null
+++ b/user/ppp/80_all_eaptls-mppe-1.101a.patch
@@ -0,0 +1,3233 @@
+diff -Naur ppp-2.4.7/README.eap-tls ppp-2.4.7-eaptls-mppe-1.101b/README.eap-tls
+--- ppp-2.4.7/README.eap-tls 1970-01-01 01:00:00.000000000 +0100
++++ ppp-2.4.7-eaptls-mppe-1.101b/README.eap-tls 2018-06-02 01:42:04.021165440 +0200
+@@ -0,0 +1,286 @@
++EAP-TLS authentication support for PPP
++======================================
++
++1. Intro
++
++ The Extensible Authentication Protocol (EAP; RFC 3748) is a
++ security protocol that can be used with PPP. It provides a means
++ to plug in multiple optional authentication methods.
++
++ Transport Level Security (TLS; RFC 2246) provides for mutual
++ authentication, integrity-protected ciphersuite negotiation and
++ key exchange between two endpoints. It also provides for optional
++ MPPE encryption.
++
++ EAP-TLS (RFC 2716) incapsulates the TLS messages in EAP packets,
++ allowing TLS mutual authentication to be used as a generic EAP
++ mechanism. It also provides optional encryption using the MPPE
++ protocol.
++
++ This patch provide EAP-TLS support to pppd.
++ This authentication method can be used in both client or server
++ mode.
++
++2. Building
++
++ To build pppd with EAP-TLS support, OpenSSL (http://www.openssl.org)
++ is required. Any version from 0.9.7 should work.
++
++ Configure, compile, and install as usual.
++
++3. Configuration
++
++ On the client side there are two ways to configure EAP-TLS:
++
++ 1. supply the appropriate 'ca', 'cert' and 'key' command-line parameters
++
++ 2. edit the /etc/ppp/eaptls-client file.
++ Insert a line for each system with which you use EAP-TLS.
++ The line is composed of this fields separated by tab:
++
++ - Client name
++ The name used by the client for authentication, can be *
++ - Server name
++ The name of the server, can be *
++ - Client certificate file
++ The file containing the certificate chain for the
++ client in PEM format
++ - Server certificate file
++ If you want to specify the certificate that the
++ server is allowed to use, put the certificate file name.
++ Else put a dash '-'.
++ - CA certificate file
++ The file containing the trusted CA certificates in PEM
++ format.
++ - Client private key file
++ The file containing the client private key in PEM format.
++
++
++ On the server side edit the /etc/ppp/eaptls-server file.
++ Insert a line for each system with which you use EAP-TLS.
++ The line is composed of this fields separated by tab:
++
++ - Client name
++ The name used by the client for authentication, can be *
++ - Server name
++ The name of the server, can be *
++ - Client certificate file
++ If you want to specify the certificate that the
++ client is allowed to use, put the certificate file name.
++ Else put a dash '-'.
++ - Server certificate file
++ The file containing the certificate chain for the
++ server in PEM format
++ - CA certificate file
++ The file containing the trusted CA certificates in PEM format.
++ - Client private key file
++ The file containing the server private key in PEM format.
++ - addresses
++ A list of IP addresses the client is allowed to use.
++
++
++ OpenSSL engine support is included starting with v0.95 of this patch.
++ Currently the only engine tested is the 'pkcs11' engine (hardware token
++ support). To use the 'pksc11' engine:
++ - Use a special private key fileiname in the /etc/ppp/eaptls-client file:
++ <engine>:<identifier>
++ e.g.
++ pkcs11:123456
++
++ - The certificate can also be loaded from the 'pkcs11' engine using
++ a special client certificate filename in the /etc/ppp/eaptls-client file:
++ <engine>:<identifier>
++ e.g.
++ pkcs11:123456
++
++ - Create an /etc/ppp/openssl.cnf file to load the right OpenSSL engine prior
++ to starting 'pppd'. A sample openssl.cnf file is
++
++ openssl_conf = openssl_def
++
++ [ openssl_def ]
++ engines = engine_section
++
++ [ engine_section ]
++ pkcs11 = pkcs11_section
++
++ [ pkcs11_section ]
++ engine_id = pkcs11
++ dynamic_path = /usr/lib64/openssl/engines/engine_pkcs11.so
++ MODULE_PATH = /usr/lib64/libeTPkcs11.so
++ init = 0
++
++ - There are two ways to specify a password/PIN for the PKCS11 engine:
++ - inside the openssl.cnf file using
++ PIN = your-secret-pin
++ Note The keyword 'PIN' is case sensitive!
++ - Using the 'password' in the ppp options file.
++ From v0.97 of the eap-tls patch the password can also be supplied
++ using the appropriate 'eaptls_passwd_hook' (see plugins/passprompt.c
++ for an example).
++
++
++4. Options
++
++ These pppd options are available:
++
++ ca <ca-file>
++ Use the CA public certificate found in <ca-file> in PEM format
++ cert <cert-file>
++ Use the client public certificate found in <cert-file> in PEM format
++ or in engine:engine_id format
++ key <key-file>
++ Use the client private key found in <key-file> in PEM format
++ or in engine:engine_id format
++ crl <crl-file>
++ Use the Certificate Revocation List (CRL) file <crl-file> in PEM format.
++ crl-dir <dir>
++ Use CRL files from directory <dir>. It contains CRL files in PEM
++ format and each file contains a CRL. The files are looked up
++ by the issuer name hash value. Use the c_rehash utility
++ to create necessary links.
++ need-peer-eap
++ If the peer doesn't ask us to authenticate or doesn't use eap
++ to authenticate us, disconnect.
++
++ Note:
++ password-encrypted certificates can be used as of v0.94 of this
++ patch. The password for the eap-tls.key file is specified using
++ the regular
++ password ....
++ statement in the ppp options file, or by using the appropriate
++ plugin which supplies a 'eaptls_passwd_hook' routine.
++
++5. Connecting
++
++ If you're setting up a pppd server, edit the EAP-TLS configuration file
++ as written above and then run pppd with the 'auth' option to authenticate
++ the client. The EAP-TLS method will be used if the other eap methods can't
++ be used (no secrets).
++
++ If you're setting up a client, edit the configuration file and then run
++ pppd with 'remotename' option to specify the server name. Add the
++ 'need-peer-eap' option if you want to be sure the peer ask you to
++ authenticate (and to use eap) and to disconnect if it doesn't.
++
++6. Example
++
++ The following example can be used to connect a Linux client with the 'pptp'
++ package to a Linux server running the 'pptpd' (PoPToP) package. The server
++ was configured with a certificate with name (CN) 'pptp-server', the client
++ was configured with a certificate with name (CN) 'pptp-client', both
++ signed by the same Certificate Authority (CA).
++
++ Server side:
++ - /etc/pptpd.conf file:
++ option /etc/ppp/options-pptpd-eaptls
++ localip 172.16.1.1
++ remoteip 172.16.1.10-20
++ - /etc/ppp/options-pptpd-eaptls file:
++ name pptp-server
++ lock
++ mtu 1500
++ mru 1450
++ auth
++ lcp-echo-failure 3
++ lcp-echo-interval 5
++ nodeflate
++ nobsdcomp
++ nopredictor1
++ nopcomp
++ noaccomp
++
++ require-eap
++ require-mppe-128
++
++ crl /home/janjust/ppp/keys/crl.pem
++
++ debug
++ logfile /tmp/pppd.log
++
++ - /etc/ppp/eaptls-server file:
++ * pptp-server - /etc/ppp/pptp-server.crt /etc/ppp/ca.crt /etc/ppp/pptp-server.key *
++
++ - On the server, run
++ pptdp --conf /etc/pptpd.conf
++
++ Client side:
++ - Run
++ pppd noauth require-eap require-mppe-128 \
++ ipcp-accept-local ipcp-accept-remote noipdefault \
++ cert /etc/ppp/keys/pptp-client.crt \
++ key /etc/ppp/keys/pptp-client.key \
++ ca /etc/ppp/keys/ca.crt \
++ name pptp-client remotename pptp-server \
++ debug logfile /tmp/pppd.log
++ pty "pptp pptp-server.example.com --nolaunchpppd"
++
++ Check /var/log/messages and the files /tmp/pppd.log on both sides for debugging info.
++
++7. Notes
++
++ This is experimental code.
++ Send suggestions and comments to Jan Just Keijser <janjust@nikhef.nl>
++
++8. Changelog of ppp-<>-eaptls-mppe-* patches
++
++v0.7 (22-Nov-2005)
++ - First version of the patch to include MPPE support
++ - ppp-2.4.3 only
++v0.9 (25-Jul-2006)
++ - Bug fixes
++ - First version for ppp-2.4.4
++v0.91 (03-Sep-2006)
++ - Added missing #include for md5.h
++ - Last version for ppp-2.4.3
++v0.92 (22-Apr-2008)
++ - Fix for openssl 0.9.8 issue with md5 function overload.
++v0.93 (14-Aug-2008)
++ - Make sure 'noauth' option can be used to bypass server certificate verification.
++v0.94 (15-Oct-2008)
++ - Added support for password-protected private keys by (ab)using the 'password' field.
++v0.95 (23-Dec-2009)
++ - First version with OpenSSL engine support.
++v0.96 (27-Jan-2010)
++ - Added fully functional support for OpenSSL engines (PKCS#11)
++ - First version for ppp-2.4.5
++v0.97 (20-Apr-2010)
++ - Some bug fixes for v0.96
++ - Added support for entering the password via a plugin. The sample plugin
++ .../pppd/plugins/passprompt.c has been extended with EAP-TLS support.
++ The "old" methods using the password option or the /etc/ppp/openssl.cnf file still work.
++ - Added support for specifying the client CA, certificate and private key on the command-line
++ or via the ppp config file.
++v0.98 (20-Apr-2010)
++ - Fix initialisation bug when using ca/cert/key command-line options.
++ - Last version for ppp-2.4.4
++v0.99 (05-Oct-2010)
++ - Fix coredump when using multilink option.
++v0.991 (08-Aug-2011)
++ - Fix compilation issue with openssl 1.0.
++v0.992 (01-Dec-2011)
++ - Fix compilation issue with eaptls_check_hook and passwordfd plugin.
++v0.993 (24-Apr-2012)
++ - Fix compilation issue when EAP_TLS=n in pppd/Makefile.
++v0.994 (11-Jun-2012)
++ - Fix compilation issue on Ubuntu 11.10.
++v0.995 (27-May-2014)
++ - Add support for a CRL file using the command-line option 'crl'
++ (prior only 'crl-dir' was supported).
++ - Fix segfault when pkcs11 enginename was not specified correctly.
++ - Fix segfault when client was misconfigured.
++ - Disable SSL Session Ticket support as Windows 8 does not support this.
++v0.996 (28-May-2014)
++ - Fix minor bug where SessionTicket message was printed as 'Unknown SSL3 code 4'
++ - Add EAP-TLS-specific options to pppd.8 manual page.
++ - Updated README.eap-tls file with new options and provide an example.
++v0.997 (19-Jun-2014)
++ - Change SSL_OP_NO_TICKETS to SSL_OP_NO_TICKET
++ - Fix bug in initialisation code with fragmented packets.
++v0.998 (13-Mar-2015)
++ - Added fix for https://bugzilla.redhat.com/show_bug.cgi?id=1023620
++v0.999 (11-May-2017)
++ - Added support for OpenSSL 1.1: the code will now compile against OpenSSL 1.0.x or 1.1.x.
++v1.101 (1-Jun-2018)
++ - Fix vulnerabilities CVE-2018-11574.
++
+diff -Naur ppp-2.4.7/etc.ppp/eaptls-client ppp-2.4.7-eaptls-mppe-1.101b/etc.ppp/eaptls-client
+--- ppp-2.4.7/etc.ppp/eaptls-client 1970-01-01 01:00:00.000000000 +0100
++++ ppp-2.4.7-eaptls-mppe-1.101b/etc.ppp/eaptls-client 2018-06-02 01:42:04.021165440 +0200
+@@ -0,0 +1,10 @@
++# Parameters for authentication using EAP-TLS (client)
++
++# client name (can be *)
++# server name (can be *)
++# client certificate file (required)
++# server certificate file (optional, if unused put '-')
++# CA certificate file (required)
++# client private key file (required)
++
++#client server /root/cert/client.crt - /root/cert/ca.crt /root/cert/client.key
+diff -Naur ppp-2.4.7/etc.ppp/eaptls-server ppp-2.4.7-eaptls-mppe-1.101b/etc.ppp/eaptls-server
+--- ppp-2.4.7/etc.ppp/eaptls-server 1970-01-01 01:00:00.000000000 +0100
++++ ppp-2.4.7-eaptls-mppe-1.101b/etc.ppp/eaptls-server 2018-06-02 01:42:04.021165440 +0200
+@@ -0,0 +1,11 @@
++# Parameters for authentication using EAP-TLS (server)
++
++# client name (can be *)
++# server name (can be *)
++# client certificate file (optional, if unused put '-')
++# server certificate file (required)
++# CA certificate file (required)
++# server private key file (required)
++# allowed addresses (required, can be *)
++
++#client server - /root/cert/server.crt /root/cert/ca.crt /root/cert/server.key 192.168.1.0/24
+diff -Naur ppp-2.4.7/etc.ppp/openssl.cnf ppp-2.4.7-eaptls-mppe-1.101b/etc.ppp/openssl.cnf
+--- ppp-2.4.7/etc.ppp/openssl.cnf 1970-01-01 01:00:00.000000000 +0100
++++ ppp-2.4.7-eaptls-mppe-1.101b/etc.ppp/openssl.cnf 2018-06-02 01:42:04.021165440 +0200
+@@ -0,0 +1,14 @@
++openssl_conf = openssl_def
++
++[ openssl_def ]
++engines = engine_section
++
++[ engine_section ]
++pkcs11 = pkcs11_section
++
++[ pkcs11_section ]
++engine_id = pkcs11
++dynamic_path = /usr/lib64/openssl/engines/engine_pkcs11.so
++MODULE_PATH = /usr/lib64/libeTPkcs11.so
++init = 0
++
+diff -Naur ppp-2.4.7/linux/Makefile.top ppp-2.4.7-eaptls-mppe-1.101b/linux/Makefile.top
+--- ppp-2.4.7/linux/Makefile.top 2014-08-09 14:31:39.000000000 +0200
++++ ppp-2.4.7-eaptls-mppe-1.101b/linux/Makefile.top 2018-06-02 01:42:04.021165440 +0200
+@@ -26,7 +26,7 @@
+ cd pppdump; $(MAKE) $(MFLAGS) install
+
+ install-etcppp: $(ETCDIR) $(ETCDIR)/options $(ETCDIR)/pap-secrets \
+- $(ETCDIR)/chap-secrets
++ $(ETCDIR)/chap-secrets $(ETCDIR)/eaptls-server $(ETCDIR)/eaptls-client
+
+ install-devel:
+ cd pppd; $(MAKE) $(MFLAGS) install-devel
+@@ -37,6 +37,10 @@
+ $(INSTALL) -c -m 600 etc.ppp/pap-secrets $@
+ $(ETCDIR)/chap-secrets:
+ $(INSTALL) -c -m 600 etc.ppp/chap-secrets $@
++$(ETCDIR)/eaptls-server:
++ $(INSTALL) -c -m 600 etc.ppp/eaptls-server $@
++$(ETCDIR)/eaptls-client:
++ $(INSTALL) -c -m 600 etc.ppp/eaptls-client $@
+
+ $(BINDIR):
+ $(INSTALL) -d -m 755 $@
+diff -Naur ppp-2.4.7/pppd/Makefile.linux ppp-2.4.7-eaptls-mppe-1.101b/pppd/Makefile.linux
+--- ppp-2.4.7/pppd/Makefile.linux 2014-08-09 14:31:39.000000000 +0200
++++ ppp-2.4.7-eaptls-mppe-1.101b/pppd/Makefile.linux 2018-06-02 01:42:04.021165440 +0200
+@@ -76,6 +76,9 @@
+ # Use libutil
+ USE_LIBUTIL=y
+
++# Enable EAP-TLS authentication (requires libssl and libcrypto)
++USE_EAPTLS=y
++
+ MAXOCTETS=y
+
+ INCLUDE_DIRS= -I../include
+@@ -115,6 +118,15 @@
+ PPPDOBJS += sha1.o
+ endif
+
++# EAP-TLS
++ifdef USE_EAPTLS
++CFLAGS += -DUSE_EAPTLS=1 -I/usr/kerberos/include
++LIBS += -lssl -lcrypto
++PPPDSRC += eap-tls.c
++HEADERS += eap-tls.h
++PPPDOBJS += eap-tls.o
++endif
++
+ ifdef HAS_SHADOW
+ CFLAGS += -DHAS_SHADOW
+ #LIBS += -lshadow $(LIBS)
+diff -Naur ppp-2.4.7/pppd/auth.c ppp-2.4.7-eaptls-mppe-1.101b/pppd/auth.c
+--- ppp-2.4.7/pppd/auth.c 2014-08-09 14:31:39.000000000 +0200
++++ ppp-2.4.7-eaptls-mppe-1.101b/pppd/auth.c 2018-06-02 01:42:04.022165436 +0200
+@@ -109,6 +109,9 @@
+ #include "upap.h"
+ #include "chap-new.h"
+ #include "eap.h"
++#ifdef USE_EAPTLS
++#include "eap-tls.h"
++#endif
+ #ifdef CBCP_SUPPORT
+ #include "cbcp.h"
+ #endif
+@@ -183,6 +186,11 @@
+ /* Hook for a plugin to get the CHAP password for authenticating us */
+ int (*chap_passwd_hook) __P((char *user, char *passwd)) = NULL;
+
++#ifdef USE_EAPTLS
++/* Hook for a plugin to get the EAP-TLS password for authenticating us */
++int (*eaptls_passwd_hook) __P((char *user, char *passwd)) = NULL;
++#endif
++
+ /* Hook for a plugin to say whether it is OK if the peer
+ refuses to authenticate. */
+ int (*null_auth_hook) __P((struct wordlist **paddrs,
+@@ -238,6 +246,14 @@
+ bool explicit_user = 0; /* Set if "user" option supplied */
+ bool explicit_passwd = 0; /* Set if "password" option supplied */
+ char remote_name[MAXNAMELEN]; /* Peer's name for authentication */
++#ifdef USE_EAPTLS
++char *cacert_file = NULL; /* CA certificate file (pem format) */
++char *cert_file = NULL; /* client certificate file (pem format) */
++char *privkey_file = NULL; /* client private key file (pem format) */
++char *crl_dir = NULL; /* directory containing CRL files */
++char *crl_file = NULL; /* Certificate Revocation List (CRL) file (pem format) */
++bool need_peer_eap = 0; /* Require peer to authenticate us */
++#endif
+
+ static char *uafname; /* name of most recent +ua file */
+
+@@ -254,6 +270,19 @@
+ static int have_chap_secret __P((char *, char *, int, int *));
+ static int have_srp_secret __P((char *client, char *server, int need_ip,
+ int *lacks_ipp));
++
++#ifdef USE_EAPTLS
++static int have_eaptls_secret_server
++__P((char *client, char *server, int need_ip, int *lacks_ipp));
++static int have_eaptls_secret_client __P((char *client, char *server));
++static int scan_authfile_eaptls __P((FILE * f, char *client, char *server,
++ char *cli_cert, char *serv_cert,
++ char *ca_cert, char *pk,
++ struct wordlist ** addrs,
++ struct wordlist ** opts,
++ char *filename, int flags));
++#endif
++
+ static int ip_addr_check __P((u_int32_t, struct permitted_ip *));
+ static int scan_authfile __P((FILE *, char *, char *, char *,
+ struct wordlist **, struct wordlist **,
+@@ -401,6 +430,15 @@
+ "Set telephone number(s) which are allowed to connect",
+ OPT_PRIV | OPT_A2LIST },
+
++#ifdef USE_EAPTLS
++ { "ca", o_string, &cacert_file, "EAP-TLS CA certificate in PEM format" },
++ { "cert", o_string, &cert_file, "EAP-TLS client certificate in PEM format" },
++ { "key", o_string, &privkey_file, "EAP-TLS client private key in PEM format" },
++ { "crl-dir", o_string, &crl_dir, "Use CRLs in directory" },
++ { "crl", o_string, &crl_file, "Use specific CRL file" },
++ { "need-peer-eap", o_bool, &need_peer_eap,
++ "Require the peer to authenticate us", 1 },
++#endif /* USE_EAPTLS */
+ { NULL }
+ };
+
+@@ -730,6 +768,9 @@
+ lcp_options *wo = &lcp_wantoptions[unit];
+ lcp_options *go = &lcp_gotoptions[unit];
+ lcp_options *ho = &lcp_hisoptions[unit];
++#ifdef USE_EAPTLS
++ lcp_options *ao = &lcp_allowoptions[unit];
++#endif
+ int i;
+ struct protent *protp;
+
+@@ -764,6 +805,22 @@
+ }
+ }
+
++#ifdef USE_EAPTLS
++ if (need_peer_eap && !ao->neg_eap) {
++ warn("eap required to authenticate us but no suitable secrets");
++ lcp_close(unit, "couldn't negotiate eap");
++ status = EXIT_AUTH_TOPEER_FAILED;
++ return;
++ }
++
++ if (need_peer_eap && !ho->neg_eap) {
++ warn("peer doesn't want to authenticate us with eap");
++ lcp_close(unit, "couldn't negotiate eap");
++ status = EXIT_PEER_AUTH_FAILED;
++ return;
++ }
++#endif
++
+ new_phase(PHASE_AUTHENTICATE);
+ auth = 0;
+ if (go->neg_eap) {
+@@ -1277,6 +1334,15 @@
+ our_name, 1, &lacks_ip);
+ }
+
++#ifdef USE_EAPTLS
++ if (!can_auth && wo->neg_eap) {
++ can_auth =
++ have_eaptls_secret_server((explicit_remote ? remote_name :
++ NULL), our_name, 1, &lacks_ip);
++
++ }
++#endif
++
+ if (auth_required && !can_auth && noauth_addrs == NULL) {
+ if (default_auth) {
+ option_error(
+@@ -1331,7 +1397,11 @@
+ passwd[0] != 0 ||
+ (hadchap == 1 || (hadchap == -1 && have_chap_secret(user,
+ (explicit_remote? remote_name: NULL), 0, NULL))) ||
+- have_srp_secret(user, (explicit_remote? remote_name: NULL), 0, NULL));
++ have_srp_secret(user, (explicit_remote? remote_name: NULL), 0, NULL)
++#ifdef USE_EAPTLS
++ || have_eaptls_secret_client(user, (explicit_remote? remote_name: NULL))
++#endif
++ );
+
+ hadchap = -1;
+ if (go->neg_upap && !uselogin && !have_pap_secret(NULL))
+@@ -1346,8 +1416,14 @@
+ !have_chap_secret((explicit_remote? remote_name: NULL), our_name,
+ 1, NULL))) &&
+ !have_srp_secret((explicit_remote? remote_name: NULL), our_name, 1,
+- NULL))
++ NULL)
++#ifdef USE_EAPTLS
++ && !have_eaptls_secret_server((explicit_remote? remote_name: NULL),
++ our_name, 1, NULL)
++#endif
++ )
+ go->neg_eap = 0;
++
+ }
+
+
+@@ -1707,6 +1783,7 @@
+ }
+
+
++
+ /*
+ * get_secret - open the CHAP secret file and return the secret
+ * for authenticating the given client on the given server.
+@@ -2359,3 +2436,335 @@
+
+ auth_script_pid = run_program(script, argv, 0, auth_script_done, NULL, 0);
+ }
++
++
++#ifdef USE_EAPTLS
++static int
++have_eaptls_secret_server(client, server, need_ip, lacks_ipp)
++ char *client;
++ char *server;
++ int need_ip;
++ int *lacks_ipp;
++{
++ FILE *f;
++ int ret;
++ char *filename;
++ struct wordlist *addrs;
++ char servcertfile[MAXWORDLEN];
++ char clicertfile[MAXWORDLEN];
++ char cacertfile[MAXWORDLEN];
++ char pkfile[MAXWORDLEN];
++
++ filename = _PATH_EAPTLSSERVFILE;
++ f = fopen(filename, "r");
++ if (f == NULL)
++ return 0;
++
++ if (client != NULL && client[0] == 0)
++ client = NULL;
++ else if (server != NULL && server[0] == 0)
++ server = NULL;
++
++ ret =
++ scan_authfile_eaptls(f, client, server, clicertfile, servcertfile,
++ cacertfile, pkfile, &addrs, NULL, filename,
++ 0);
++
++ fclose(f);
++
++/*
++ if (ret >= 0 && !eaptls_init_ssl(1, cacertfile, servcertfile,
++ clicertfile, pkfile))
++ ret = -1;
++*/
++
++ if (ret >= 0 && need_ip && !some_ip_ok(addrs)) {
++ if (lacks_ipp != 0)
++ *lacks_ipp = 1;
++ ret = -1;
++ }
++ if (addrs != 0)
++ free_wordlist(addrs);
++
++ return ret >= 0;
++}
++
++
++static int
++have_eaptls_secret_client(client, server)
++ char *client;
++ char *server;
++{
++ FILE *f;
++ int ret;
++ char *filename;
++ struct wordlist *addrs = NULL;
++ char servcertfile[MAXWORDLEN];
++ char clicertfile[MAXWORDLEN];
++ char cacertfile[MAXWORDLEN];
++ char pkfile[MAXWORDLEN];
++
++ if (client != NULL && client[0] == 0)
++ client = NULL;
++ else if (server != NULL && server[0] == 0)
++ server = NULL;
++
++ if (cacert_file && cert_file && privkey_file)
++ return 1;
++
++ filename = _PATH_EAPTLSCLIFILE;
++ f = fopen(filename, "r");
++ if (f == NULL)
++ return 0;
++
++ ret =
++ scan_authfile_eaptls(f, client, server, clicertfile, servcertfile,
++ cacertfile, pkfile, &addrs, NULL, filename,
++ 0);
++ fclose(f);
++
++/*
++ if (ret >= 0 && !eaptls_init_ssl(0, cacertfile, clicertfile,
++ servcertfile, pkfile))
++ ret = -1;
++*/
++
++ if (addrs != 0)
++ free_wordlist(addrs);
++
++ return ret >= 0;
++}
++
++
++static int
++scan_authfile_eaptls(f, client, server, cli_cert, serv_cert, ca_cert, pk,
++ addrs, opts, filename, flags)
++ FILE *f;
++ char *client;
++ char *server;
++ char *cli_cert;
++ char *serv_cert;
++ char *ca_cert;
++ char *pk;
++ struct wordlist **addrs;
++ struct wordlist **opts;
++ char *filename;
++ int flags;
++{
++ int newline;
++ int got_flag, best_flag;
++ struct wordlist *ap, *addr_list, *alist, **app;
++ char word[MAXWORDLEN];
++
++ if (addrs != NULL)
++ *addrs = NULL;
++ if (opts != NULL)
++ *opts = NULL;
++ addr_list = NULL;
++ if (!getword(f, word, &newline, filename))
++ return -1; /* file is empty??? */
++ newline = 1;
++ best_flag = -1;
++ for (;;) {
++ /*
++ * Skip until we find a word at the start of a line.
++ */
++ while (!newline && getword(f, word, &newline, filename));
++ if (!newline)
++ break; /* got to end of file */
++
++ /*
++ * Got a client - check if it's a match or a wildcard.
++ */
++ got_flag = 0;
++ if (client != NULL && strcmp(word, client) != 0 && !ISWILD(word)) {
++ newline = 0;
++ continue;
++ }
++ if (!ISWILD(word))
++ got_flag = NONWILD_CLIENT;
++
++ /*
++ * Now get a server and check if it matches.
++ */
++ if (!getword(f, word, &newline, filename))
++ break;
++ if (newline)
++ continue;
++ if (!ISWILD(word)) {
++ if (server != NULL && strcmp(word, server) != 0)
++ continue;
++ got_flag |= NONWILD_SERVER;
++ }
++
++ /*
++ * Got some sort of a match - see if it's better than what
++ * we have already.
++ */
++ if (got_flag <= best_flag)
++ continue;
++
++ /*
++ * Get the cli_cert
++ */
++ if (!getword(f, word, &newline, filename))
++ break;
++ if (newline)
++ continue;
++ if (strcmp(word, "-") != 0) {
++ strlcpy(cli_cert, word, MAXWORDLEN);
++ } else
++ cli_cert[0] = 0;
++
++ /*
++ * Get serv_cert
++ */
++ if (!getword(f, word, &newline, filename))
++ break;
++ if (newline)
++ continue;
++ if (strcmp(word, "-") != 0) {
++ strlcpy(serv_cert, word, MAXWORDLEN);
++ } else
++ serv_cert[0] = 0;
++
++ /*
++ * Get ca_cert
++ */
++ if (!getword(f, word, &newline, filename))
++ break;
++ if (newline)
++ continue;
++ strlcpy(ca_cert, word, MAXWORDLEN);
++
++ /*
++ * Get pk
++ */
++ if (!getword(f, word, &newline, filename))
++ break;
++ if (newline)
++ continue;
++ strlcpy(pk, word, MAXWORDLEN);
++
++
++ /*
++ * Now read address authorization info and make a wordlist.
++ */
++ app = &alist;
++ for (;;) {
++ if (!getword(f, word, &newline, filename) || newline)
++ break;
++ ap = (struct wordlist *)
++ malloc(sizeof(struct wordlist) + strlen(word) + 1);
++ if (ap == NULL)
++ novm("authorized addresses");
++ ap->word = (char *) (ap + 1);
++ strcpy(ap->word, word);
++ *app = ap;
++ app = &ap->next;
++ }
++ *app = NULL;
++ /*
++ * This is the best so far; remember it.
++ */
++ best_flag = got_flag;
++ if (addr_list)
++ free_wordlist(addr_list);
++ addr_list = alist;
++
++ if (!newline)
++ break;
++ }
++
++ /* scan for a -- word indicating the start of options */
++ for (app = &addr_list; (ap = *app) != NULL; app = &ap->next)
++ if (strcmp(ap->word, "--") == 0)
++ break;
++ /* ap = start of options */
++ if (ap != NULL) {
++ ap = ap->next; /* first option */
++ free(*app); /* free the "--" word */
++ *app = NULL; /* terminate addr list */
++ }
++ if (opts != NULL)
++ *opts = ap;
++ else if (ap != NULL)
++ free_wordlist(ap);
++ if (addrs != NULL)
++ *addrs = addr_list;
++ else if (addr_list != NULL)
++ free_wordlist(addr_list);
++
++ return best_flag;
++}
++
++
++int
++get_eaptls_secret(unit, client, server, clicertfile, servcertfile,
++ cacertfile, pkfile, am_server)
++ int unit;
++ char *client;
++ char *server;
++ char *clicertfile;
++ char *servcertfile;
++ char *cacertfile;
++ char *pkfile;
++ int am_server;
++{
++ FILE *fp;
++ int ret;
++ char *filename = NULL;
++ struct wordlist *addrs = NULL;
++ struct wordlist *opts = NULL;
++
++ /* in client mode the ca+cert+privkey can also be specified as options */
++ if (!am_server && cacert_file && cert_file && privkey_file )
++ {
++ strlcpy( clicertfile, cert_file, MAXWORDLEN );
++ strlcpy( cacertfile, cacert_file, MAXWORDLEN );
++ strlcpy( pkfile, privkey_file, MAXWORDLEN );
++ servcertfile[0] = '\0';
++ }
++ else
++ {
++ filename = (am_server ? _PATH_EAPTLSSERVFILE : _PATH_EAPTLSCLIFILE);
++ addrs = NULL;
++
++ fp = fopen(filename, "r");
++ if (fp == NULL)
++ {
++ error("Can't open eap-tls secret file %s: %m", filename);
++ return 0;
++ }
++
++ check_access(fp, filename);
++
++ ret = scan_authfile_eaptls(fp, client, server, clicertfile, servcertfile,
++ cacertfile, pkfile, &addrs, &opts, filename, 0);
++
++ fclose(fp);
++
++ if (ret < 0) return 0;
++ }
++
++ if (eaptls_passwd_hook)
++ {
++ dbglog( "Calling eaptls password hook" );
++ if ( (*eaptls_passwd_hook)(pkfile, passwd) < 0)
++ {
++ error("Unable to obtain EAP-TLS password for %s (%s) from plugin",
++ client, pkfile);
++ return 0;
++ }
++ }
++ if (am_server)
++ set_allowed_addrs(unit, addrs, opts);
++ else if (opts != NULL)
++ free_wordlist(opts);
++ if (addrs != NULL)
++ free_wordlist(addrs);
++
++ return 1;
++}
++#endif
++
+diff -Naur ppp-2.4.7/pppd/ccp.c ppp-2.4.7-eaptls-mppe-1.101b/pppd/ccp.c
+--- ppp-2.4.7/pppd/ccp.c 2014-08-09 14:31:39.000000000 +0200
++++ ppp-2.4.7-eaptls-mppe-1.101b/pppd/ccp.c 2018-06-02 01:42:04.022165436 +0200
+@@ -540,6 +540,9 @@
+ if (go->mppe) {
+ ccp_options *ao = &ccp_allowoptions[f->unit];
+ int auth_mschap_bits = auth_done[f->unit];
++#ifdef USE_EAPTLS
++ int auth_eap_bits = auth_done[f->unit];
++#endif
+ int numbits;
+
+ /*
+@@ -567,8 +570,23 @@
+ lcp_close(f->unit, "MPPE required but not available");
+ return;
+ }
++
++#ifdef USE_EAPTLS
++ /*
++ * MPPE is also possible in combination with EAP-TLS.
++ * It is not possible to detect if we're doing EAP or EAP-TLS
++ * at this stage, hence we accept all forms of EAP. If TLS is
++ * not used then the MPPE keys will not be derived anyway.
++ */
++ /* Leave only the eap auth bits set */
++ auth_eap_bits &= (EAP_WITHPEER | EAP_PEER );
++
++ if ((numbits == 0) && (auth_eap_bits == 0)) {
++ error("MPPE required, but MS-CHAP[v2] nor EAP-TLS auth are performed.");
++#else
+ if (!numbits) {
+- error("MPPE required, but MS-CHAP[v2] auth not performed.");
++ error("MPPE required, but MS-CHAP[v2] auth not performed.");
++#endif
+ lcp_close(f->unit, "MPPE required but not available");
+ return;
+ }
+diff -Naur ppp-2.4.7/pppd/chap-md5.c ppp-2.4.7-eaptls-mppe-1.101b/pppd/chap-md5.c
+--- ppp-2.4.7/pppd/chap-md5.c 2014-08-09 14:31:39.000000000 +0200
++++ ppp-2.4.7-eaptls-mppe-1.101b/pppd/chap-md5.c 2018-06-02 01:42:04.022165436 +0200
+@@ -36,7 +36,11 @@
+ #include "chap-new.h"
+ #include "chap-md5.h"
+ #include "magic.h"
++#ifdef USE_EAPTLS
++#include "eap-tls.h"
++#else
+ #include "md5.h"
++#endif /* USE_EAPTLS */
+
+ #define MD5_HASH_SIZE 16
+ #define MD5_MIN_CHALLENGE 16
+diff -Naur ppp-2.4.7/pppd/eap-tls.c ppp-2.4.7-eaptls-mppe-1.101b/pppd/eap-tls.c
+--- ppp-2.4.7/pppd/eap-tls.c 1970-01-01 01:00:00.000000000 +0100
++++ ppp-2.4.7-eaptls-mppe-1.101b/pppd/eap-tls.c 2018-06-02 01:42:16.790124406 +0200
+@@ -0,0 +1,1313 @@
++/*
++ * eap-tls.c - EAP-TLS implementation for PPP
++ *
++ * Copyright (c) Beniamino Galvani 2005 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.
++ *
++ * 3. The name(s) of the authors of this software must not be used to
++ * endorse or promote products derived from this software without
++ * prior written permission.
++ *
++ * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
++ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
++ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
++ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
++ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ *
++ */
++
++#include <string.h>
++#include <unistd.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++
++#include <openssl/conf.h>
++#include <openssl/engine.h>
++#include <openssl/hmac.h>
++#include <openssl/err.h>
++#include <openssl/x509v3.h>
++
++#include "pppd.h"
++#include "eap.h"
++#include "eap-tls.h"
++#include "fsm.h"
++#include "lcp.h"
++#include "pathnames.h"
++
++/* The openssl configuration file and engines can be loaded only once */
++static CONF *ssl_config = NULL;
++static ENGINE *cert_engine = NULL;
++static ENGINE *pkey_engine = NULL;
++
++#ifdef MPPE
++
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
++
++/*
++ * https://wiki.openssl.org/index.php/1.1_API_Changes
++ * tries to provide some guidance but ultimately falls short.
++ */
++
++
++static void HMAC_CTX_free(HMAC_CTX *ctx)
++{
++ if (ctx != NULL) {
++ HMAC_CTX_cleanup(ctx);
++ OPENSSL_free(ctx);
++ }
++}
++
++static HMAC_CTX *HMAC_CTX_new(void)
++{
++ HMAC_CTX *ctx = OPENSSL_malloc(sizeof(*ctx));
++ if (ctx != NULL)
++ HMAC_CTX_init(ctx);
++ return ctx;
++}
++
++/*
++ * These were basically jacked directly from the OpenSSL tree
++ * without adjustments.
++ */
++
++static size_t SSL_get_client_random(const SSL *ssl, unsigned char *out,
++ size_t outlen)
++{
++ if (outlen == 0)
++ return sizeof(ssl->s3->client_random);
++ if (outlen > sizeof(ssl->s3->client_random))
++ outlen = sizeof(ssl->s3->client_random);
++ memcpy(out, ssl->s3->client_random, outlen);
++ return outlen;
++}
++
++static size_t SSL_get_server_random(const SSL *ssl, unsigned char *out,
++ size_t outlen)
++{
++ if (outlen == 0)
++ return sizeof(ssl->s3->server_random);
++ if (outlen > sizeof(ssl->s3->server_random))
++ outlen = sizeof(ssl->s3->server_random);
++ memcpy(out, ssl->s3->server_random, outlen);
++ return outlen;
++}
++
++static size_t SSL_SESSION_get_master_key(const SSL_SESSION *session,
++ unsigned char *out, size_t outlen)
++{
++ if (outlen == 0)
++ return session->master_key_length;
++ if (outlen > session->master_key_length)
++ outlen = session->master_key_length;
++ memcpy(out, session->master_key, outlen);
++ return outlen;
++}
++
++/* Avoid a deprecated warning in OpenSSL 1.1 whilst still allowing to build against 1.0.x */
++#define TLS_method TLSv1_method
++
++#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
++
++/*
++ * TLS PRF from RFC 2246
++ */
++static void P_hash(const EVP_MD *evp_md,
++ const unsigned char *secret, unsigned int secret_len,
++ const unsigned char *seed, unsigned int seed_len,
++ unsigned char *out, unsigned int out_len)
++{
++ HMAC_CTX *ctx_a, *ctx_out;
++ unsigned char a[HMAC_MAX_MD_CBLOCK];
++ unsigned int size;
++
++ ctx_a = HMAC_CTX_new();
++ ctx_out = HMAC_CTX_new();
++ HMAC_Init_ex(ctx_a, secret, secret_len, evp_md, NULL);
++ HMAC_Init_ex(ctx_out, secret, secret_len, evp_md, NULL);
++
++ size = HMAC_size(ctx_out);
++
++ /* Calculate A(1) */
++ HMAC_Update(ctx_a, seed, seed_len);
++ HMAC_Final(ctx_a, a, NULL);
++
++ while (1) {
++ /* Calculate next part of output */
++ HMAC_Update(ctx_out, a, size);
++ HMAC_Update(ctx_out, seed, seed_len);
++
++ /* Check if last part */
++ if (out_len < size) {
++ HMAC_Final(ctx_out, a, NULL);
++ memcpy(out, a, out_len);
++ break;
++ }
++
++ /* Place digest in output buffer */
++ HMAC_Final(ctx_out, out, NULL);
++ HMAC_Init_ex(ctx_out, NULL, 0, NULL, NULL);
++ out += size;
++ out_len -= size;
++
++ /* Calculate next A(i) */
++ HMAC_Init_ex(ctx_a, NULL, 0, NULL, NULL);
++ HMAC_Update(ctx_a, a, size);
++ HMAC_Final(ctx_a, a, NULL);
++ }
++
++ HMAC_CTX_free(ctx_a);
++ HMAC_CTX_free(ctx_out);
++ memset(a, 0, sizeof(a));
++}
++
++static void PRF(const unsigned char *secret, unsigned int secret_len,
++ const unsigned char *seed, unsigned int seed_len,
++ unsigned char *out, unsigned char *buf, unsigned int out_len)
++{
++ unsigned int i;
++ unsigned int len = (secret_len + 1) / 2;
++ const unsigned char *s1 = secret;
++ const unsigned char *s2 = secret + (secret_len - len);
++
++ P_hash(EVP_md5(), s1, len, seed, seed_len, out, out_len);
++ P_hash(EVP_sha1(), s2, len, seed, seed_len, buf, out_len);
++
++ for (i=0; i < out_len; i++) {
++ out[i] ^= buf[i];
++ }
++}
++
++#define EAPTLS_MPPE_KEY_LEN 32
++
++/*
++ * Generate keys according to RFC 2716 and add to reply
++ */
++void eaptls_gen_mppe_keys(struct eaptls_session *ets, const char *prf_label,
++ int client)
++{
++ unsigned char out[4*EAPTLS_MPPE_KEY_LEN], buf[4*EAPTLS_MPPE_KEY_LEN];
++ unsigned char seed[64 + 2*SSL3_RANDOM_SIZE];
++ unsigned char *p = seed;
++ SSL *s = ets->ssl;
++ size_t prf_size;
++ unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
++ size_t master_key_length;
++
++ prf_size = strlen(prf_label);
++
++ memcpy(p, prf_label, prf_size);
++ p += prf_size;
++
++ prf_size += SSL_get_client_random(s, p, SSL3_RANDOM_SIZE);
++ p += SSL3_RANDOM_SIZE;
++
++ prf_size += SSL_get_server_random(s, p, SSL3_RANDOM_SIZE);
++
++ master_key_length = SSL_SESSION_get_master_key(SSL_get_session(s), master_key,
++ sizeof(master_key));
++ PRF(master_key, master_key_length, seed, prf_size, out, buf, sizeof(out));
++
++ /*
++ * We now have the master send and receive keys.
++ * From these, generate the session send and receive keys.
++ * (see RFC3079 / draft-ietf-pppext-mppe-keys-03.txt for details)
++ */
++ if (client)
++ {
++ p = out;
++ BCOPY( p, mppe_send_key, sizeof(mppe_send_key) );
++ p += EAPTLS_MPPE_KEY_LEN;
++ BCOPY( p, mppe_recv_key, sizeof(mppe_recv_key) );
++ }
++ else
++ {
++ p = out;
++ BCOPY( p, mppe_recv_key, sizeof(mppe_recv_key) );
++ p += EAPTLS_MPPE_KEY_LEN;
++ BCOPY( p, mppe_send_key, sizeof(mppe_send_key) );
++ }
++
++ mppe_keys_set = 1;
++}
++
++#endif
++
++void log_ssl_errors( void )
++{
++ unsigned long ssl_err = ERR_get_error();
++
++ if (ssl_err != 0)
++ dbglog("EAP-TLS SSL error stack:");
++ while (ssl_err != 0) {
++ dbglog( ERR_error_string( ssl_err, NULL ) );
++ ssl_err = ERR_get_error();
++ }
++}
++
++
++int password_callback (char *buf, int size, int rwflag, void *u)
++{
++ if (buf)
++ {
++ strncpy (buf, passwd, size);
++ return strlen (buf);
++ }
++ return 0;
++}
++
++
++CONF *eaptls_ssl_load_config( void )
++{
++ CONF *config;
++ int ret_code;
++ long error_line = 33;
++
++ config = NCONF_new( NULL );
++ dbglog( "Loading OpenSSL config file" );
++ ret_code = NCONF_load( config, _PATH_OPENSSLCONFFILE, &error_line );
++ if (ret_code == 0)
++ {
++ warn( "EAP-TLS: Error in OpenSSL config file %s at line %d", _PATH_OPENSSLCONFFILE, error_line );
++ NCONF_free( config );
++ config = NULL;
++ ERR_clear_error();
++ }
++
++ dbglog( "Loading OpenSSL built-ins" );
++ ENGINE_load_builtin_engines();
++ OPENSSL_load_builtin_modules();
++
++ dbglog( "Loading OpenSSL configured modules" );
++ if (CONF_modules_load( config, NULL, 0 ) <= 0 )
++ {
++ warn( "EAP-TLS: Error loading OpenSSL modules" );
++ log_ssl_errors();
++ config = NULL;
++ }
++
++ return config;
++}
++
++ENGINE *eaptls_ssl_load_engine( char *engine_name )
++{
++ ENGINE *e = NULL;
++
++ dbglog( "Enabling OpenSSL auto engines" );
++ ENGINE_register_all_complete();
++
++ dbglog( "Loading OpenSSL '%s' engine support", engine_name );
++ e = ENGINE_by_id( engine_name );
++ if (!e)
++ {
++ dbglog( "EAP-TLS: Cannot load '%s' engine support, trying 'dynamic'", engine_name );
++ e = ENGINE_by_id( "dynamic" );
++ if (e)
++ {
++ if (!ENGINE_ctrl_cmd_string(e, "SO_PATH", engine_name, 0)
++ || !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0))
++ {
++ warn( "EAP-TLS: Error loading dynamic engine '%s'", engine_name );
++ log_ssl_errors();
++ ENGINE_free(e);
++ e = NULL;
++ }
++ }
++ else
++ {
++ warn( "EAP-TLS: Cannot load dynamic engine support" );
++ }
++ }
++
++ if (e)
++ {
++ dbglog( "Initialising engine" );
++ if(!ENGINE_set_default(e, ENGINE_METHOD_ALL))
++ {
++ warn( "EAP-TLS: Cannot use that engine" );
++ log_ssl_errors();
++ ENGINE_free(e);
++ e = NULL;
++ }
++ }
++
++ return e;
++}
++
++/*
++ * Initialize the SSL stacks and tests if certificates, key and crl
++ * for client or server use can be loaded.
++ */
++SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile,
++ char *certfile, char *peer_certfile, char *privkeyfile)
++{
++ char *cert_engine_name = NULL;
++ char *cert_identifier = NULL;
++ char *pkey_engine_name = NULL;
++ char *pkey_identifier = NULL;
++ SSL_CTX *ctx;
++ X509_STORE *certstore;
++ X509_LOOKUP *lookup;
++ X509 *tmp;
++
++ /*
++ * Without these can't continue
++ */
++ if (!cacertfile[0])
++ {
++ error("EAP-TLS: CA certificate missing");
++ return NULL;
++ }
++
++ if (!certfile[0])
++ {
++ error("EAP-TLS: User certificate missing");
++ return NULL;
++ }
++
++ if (!privkeyfile[0])
++ {
++ error("EAP-TLS: User private key missing");
++ return NULL;
++ }
++
++ SSL_library_init();
++ SSL_load_error_strings();
++
++ ctx = SSL_CTX_new(TLS_method());
++
++ if (!ctx) {
++ error("EAP-TLS: Cannot initialize SSL CTX context");
++ goto fail;
++ }
++
++ /* if the certificate filename is of the form engine:id. e.g.
++ pkcs11:12345
++ then we try to load and use this engine.
++ If the certificate filename starts with a / or . then we
++ ALWAYS assume it is a file and not an engine/pkcs11 identifier
++ */
++ if ( index( certfile, '/' ) == NULL && index( certfile, '.') == NULL )
++ {
++ cert_identifier = index( certfile, ':' );
++
++ if (cert_identifier)
++ {
++ cert_engine_name = certfile;
++ *cert_identifier = '\0';
++ cert_identifier++;
++
++ dbglog( "Found certificate engine '%s'", cert_engine_name );
++ dbglog( "Found certificate identifier '%s'", cert_identifier );
++ }
++ }
++
++ /* if the privatekey filename is of the form engine:id. e.g.
++ pkcs11:12345
++ then we try to load and use this engine.
++ If the privatekey filename starts with a / or . then we
++ ALWAYS assume it is a file and not an engine/pkcs11 identifier
++ */
++ if ( index( privkeyfile, '/' ) == NULL && index( privkeyfile, '.') == NULL )
++ {
++ pkey_identifier = index( privkeyfile, ':' );
++
++ if (pkey_identifier)
++ {
++ pkey_engine_name = privkeyfile;
++ *pkey_identifier = '\0';
++ pkey_identifier++;
++
++ dbglog( "Found privatekey engine '%s'", pkey_engine_name );
++ dbglog( "Found privatekey identifier '%s'", pkey_identifier );
++ }
++ }
++
++ if (cert_identifier && pkey_identifier)
++ {
++ if (strlen( cert_identifier ) == 0)
++ {
++ if (strlen( pkey_identifier ) == 0)
++ error( "EAP-TLS: both the certificate and privatekey identifiers are missing!" );
++ else
++ {
++ dbglog( "Substituting privatekey identifier for certificate identifier" );
++ cert_identifier = pkey_identifier;
++ }
++ }
++ else
++ {
++ if (strlen( pkey_identifier ) == 0)
++ {
++ dbglog( "Substituting certificate identifier for privatekey identifier" );
++ pkey_identifier = cert_identifier;
++ }
++ }
++
++ }
++
++ /* load the openssl config file only once */
++ if (!ssl_config)
++ {
++ if (cert_engine_name || pkey_engine_name)
++ ssl_config = eaptls_ssl_load_config();
++
++ if (ssl_config && cert_engine_name)
++ cert_engine = eaptls_ssl_load_engine( cert_engine_name );
++
++ if (ssl_config && pkey_engine_name)
++ {
++ /* don't load the same engine twice */
++ if ( cert_engine && strcmp( cert_engine_name, pkey_engine_name) == 0 )
++ pkey_engine = cert_engine;
++ else
++ pkey_engine = eaptls_ssl_load_engine( pkey_engine_name );
++ }
++ }
++
++ SSL_CTX_set_default_passwd_cb (ctx, password_callback);
++
++ if (!SSL_CTX_load_verify_locations(ctx, cacertfile, NULL))
++ {
++ error("EAP-TLS: Cannot load or verify CA file %s", cacertfile);
++ goto fail;
++ }
++
++ if (init_server)
++ SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(cacertfile));
++
++ if (cert_engine)
++ {
++ struct
++ {
++ const char *s_slot_cert_id;
++ X509 *cert;
++ } cert_info;
++
++ cert_info.s_slot_cert_id = cert_identifier;
++ cert_info.cert = NULL;
++
++ if (!ENGINE_ctrl_cmd( cert_engine, "LOAD_CERT_CTRL", 0, &cert_info, NULL, 0 ) )
++ {
++ error( "EAP-TLS: Error loading certificate with id '%s' from engine", cert_identifier );
++ goto fail;
++ }
++
++ if (cert_info.cert)
++ {
++ dbglog( "Got the certificate, adding it to SSL context" );
++ dbglog( "subject = %s", X509_NAME_oneline( X509_get_subject_name( cert_info.cert ), NULL, 0 ) );
++ if (SSL_CTX_use_certificate(ctx, cert_info.cert) <= 0)
++ {
++ error("EAP-TLS: Cannot use PKCS11 certificate %s", cert_identifier);
++ goto fail;
++ }
++ }
++ else
++ {
++ warn("EAP-TLS: Cannot load PKCS11 key %s", cert_identifier);
++ log_ssl_errors();
++ }
++ }
++ else
++ {
++ if (!SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM))
++ {
++ error( "EAP-TLS: Cannot use public certificate %s", certfile );
++ goto fail;
++ }
++ }
++
++ if (pkey_engine)
++ {
++ EVP_PKEY *pkey = NULL;
++ PW_CB_DATA cb_data;
++
++ cb_data.password = passwd;
++ cb_data.prompt_info = pkey_identifier;
++
++ dbglog( "Loading private key '%s' from engine", pkey_identifier );
++ pkey = ENGINE_load_private_key(pkey_engine, pkey_identifier, NULL, &cb_data);
++ if (pkey)
++ {
++ dbglog( "Got the private key, adding it to SSL context" );
++ if (SSL_CTX_use_PrivateKey(ctx, pkey) <= 0)
++ {
++ error("EAP-TLS: Cannot use PKCS11 key %s", pkey_identifier);
++ goto fail;
++ }
++ }
++ else
++ {
++ warn("EAP-TLS: Cannot load PKCS11 key %s", pkey_identifier);
++ log_ssl_errors();
++ }
++ }
++ else
++ {
++ if (!SSL_CTX_use_PrivateKey_file(ctx, privkeyfile, SSL_FILETYPE_PEM))
++ {
++ error("EAP-TLS: Cannot use private key %s", privkeyfile);
++ goto fail;
++ }
++ }
++
++ if (SSL_CTX_check_private_key(ctx) != 1) {
++ error("EAP-TLS: Private key %s fails security check", privkeyfile);
++ goto fail;
++ }
++
++ /* Explicitly set the NO_TICKETS flag to support Win7/Win8 clients */
++ SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3
++#ifdef SSL_OP_NO_TICKET
++ | SSL_OP_NO_TICKET
++#endif
++);
++ SSL_CTX_set_verify_depth(ctx, 5);
++ SSL_CTX_set_verify(ctx,
++ SSL_VERIFY_PEER |
++ SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
++ &ssl_verify_callback);
++
++ if (crl_dir) {
++ if (!(certstore = SSL_CTX_get_cert_store(ctx))) {
++ error("EAP-TLS: Failed to get certificate store");
++ goto fail;
++ }
++
++ if (!(lookup =
++ X509_STORE_add_lookup(certstore, X509_LOOKUP_hash_dir()))) {
++ error("EAP-TLS: Store lookup for CRL failed");
++
++ goto fail;
++ }
++
++ X509_LOOKUP_add_dir(lookup, crl_dir, X509_FILETYPE_PEM);
++ X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK);
++ }
++
++ if (crl_file) {
++ FILE *fp = NULL;
++ X509_CRL *crl = NULL;
++
++ fp = fopen(crl_file, "r");
++ if (!fp) {
++ error("EAP-TLS: Cannot open CRL file '%s'", crl_file);
++ goto fail;
++ }
++
++ crl = PEM_read_X509_CRL(fp, NULL, NULL, NULL);
++ if (!crl) {
++ error("EAP-TLS: Cannot read CRL file '%s'", crl_file);
++ goto fail;
++ }
++
++ if (!(certstore = SSL_CTX_get_cert_store(ctx))) {
++ error("EAP-TLS: Failed to get certificate store");
++ goto fail;
++ }
++ if (!X509_STORE_add_crl(certstore, crl)) {
++ error("EAP-TLS: Cannot add CRL to certificate store");
++ goto fail;
++ }
++ X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK);
++
++ }
++
++ /*
++ * If a peer certificate file was specified, it must be valid, else fail
++ */
++ if (peer_certfile[0]) {
++ if (!(tmp = get_X509_from_file(peer_certfile))) {
++ error("EAP-TLS: Error loading client certificate from file %s",
++ peer_certfile);
++ goto fail;
++ }
++ X509_free(tmp);
++ }
++
++ return ctx;
++
++fail:
++ log_ssl_errors();
++ SSL_CTX_free(ctx);
++ return NULL;
++}
++
++/*
++ * Determine the maximum packet size by looking at the LCP handshake
++ */
++
++int eaptls_get_mtu(int unit)
++{
++ int mtu, mru;
++
++ lcp_options *wo = &lcp_wantoptions[unit];
++ lcp_options *go = &lcp_gotoptions[unit];
++ lcp_options *ho = &lcp_hisoptions[unit];
++ lcp_options *ao = &lcp_allowoptions[unit];
++
++ mtu = ho->neg_mru? ho->mru: PPP_MRU;
++ mru = go->neg_mru? MAX(wo->mru, go->mru): PPP_MRU;
++ mtu = MIN(MIN(mtu, mru), ao->mru)- PPP_HDRLEN - 10;
++
++ dbglog("MTU = %d", mtu);
++ return mtu;
++}
++
++
++/*
++ * Init the ssl handshake (server mode)
++ */
++int eaptls_init_ssl_server(eap_state * esp)
++{
++ struct eaptls_session *ets;
++ char servcertfile[MAXWORDLEN];
++ char clicertfile[MAXWORDLEN];
++ char cacertfile[MAXWORDLEN];
++ char pkfile[MAXWORDLEN];
++ /*
++ * Allocate new eaptls session
++ */
++ esp->es_server.ea_session = malloc(sizeof(struct eaptls_session));
++ if (!esp->es_server.ea_session)
++ fatal("Allocation error");
++ ets = esp->es_server.ea_session;
++
++ if (!esp->es_server.ea_peer) {
++ error("EAP-TLS: Error: client name not set (BUG)");
++ return 0;
++ }
++
++ strncpy(ets->peer, esp->es_server.ea_peer, MAXWORDLEN);
++
++ dbglog( "getting eaptls secret" );
++ if (!get_eaptls_secret(esp->es_unit, esp->es_server.ea_peer,
++ esp->es_server.ea_name, clicertfile,
++ servcertfile, cacertfile, pkfile, 1)) {
++ error( "EAP-TLS: Cannot get secret/password for client \"%s\", server \"%s\"",
++ esp->es_server.ea_peer, esp->es_server.ea_name );
++ return 0;
++ }
++
++ ets->mtu = eaptls_get_mtu(esp->es_unit);
++
++ ets->ctx = eaptls_init_ssl(1, cacertfile, servcertfile, clicertfile, pkfile);
++ if (!ets->ctx)
++ goto fail;
++
++ if (!(ets->ssl = SSL_new(ets->ctx)))
++ goto fail;
++
++ /*
++ * Set auto-retry to avoid timeouts on BIO_read
++ */
++ SSL_set_mode(ets->ssl, SSL_MODE_AUTO_RETRY);
++
++ /*
++ * Initialize the BIOs we use to read/write to ssl engine
++ */
++ ets->into_ssl = BIO_new(BIO_s_mem());
++ ets->from_ssl = BIO_new(BIO_s_mem());
++ SSL_set_bio(ets->ssl, ets->into_ssl, ets->from_ssl);
++
++ SSL_set_msg_callback(ets->ssl, ssl_msg_callback);
++ SSL_set_msg_callback_arg(ets->ssl, ets);
++
++ /*
++ * Attach the session struct to the connection, so we can later
++ * retrieve it when doing certificate verification
++ */
++ SSL_set_ex_data(ets->ssl, 0, ets);
++
++ SSL_set_accept_state(ets->ssl);
++
++ ets->data = NULL;
++ ets->datalen = 0;
++ ets->alert_sent = 0;
++ ets->alert_recv = 0;
++
++ /*
++ * If we specified the client certificate file, store it in ets->peercertfile,
++ * so we can check it later in ssl_verify_callback()
++ */
++ if (clicertfile[0])
++ strncpy(&ets->peercertfile[0], clicertfile, MAXWORDLEN);
++ else
++ ets->peercertfile[0] = 0;
++
++ return 1;
++
++fail:
++ SSL_CTX_free(ets->ctx);
++ return 0;
++}
++
++/*
++ * Init the ssl handshake (client mode)
++ */
++int eaptls_init_ssl_client(eap_state * esp)
++{
++ struct eaptls_session *ets;
++ char servcertfile[MAXWORDLEN];
++ char clicertfile[MAXWORDLEN];
++ char cacertfile[MAXWORDLEN];
++ char pkfile[MAXWORDLEN];
++
++ /*
++ * Allocate new eaptls session
++ */
++ esp->es_client.ea_session = malloc(sizeof(struct eaptls_session));
++ if (!esp->es_client.ea_session)
++ fatal("Allocation error");
++ ets = esp->es_client.ea_session;
++
++ /*
++ * If available, copy server name in ets; it will be used in cert
++ * verify
++ */
++ if (esp->es_client.ea_peer)
++ strncpy(ets->peer, esp->es_client.ea_peer, MAXWORDLEN);
++ else
++ ets->peer[0] = 0;
++
++ ets->mtu = eaptls_get_mtu(esp->es_unit);
++
++ dbglog( "calling get_eaptls_secret" );
++ if (!get_eaptls_secret(esp->es_unit, esp->es_client.ea_name,
++ ets->peer, clicertfile,
++ servcertfile, cacertfile, pkfile, 0)) {
++ error( "EAP-TLS: Cannot get secret/password for client \"%s\", server \"%s\"",
++ esp->es_client.ea_name, ets->peer );
++ return 0;
++ }
++
++ dbglog( "calling eaptls_init_ssl" );
++ ets->ctx = eaptls_init_ssl(0, cacertfile, clicertfile, servcertfile, pkfile);
++ if (!ets->ctx)
++ goto fail;
++
++ ets->ssl = SSL_new(ets->ctx);
++
++ if (!ets->ssl)
++ goto fail;
++
++ /*
++ * Initialize the BIOs we use to read/write to ssl engine
++ */
++ dbglog( "Initializing SSL BIOs" );
++ ets->into_ssl = BIO_new(BIO_s_mem());
++ ets->from_ssl = BIO_new(BIO_s_mem());
++ SSL_set_bio(ets->ssl, ets->into_ssl, ets->from_ssl);
++
++ SSL_set_msg_callback(ets->ssl, ssl_msg_callback);
++ SSL_set_msg_callback_arg(ets->ssl, ets);
++
++ /*
++ * Attach the session struct to the connection, so we can later
++ * retrieve it when doing certificate verification
++ */
++ SSL_set_ex_data(ets->ssl, 0, ets);
++
++ SSL_set_connect_state(ets->ssl);
++
++ ets->data = NULL;
++ ets->datalen = 0;
++ ets->alert_sent = 0;
++ ets->alert_recv = 0;
++
++ /*
++ * If we specified the server certificate file, store it in
++ * ets->peercertfile, so we can check it later in
++ * ssl_verify_callback()
++ */
++ if (servcertfile[0])
++ strncpy(ets->peercertfile, servcertfile, MAXWORDLEN);
++ else
++ ets->peercertfile[0] = 0;
++
++ return 1;
++
++fail:
++ dbglog( "eaptls_init_ssl_client: fail" );
++ SSL_CTX_free(ets->ctx);
++ return 0;
++
++}
++
++void eaptls_free_session(struct eaptls_session *ets)
++{
++ if (ets->ssl)
++ SSL_free(ets->ssl);
++
++ if (ets->ctx)
++ SSL_CTX_free(ets->ctx);
++
++ free(ets);
++}
++
++/*
++ * Handle a received packet, reassembling fragmented messages and
++ * passing them to the ssl engine
++ */
++int eaptls_receive(struct eaptls_session *ets, u_char * inp, int len)
++{
++ u_char flags;
++ u_int tlslen = 0;
++ u_char dummy[65536];
++
++ if (len < 1) {
++ warn("EAP-TLS: received no or invalid data");
++ return 1;
++ }
++
++ GETCHAR(flags, inp);
++ len--;
++
++ if (flags & EAP_TLS_FLAGS_LI && len >= 4) {
++ /*
++ * LenghtIncluded flag set -> this is the first packet of a message
++ */
++
++ /*
++ * the first 4 octets are the length of the EAP-TLS message
++ */
++ GETLONG(tlslen, inp);
++ len -= 4;
++
++ if (!ets->data) {
++
++ if (tlslen > EAP_TLS_MAX_LEN) {
++ error("EAP-TLS: TLS message length > %d, truncated", EAP_TLS_MAX_LEN);
++ tlslen = EAP_TLS_MAX_LEN;
++ }
++
++ /*
++ * Allocate memory for the whole message
++ */
++ ets->data = malloc(tlslen);
++ if (!ets->data)
++ fatal("EAP-TLS: allocation error\n");
++
++ ets->datalen = 0;
++ ets->tlslen = tlslen;
++ }
++ else
++ warn("EAP-TLS: non-first LI packet? that's odd...");
++ }
++ else if (!ets->data) {
++ /*
++ * A non fragmented message without LI flag
++ */
++
++ ets->data = malloc(len);
++ if (!ets->data)
++ fatal("EAP-TLS: allocation error\n");
++
++ ets->datalen = 0;
++ ets->tlslen = len;
++ }
++
++ if (flags & EAP_TLS_FLAGS_MF)
++ ets->frag = 1;
++ else
++ ets->frag = 0;
++
++ if (len < 0) {
++ warn("EAP-TLS: received malformed data");
++ return 1;
++ }
++
++ if (len + ets->datalen > ets->tlslen) {
++ warn("EAP-TLS: received data > TLS message length");
++ return 1;
++ }
++
++ BCOPY(inp, ets->data + ets->datalen, len);
++ ets->datalen += len;
++
++ if (!ets->frag) {
++
++ /*
++ * If we have the whole message, pass it to ssl
++ */
++
++ if (ets->datalen != ets->tlslen) {
++ warn("EAP-TLS: received data != TLS message length");
++ return 1;
++ }
++
++ if (BIO_write(ets->into_ssl, ets->data, ets->datalen) == -1)
++ log_ssl_errors();
++
++ SSL_read(ets->ssl, dummy, 65536);
++
++ free(ets->data);
++ ets->data = NULL;
++ ets->datalen = 0;
++ }
++
++ return 0;
++}
++
++/*
++ * Return an eap-tls packet in outp.
++ * A TLS message read from the ssl engine is buffered in ets->data.
++ * At each call we control if there is buffered data and send a
++ * packet of mtu bytes.
++ */
++int eaptls_send(struct eaptls_session *ets, u_char ** outp)
++{
++ bool first = 0;
++ int size;
++ u_char fromtls[65536];
++ int res;
++ u_char *start;
++
++ start = *outp;
++
++ if (!ets->data) {
++
++ if(!ets->alert_sent)
++ SSL_read(ets->ssl, fromtls, 65536);
++
++ /*
++ * Read from ssl
++ */
++ if ((res = BIO_read(ets->from_ssl, fromtls, 65536)) == -1)
++ fatal("No data from BIO_read");
++
++ ets->datalen = res;
++
++ ets->data = malloc(ets->datalen);
++ BCOPY(fromtls, ets->data, ets->datalen);
++
++ ets->offset = 0;
++ first = 1;
++
++ }
++
++ size = ets->datalen - ets->offset;
++
++ if (size > ets->mtu) {
++ size = ets->mtu;
++ ets->frag = 1;
++ } else
++ ets->frag = 0;
++
++ PUTCHAR(EAPT_TLS, *outp);
++
++ /*
++ * Set right flags and length if necessary
++ */
++ if (ets->frag && first) {
++ PUTCHAR(EAP_TLS_FLAGS_LI | EAP_TLS_FLAGS_MF, *outp);
++ PUTLONG(ets->datalen, *outp);
++ } else if (ets->frag) {
++ PUTCHAR(EAP_TLS_FLAGS_MF, *outp);
++ } else
++ PUTCHAR(0, *outp);
++
++ /*
++ * Copy the data in outp
++ */
++ BCOPY(ets->data + ets->offset, *outp, size);
++ INCPTR(size, *outp);
++
++ /*
++ * Copy the packet in retransmission buffer
++ */
++ BCOPY(start, &ets->rtx[0], *outp - start);
++ ets->rtx_len = *outp - start;
++
++ ets->offset += size;
++
++ if (ets->offset >= ets->datalen) {
++
++ /*
++ * The whole message has been sent
++ */
++
++ free(ets->data);
++ ets->data = NULL;
++ ets->datalen = 0;
++ ets->offset = 0;
++ }
++
++ return 0;
++}
++
++/*
++ * Get the sent packet from the retransmission buffer
++ */
++void eaptls_retransmit(struct eaptls_session *ets, u_char ** outp)
++{
++ BCOPY(ets->rtx, *outp, ets->rtx_len);
++ INCPTR(ets->rtx_len, *outp);
++}
++
++/*
++ * Verify a certificate.
++ * Most of the work (signatures and issuer attributes checking)
++ * is done by ssl; we check the CN in the peer certificate
++ * against the peer name.
++ */
++int ssl_verify_callback(int preverify_ok, X509_STORE_CTX * ctx)
++{
++ char subject[256];
++ char cn_str[256];
++ X509 *peer_cert;
++ int err, depth;
++ int ok = preverify_ok;
++ SSL *ssl;
++ struct eaptls_session *ets;
++
++ peer_cert = X509_STORE_CTX_get_current_cert(ctx);
++ err = X509_STORE_CTX_get_error(ctx);
++ depth = X509_STORE_CTX_get_error_depth(ctx);
++
++ dbglog("certificate verify depth: %d", depth);
++
++ if (auth_required && !ok) {
++ X509_NAME_oneline(X509_get_subject_name(peer_cert),
++ subject, 256);
++
++ X509_NAME_get_text_by_NID(X509_get_subject_name(peer_cert),
++ NID_commonName, cn_str, 256);
++
++ dbglog("Certificate verification error:\n depth: %d CN: %s"
++ "\n err: %d (%s)\n", depth, cn_str, err,
++ X509_verify_cert_error_string(err));
++
++ return 0;
++ }
++
++ ssl = X509_STORE_CTX_get_ex_data(ctx,
++ SSL_get_ex_data_X509_STORE_CTX_idx());
++
++ ets = (struct eaptls_session *)SSL_get_ex_data(ssl, 0);
++
++ if (ets == NULL) {
++ error("Error: SSL_get_ex_data returned NULL");
++ return 0;
++ }
++
++ log_ssl_errors();
++
++ if (!depth) { /* This is the peer certificate */
++
++ X509_NAME_oneline(X509_get_subject_name(peer_cert),
++ subject, 256);
++
++ X509_NAME_get_text_by_NID(X509_get_subject_name(peer_cert),
++ NID_commonName, cn_str, 256);
++
++ /*
++ * If acting as client and the name of the server wasn't specified
++ * explicitely, we can't verify the server authenticity
++ */
++ if (!ets->peer[0]) {
++ warn("Peer name not specified: no check");
++ return 1;
++ }
++
++ /*
++ * Check the CN
++ */
++ if (strcmp(cn_str, ets->peer)) {
++ error
++ ("Certificate verification error: CN (%s) != peer_name (%s)",
++ cn_str, ets->peer);
++ return 0;
++ }
++
++ warn("Certificate CN: %s , peer name %s", cn_str, ets->peer);
++
++ /*
++ * If a peer certificate file was specified, here we check it
++ */
++ if (ets->peercertfile[0]) {
++ if (ssl_cmp_certs(&ets->peercertfile[0], peer_cert)
++ != 0) {
++ error
++ ("Peer certificate doesn't match stored certificate");
++ return 0;
++ }
++ }
++ }
++
++ return 1;
++}
++
++/*
++ * Compare a certificate with the one stored in a file
++ */
++int ssl_cmp_certs(char *filename, X509 * a)
++{
++ X509 *b;
++ int ret;
++
++ if (!(b = get_X509_from_file(filename)))
++ return 1;
++
++ ret = X509_cmp(a, b);
++ X509_free(b);
++
++ return ret;
++
++}
++
++X509 *get_X509_from_file(char *filename)
++{
++ FILE *fp;
++ X509 *ret;
++
++ if (!(fp = fopen(filename, "r")))
++ return NULL;
++
++ ret = PEM_read_X509(fp, NULL, NULL, NULL);
++
++ fclose(fp);
++
++ return ret;
++}
++
++/*
++ * Every sent & received message this callback function is invoked,
++ * so we know when alert messages have arrived or are sent and
++ * we can print debug information about TLS handshake.
++ */
++void
++ssl_msg_callback(int write_p, int version, int content_type,
++ const void *buf, size_t len, SSL * ssl, void *arg)
++{
++ char string[256];
++ struct eaptls_session *ets = (struct eaptls_session *)arg;
++ unsigned char code;
++ const unsigned char*msg = buf;
++ int hvers = msg[1] << 8 | msg[2];
++
++ if(write_p)
++ strcpy(string, " -> ");
++ else
++ strcpy(string, " <- ");
++
++ switch(content_type) {
++
++ case SSL3_RT_HEADER:
++ strcat(string, "SSL/TLS Header: ");
++ switch(hvers) {
++ case SSL3_VERSION:
++ strcat(string, "SSL 3.0");
++ break;
++ case TLS1_VERSION:
++ strcat(string, "TLS 1.0");
++ break;
++ case TLS1_1_VERSION:
++ strcat(string, "TLS 1.1");
++ break;
++ case TLS1_2_VERSION:
++ strcat(string, "TLS 1.2");
++ break;
++ case DTLS1_VERSION:
++ strcat(string, "DTLS 1.0");
++ break;
++ case DTLS1_2_VERSION:
++ strcat(string, "DTLS 1.2");
++ break;
++ default:
++ strcat(string, "Unknown version");
++ }
++ break;
++
++ case SSL3_RT_ALERT:
++ strcat(string, "Alert: ");
++ code = msg[1];
++
++ if (write_p) {
++ ets->alert_sent = 1;
++ ets->alert_sent_desc = code;
++ } else {
++ ets->alert_recv = 1;
++ ets->alert_recv_desc = code;
++ }
++
++ strcat(string, SSL_alert_desc_string_long(code));
++ break;
++
++ case SSL3_RT_CHANGE_CIPHER_SPEC:
++ strcat(string, "ChangeCipherSpec");
++ break;
++
++ case SSL3_RT_HANDSHAKE:
++
++ strcat(string, "Handshake: ");
++ code = msg[0];
++
++ switch(code) {
++ case SSL3_MT_HELLO_REQUEST:
++ strcat(string,"Hello Request");
++ break;
++ case SSL3_MT_CLIENT_HELLO:
++ strcat(string,"Client Hello");
++ break;
++ case SSL3_MT_SERVER_HELLO:
++ strcat(string,"Server Hello");
++ break;
++#ifdef SSL3_MT_NEWSESSION_TICKET
++ case SSL3_MT_NEWSESSION_TICKET:
++ strcat(string,"New Session Ticket");
++ break;
++#endif
++ case SSL3_MT_CERTIFICATE:
++ strcat(string,"Certificate");
++ break;
++ case SSL3_MT_SERVER_KEY_EXCHANGE:
++ strcat(string,"Server Key Exchange");
++ break;
++ case SSL3_MT_CERTIFICATE_REQUEST:
++ strcat(string,"Certificate Request");
++ break;
++ case SSL3_MT_SERVER_DONE:
++ strcat(string,"Server Hello Done");
++ break;
++ case SSL3_MT_CERTIFICATE_VERIFY:
++ strcat(string,"Certificate Verify");
++ break;
++ case SSL3_MT_CLIENT_KEY_EXCHANGE:
++ strcat(string,"Client Key Exchange");
++ break;
++ case SSL3_MT_FINISHED:
++ strcat(string,"Finished");
++ break;
++
++ default:
++ sprintf( string, "Handshake: Unknown SSL3 code received: %d", code );
++ }
++ break;
++
++ default:
++ sprintf( string, "SSL message contains unknown content type: %d", content_type );
++
++ }
++
++ /* Alert messages must always be displayed */
++ if(content_type == SSL3_RT_ALERT)
++ error("%s", string);
++ else
++ dbglog("%s", string);
++}
++
+diff -Naur ppp-2.4.7/pppd/eap-tls.h ppp-2.4.7-eaptls-mppe-1.101b/pppd/eap-tls.h
+--- ppp-2.4.7/pppd/eap-tls.h 1970-01-01 01:00:00.000000000 +0100
++++ ppp-2.4.7-eaptls-mppe-1.101b/pppd/eap-tls.h 2018-06-02 01:42:04.023165433 +0200
+@@ -0,0 +1,107 @@
++/*
++ * eap-tls.h
++ *
++ * Copyright (c) Beniamino Galvani 2005 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.
++ *
++ * 3. The name(s) of the authors of this software must not be used to
++ * endorse or promote products derived from this software without
++ * prior written permission.
++ *
++ * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
++ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
++ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
++ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
++ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ *
++ */
++
++#ifndef __EAP_TLS_H__
++#define __EAP_TLS_H__
++
++#include "eap.h"
++
++#include <openssl/ssl.h>
++#include <openssl/bio.h>
++#include <openssl/md5.h>
++
++#define EAP_TLS_FLAGS_LI 128 /* length included flag */
++#define EAP_TLS_FLAGS_MF 64 /* more fragments flag */
++#define EAP_TLS_FLAGS_START 32 /* start flag */
++
++#define EAP_TLS_MAX_LEN 65536 /* max eap tls packet size */
++
++struct eaptls_session
++{
++ u_char *data; /* buffered data */
++ int datalen; /* buffered data len */
++ int offset; /* from where to send */
++ int tlslen; /* total length of tls data */
++ bool frag; /* packet is fragmented */
++ SSL_CTX *ctx;
++ SSL *ssl; /* ssl connection */
++ BIO *from_ssl;
++ BIO *into_ssl;
++ char peer[MAXWORDLEN]; /* peer name */
++ char peercertfile[MAXWORDLEN];
++ bool alert_sent;
++ u_char alert_sent_desc;
++ bool alert_recv;
++ u_char alert_recv_desc;
++ char rtx[65536]; /* retransmission buffer */
++ int rtx_len;
++ int mtu; /* unit mtu */
++};
++
++typedef struct pw_cb_data
++{
++ const void *password;
++ const char *prompt_info;
++} PW_CB_DATA;
++
++
++int ssl_verify_callback(int, X509_STORE_CTX *);
++void ssl_msg_callback(int write_p, int version, int ct, const void *buf,
++ size_t len, SSL * ssl, void *arg);
++
++X509 *get_X509_from_file(char *filename);
++int ssl_cmp_certs(char *filename, X509 * a);
++
++SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile,
++ char *certfile, char *peer_certfile, char *privkeyfile);
++int eaptls_init_ssl_server(eap_state * esp);
++int eaptls_init_ssl_client(eap_state * esp);
++void eaptls_free_session(struct eaptls_session *ets);
++
++int eaptls_receive(struct eaptls_session *ets, u_char * inp, int len);
++int eaptls_send(struct eaptls_session *ets, u_char ** outp);
++void eaptls_retransmit(struct eaptls_session *ets, u_char ** outp);
++
++int get_eaptls_secret(int unit, char *client, char *server,
++ char *clicertfile, char *servcertfile, char *cacertfile,
++ char *pkfile, int am_server);
++
++#ifdef MPPE
++#include "mppe.h" /* MPPE_MAX_KEY_LEN */
++extern u_char mppe_send_key[MPPE_MAX_KEY_LEN];
++extern u_char mppe_recv_key[MPPE_MAX_KEY_LEN];
++extern int mppe_keys_set;
++
++void eaptls_gen_mppe_keys(struct eaptls_session *ets, const char *prf_label, int client);
++
++#endif
++
++#endif
+diff -Naur ppp-2.4.7/pppd/eap.c ppp-2.4.7-eaptls-mppe-1.101b/pppd/eap.c
+--- ppp-2.4.7/pppd/eap.c 2014-08-09 14:31:39.000000000 +0200
++++ ppp-2.4.7-eaptls-mppe-1.101b/pppd/eap.c 2018-06-02 01:42:04.023165433 +0200
+@@ -43,6 +43,11 @@
+ * Based on draft-ietf-pppext-eap-srp-03.txt.
+ */
+
++/*
++ * Modification by Beniamino Galvani, Mar 2005
++ * Implemented EAP-TLS authentication
++ */
++
+ #define RCSID "$Id: eap.c,v 1.4 2004/11/09 22:39:25 paulus Exp $"
+
+ /*
+@@ -62,8 +67,12 @@
+
+ #include "pppd.h"
+ #include "pathnames.h"
+-#include "md5.h"
+ #include "eap.h"
++#ifdef USE_EAPTLS
++#include "eap-tls.h"
++#else
++#include "md5.h"
++#endif /* USE_EAPTLS */
+
+ #ifdef USE_SRP
+ #include <t_pwd.h>
+@@ -209,6 +218,9 @@
+ esp->es_server.ea_id = (u_char)(drand48() * 0x100);
+ esp->es_client.ea_timeout = EAP_DEFREQTIME;
+ esp->es_client.ea_maxrequests = EAP_DEFALLOWREQ;
++#ifdef USE_EAPTLS
++ esp->es_client.ea_using_eaptls = 0;
++#endif /* USE_EAPTLS */
+ }
+
+ /*
+@@ -436,8 +448,16 @@
+ u_char vals[2];
+ struct b64state bs;
+ #endif /* USE_SRP */
++#ifdef USE_EAPTLS
++ struct eaptls_session *ets;
++ int secret_len;
++ char secret[MAXWORDLEN];
++#endif /* USE_EAPTLS */
+
+ esp->es_server.ea_timeout = esp->es_savedtime;
++#ifdef USE_EAPTLS
++ esp->es_server.ea_prev_state = esp->es_server.ea_state;
++#endif /* USE_EAPTLS */
+ switch (esp->es_server.ea_state) {
+ case eapBadAuth:
+ return;
+@@ -562,9 +582,79 @@
+ break;
+ }
+ #endif /* USE_SRP */
++#ifdef USE_EAPTLS
++ if (!get_secret(esp->es_unit, esp->es_server.ea_peer,
++ esp->es_server.ea_name, secret, &secret_len, 1)) {
++
++ esp->es_server.ea_state = eapTlsStart;
++ break;
++ }
++#endif /* USE_EAPTLS */
++
+ esp->es_server.ea_state = eapMD5Chall;
+ break;
+
++#ifdef USE_EAPTLS
++ case eapTlsStart:
++ /* Initialize ssl session */
++ if(!eaptls_init_ssl_server(esp)) {
++ esp->es_server.ea_state = eapBadAuth;
++ break;
++ }
++
++ esp->es_server.ea_state = eapTlsRecv;
++ break;
++
++ case eapTlsRecv:
++ ets = (struct eaptls_session *) esp->es_server.ea_session;
++
++ if(ets->alert_sent) {
++ esp->es_server.ea_state = eapTlsSendAlert;
++ break;
++ }
++
++ if (status) {
++ esp->es_server.ea_state = eapBadAuth;
++ break;
++ }
++ ets = (struct eaptls_session *) esp->es_server.ea_session;
++
++ if(ets->frag)
++ esp->es_server.ea_state = eapTlsSendAck;
++ else
++ esp->es_server.ea_state = eapTlsSend;
++ break;
++
++ case eapTlsSend:
++ ets = (struct eaptls_session *) esp->es_server.ea_session;
++
++ if(ets->frag)
++ esp->es_server.ea_state = eapTlsRecvAck;
++ else
++ if(SSL_is_init_finished(ets->ssl))
++ esp->es_server.ea_state = eapTlsRecvClient;
++ else
++ esp->es_server.ea_state = eapTlsRecv;
++ break;
++
++ case eapTlsSendAck:
++ esp->es_server.ea_state = eapTlsRecv;
++ break;
++
++ case eapTlsRecvAck:
++ if (status) {
++ esp->es_server.ea_state = eapBadAuth;
++ break;
++ }
++
++ esp->es_server.ea_state = eapTlsSend;
++ break;
++
++ case eapTlsSendAlert:
++ esp->es_server.ea_state = eapTlsRecvAlertAck;
++ break;
++#endif /* USE_EAPTLS */
++
+ case eapSRP1:
+ #ifdef USE_SRP
+ ts = (struct t_server *)esp->es_server.ea_session;
+@@ -718,6 +808,30 @@
+ INCPTR(esp->es_server.ea_namelen, outp);
+ break;
+
++#ifdef USE_EAPTLS
++ case eapTlsStart:
++ PUTCHAR(EAPT_TLS, outp);
++ PUTCHAR(EAP_TLS_FLAGS_START, outp);
++ eap_figure_next_state(esp, 0);
++ break;
++
++ case eapTlsSend:
++ eaptls_send(esp->es_server.ea_session, &outp);
++ eap_figure_next_state(esp, 0);
++ break;
++
++ case eapTlsSendAck:
++ PUTCHAR(EAPT_TLS, outp);
++ PUTCHAR(0, outp);
++ eap_figure_next_state(esp, 0);
++ break;
++
++ case eapTlsSendAlert:
++ eaptls_send(esp->es_server.ea_session, &outp);
++ eap_figure_next_state(esp, 0);
++ break;
++#endif /* USE_EAPTLS */
++
+ #ifdef USE_SRP
+ case eapSRP1:
+ PUTCHAR(EAPT_SRP, outp);
+@@ -904,11 +1018,57 @@
+ eap_server_timeout(arg)
+ void *arg;
+ {
++#ifdef USE_EAPTLS
++ u_char *outp;
++ u_char *lenloc;
++ int outlen;
++#endif /* USE_EAPTLS */
++
+ eap_state *esp = (eap_state *) arg;
+
+ if (!eap_server_active(esp))
+ return;
+
++#ifdef USE_EAPTLS
++ switch(esp->es_server.ea_prev_state) {
++
++ /*
++ * In eap-tls the state changes after a request, so we return to
++ * previous state ...
++ */
++ case(eapTlsStart):
++ case(eapTlsSendAck):
++ esp->es_server.ea_state = esp->es_server.ea_prev_state;
++ break;
++
++ /*
++ * ... or resend the stored data
++ */
++ case(eapTlsSend):
++ case(eapTlsSendAlert):
++ outp = outpacket_buf;
++ MAKEHEADER(outp, PPP_EAP);
++ PUTCHAR(EAP_REQUEST, outp);
++ PUTCHAR(esp->es_server.ea_id, outp);
++ lenloc = outp;
++ INCPTR(2, outp);
++
++ eaptls_retransmit(esp->es_server.ea_session, &outp);
++
++ outlen = (outp - outpacket_buf) - PPP_HDRLEN;
++ PUTSHORT(outlen, lenloc);
++ output(esp->es_unit, outpacket_buf, outlen + PPP_HDRLEN);
++ esp->es_server.ea_requests++;
++
++ if (esp->es_server.ea_timeout > 0)
++ TIMEOUT(eap_server_timeout, esp, esp->es_server.ea_timeout);
++
++ return;
++ default:
++ break;
++ }
++#endif /* USE_EAPTLS */
++
+ /* EAP ID number must not change on timeout. */
+ eap_send_request(esp);
+ }
+@@ -1166,6 +1326,81 @@
+ }
+ #endif /* USE_SRP */
+
++#ifdef USE_EAPTLS
++/*
++ * Send an EAP-TLS response message with tls data
++ */
++static void
++eap_tls_response(esp, id)
++eap_state *esp;
++u_char id;
++{
++ u_char *outp;
++ int outlen;
++ u_char *lenloc;
++
++ outp = outpacket_buf;
++
++ MAKEHEADER(outp, PPP_EAP);
++
++ PUTCHAR(EAP_RESPONSE, outp);
++ PUTCHAR(id, outp);
++
++ lenloc = outp;
++ INCPTR(2, outp);
++
++ /*
++ If the id in the request is unchanged, we must retransmit
++ the old data
++ */
++ if(id == esp->es_client.ea_id)
++ eaptls_retransmit(esp->es_client.ea_session, &outp);
++ else
++ eaptls_send(esp->es_client.ea_session, &outp);
++
++ outlen = (outp - outpacket_buf) - PPP_HDRLEN;
++ PUTSHORT(outlen, lenloc);
++
++ output(esp->es_unit, outpacket_buf, PPP_HDRLEN + outlen);
++
++ esp->es_client.ea_id = id;
++
++}
++
++/*
++ * Send an EAP-TLS ack
++ */
++static void
++eap_tls_sendack(esp, id)
++eap_state *esp;
++u_char id;
++{
++ u_char *outp;
++ int outlen;
++ u_char *lenloc;
++
++ outp = outpacket_buf;
++
++ MAKEHEADER(outp, PPP_EAP);
++
++ PUTCHAR(EAP_RESPONSE, outp);
++ PUTCHAR(id, outp);
++ esp->es_client.ea_id = id;
++
++ lenloc = outp;
++ INCPTR(2, outp);
++
++ PUTCHAR(EAPT_TLS, outp);
++ PUTCHAR(0, outp);
++
++ outlen = (outp - outpacket_buf) - PPP_HDRLEN;
++ PUTSHORT(outlen, lenloc);
++
++ output(esp->es_unit, outpacket_buf, PPP_HDRLEN + outlen);
++
++}
++#endif /* USE_EAPTLS */
++
+ static void
+ eap_send_nak(esp, id, type)
+ eap_state *esp;
+@@ -1320,6 +1555,11 @@
+ char rhostname[256];
+ MD5_CTX mdContext;
+ u_char hash[MD5_SIGNATURE_SIZE];
++#ifdef USE_EAPTLS
++ u_char flags;
++ struct eaptls_session *ets = esp->es_client.ea_session;
++#endif /* USE_EAPTLS */
++
+ #ifdef USE_SRP
+ struct t_client *tc;
+ struct t_num sval, gval, Nval, *Ap, Bval;
+@@ -1456,6 +1696,100 @@
+ esp->es_client.ea_namelen);
+ break;
+
++#ifdef USE_EAPTLS
++ case EAPT_TLS:
++
++ switch(esp->es_client.ea_state) {
++
++ case eapListen:
++
++ if (len < 1) {
++ error("EAP: received EAP-TLS Listen packet with no data");
++ /* Bogus request; wait for something real. */
++ return;
++ }
++ GETCHAR(flags, inp);
++ if(flags & EAP_TLS_FLAGS_START){
++
++ esp->es_client.ea_using_eaptls = 1;
++
++ if (explicit_remote){
++ esp->es_client.ea_peer = strdup(remote_name);
++ esp->es_client.ea_peerlen = strlen(remote_name);
++ } else
++ esp->es_client.ea_peer = NULL;
++
++ /* Init ssl session */
++ if(!eaptls_init_ssl_client(esp)) {
++ dbglog("cannot init ssl");
++ eap_send_nak(esp, id, EAPT_TLS);
++ esp->es_client.ea_using_eaptls = 0;
++ break;
++ }
++
++ ets = esp->es_client.ea_session;
++ eap_tls_response(esp, id);
++ esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck :
++ eapTlsRecv);
++ break;
++ }
++
++ /* The server has sent a bad start packet. */
++ eap_send_nak(esp, id, EAPT_TLS);
++ break;
++
++ case eapTlsRecvAck:
++ eap_tls_response(esp, id);
++ esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck :
++ eapTlsRecv);
++ break;
++
++ case eapTlsRecv:
++ if (len < 1) {
++ error("EAP: discarding EAP-TLS Receive packet with no data");
++ /* Bogus request; wait for something real. */
++ return;
++ }
++ eaptls_receive(ets, inp, len);
++
++ if(ets->frag) {
++ eap_tls_sendack(esp, id);
++ esp->es_client.ea_state = eapTlsRecv;
++ break;
++ }
++
++ if(ets->alert_recv) {
++ eap_tls_sendack(esp, id);
++ esp->es_client.ea_state = eapTlsRecvFailure;
++ break;
++ }
++
++ /* Check if TLS handshake is finished */
++ if(SSL_is_init_finished(ets->ssl)){
++#ifdef MPPE
++ eaptls_gen_mppe_keys( ets, "client EAP encryption", 1 );
++#endif
++ eaptls_free_session(ets);
++ eap_tls_sendack(esp, id);
++ esp->es_client.ea_state = eapTlsRecvSuccess;
++ break;
++ }
++
++ eap_tls_response(esp,id);
++ esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck :
++ eapTlsRecv);
++
++ break;
++
++ default:
++ eap_send_nak(esp, id, EAPT_TLS);
++ esp->es_client.ea_using_eaptls = 0;
++ break;
++ }
++
++ break;
++#endif /* USE_EAPTLS */
++
+ #ifdef USE_SRP
+ case EAPT_SRP:
+ if (len < 1) {
+@@ -1737,6 +2071,11 @@
+ u_char dig[SHA_DIGESTSIZE];
+ #endif /* USE_SRP */
+
++#ifdef USE_EAPTLS
++ struct eaptls_session *ets;
++ u_char flags;
++#endif /* USE_EAPTLS */
++
+ if (esp->es_server.ea_id != id) {
+ dbglog("EAP: discarding Response %d; expected ID %d", id,
+ esp->es_server.ea_id);
+@@ -1776,6 +2115,64 @@
+ eap_figure_next_state(esp, 0);
+ break;
+
++#ifdef USE_EAPTLS
++ case EAPT_TLS:
++ switch(esp->es_server.ea_state) {
++
++ case eapTlsRecv:
++
++ ets = (struct eaptls_session *) esp->es_server.ea_session;
++ eap_figure_next_state(esp,
++ eaptls_receive(esp->es_server.ea_session, inp, len));
++
++ if(ets->alert_recv) {
++ eap_send_failure(esp);
++ break;
++ }
++ break;
++
++ case eapTlsRecvAck:
++ if(len > 1) {
++ dbglog("EAP-TLS ACK with extra data");
++ }
++ eap_figure_next_state(esp, 0);
++ break;
++
++ case eapTlsRecvClient:
++ /* Receive authentication response from client */
++
++ if (len > 0) {
++ GETCHAR(flags, inp);
++
++ if(len == 1 && !flags) { /* Ack = ok */
++#ifdef MPPE
++ eaptls_gen_mppe_keys( esp->es_server.ea_session, "client EAP encryption", 0 );
++#endif
++ eap_send_success(esp);
++ }
++ else { /* failure */
++ warn("Server authentication failed");
++ eap_send_failure(esp);
++ }
++ }
++ else
++ warn("Bogus EAP-TLS packet received from client");
++
++ eaptls_free_session(esp->es_server.ea_session);
++
++ break;
++
++ case eapTlsRecvAlertAck:
++ eap_send_failure(esp);
++ break;
++
++ default:
++ eap_figure_next_state(esp, 1);
++ break;
++ }
++ break;
++#endif /* USE_EAPTLS */
++
+ case EAPT_NOTIFICATION:
+ dbglog("EAP unexpected Notification; response discarded");
+ break;
+@@ -1807,6 +2204,13 @@
+ esp->es_server.ea_state = eapMD5Chall;
+ break;
+
++#ifdef USE_EAPTLS
++ /* Send EAP-TLS start packet */
++ case EAPT_TLS:
++ esp->es_server.ea_state = eapTlsStart;
++ break;
++#endif /* USE_EAPTLS */
++
+ default:
+ dbglog("EAP: peer requesting unknown Type %d", vallen);
+ switch (esp->es_server.ea_state) {
+@@ -2018,13 +2422,27 @@
+ int id;
+ int len;
+ {
+- if (esp->es_client.ea_state != eapOpen && !eap_client_active(esp)) {
++ if (esp->es_client.ea_state != eapOpen && !eap_client_active(esp)
++#ifdef USE_EAPTLS
++ && esp->es_client.ea_state != eapTlsRecvSuccess
++#endif /* USE_EAPTLS */
++ ) {
+ dbglog("EAP unexpected success message in state %s (%d)",
+ eap_state_name(esp->es_client.ea_state),
+ esp->es_client.ea_state);
+ return;
+ }
+
++#ifdef USE_EAPTLS
++ if(esp->es_client.ea_using_eaptls && esp->es_client.ea_state !=
++ eapTlsRecvSuccess) {
++ dbglog("EAP-TLS unexpected success message in state %s (%d)",
++ eap_state_name(esp->es_client.ea_state),
++ esp->es_client.ea_state);
++ return;
++ }
++#endif /* USE_EAPTLS */
++
+ if (esp->es_client.ea_timeout > 0) {
+ UNTIMEOUT(eap_client_timeout, (void *)esp);
+ }
+@@ -2150,6 +2568,9 @@
+ int code, id, len, rtype, vallen;
+ u_char *pstart;
+ u_int32_t uval;
++#ifdef USE_EAPTLS
++ u_char flags;
++#endif /* USE_EAPTLS */
+
+ if (inlen < EAP_HEADERLEN)
+ return (0);
+@@ -2214,6 +2635,24 @@
+ }
+ break;
+
++#ifdef USE_EAPTLS
++ case EAPT_TLS:
++ if (len < 1)
++ break;
++ GETCHAR(flags, inp);
++ len--;
++
++ if(flags == 0 && len == 0){
++ printer(arg, " Ack");
++ break;
++ }
++
++ printer(arg, flags & EAP_TLS_FLAGS_LI ? " L":" -");
++ printer(arg, flags & EAP_TLS_FLAGS_MF ? "M":"-");
++ printer(arg, flags & EAP_TLS_FLAGS_START ? "S":"- ");
++ break;
++#endif /* USE_EAPTLS */
++
+ case EAPT_SRP:
+ if (len < 3)
+ goto truncated;
+@@ -2325,6 +2764,25 @@
+ }
+ break;
+
++#ifdef USE_EAPTLS
++ case EAPT_TLS:
++ if (len < 1)
++ break;
++ GETCHAR(flags, inp);
++ len--;
++
++ if(flags == 0 && len == 0){
++ printer(arg, " Ack");
++ break;
++ }
++
++ printer(arg, flags & EAP_TLS_FLAGS_LI ? " L":" -");
++ printer(arg, flags & EAP_TLS_FLAGS_MF ? "M":"-");
++ printer(arg, flags & EAP_TLS_FLAGS_START ? "S":"- ");
++
++ break;
++#endif /* USE_EAPTLS */
++
+ case EAPT_NAK:
+ if (len <= 0) {
+ printer(arg, " <missing hint>");
+@@ -2426,3 +2884,4 @@
+
+ return (inp - pstart);
+ }
++
+diff -Naur ppp-2.4.7/pppd/eap.h ppp-2.4.7-eaptls-mppe-1.101b/pppd/eap.h
+--- ppp-2.4.7/pppd/eap.h 2014-08-09 14:31:39.000000000 +0200
++++ ppp-2.4.7-eaptls-mppe-1.101b/pppd/eap.h 2018-06-02 01:42:04.023165433 +0200
+@@ -84,6 +84,16 @@
+ eapClosed, /* Authentication not in use */
+ eapListen, /* Client ready (and timer running) */
+ eapIdentify, /* EAP Identify sent */
++ eapTlsStart, /* Send EAP-TLS start packet */
++ eapTlsRecv, /* Receive EAP-TLS tls data */
++ eapTlsSendAck, /* Send EAP-TLS ack */
++ eapTlsSend, /* Send EAP-TLS tls data */
++ eapTlsRecvAck, /* Receive EAP-TLS ack */
++ eapTlsRecvClient, /* Receive EAP-TLS auth response from client*/
++ eapTlsSendAlert, /* Send EAP-TLS tls alert (server)*/
++ eapTlsRecvAlertAck, /* Receive EAP-TLS ack after sending alert */
++ eapTlsRecvSuccess, /* Receive EAP success */
++ eapTlsRecvFailure, /* Receive EAP failure */
+ eapSRP1, /* Sent EAP SRP-SHA1 Subtype 1 */
+ eapSRP2, /* Sent EAP SRP-SHA1 Subtype 2 */
+ eapSRP3, /* Sent EAP SRP-SHA1 Subtype 3 */
+@@ -95,9 +105,18 @@
+
+ #define EAP_STATES \
+ "Initial", "Pending", "Closed", "Listen", "Identify", \
++ "TlsStart", "TlsRecv", "TlsSendAck", "TlsSend", "TlsRecvAck", "TlsRecvClient",\
++ "TlsSendAlert", "TlsRecvAlertAck" , "TlsRecvSuccess", "TlsRecvFailure", \
+ "SRP1", "SRP2", "SRP3", "MD5Chall", "Open", "SRP4", "BadAuth"
+
+-#define eap_client_active(esp) ((esp)->es_client.ea_state == eapListen)
++#ifdef USE_EAPTLS
++#define eap_client_active(esp) ((esp)->es_client.ea_state != eapInitial &&\
++ (esp)->es_client.ea_state != eapPending &&\
++ (esp)->es_client.ea_state != eapClosed)
++#else
++#define eap_client_active(esp) ((esp)->es_client.ea_state == eapListen)
++#endif /* USE_EAPTLS */
++
+ #define eap_server_active(esp) \
+ ((esp)->es_server.ea_state >= eapIdentify && \
+ (esp)->es_server.ea_state <= eapMD5Chall)
+@@ -112,11 +131,17 @@
+ u_short ea_namelen; /* Length of our name */
+ u_short ea_peerlen; /* Length of peer's name */
+ enum eap_state_code ea_state;
++#ifdef USE_EAPTLS
++ enum eap_state_code ea_prev_state;
++#endif
+ u_char ea_id; /* Current id */
+ u_char ea_requests; /* Number of Requests sent/received */
+ u_char ea_responses; /* Number of Responses */
+ u_char ea_type; /* One of EAPT_* */
+ u_int32_t ea_keyflags; /* SRP shared key usage flags */
++#ifdef USE_EAPTLS
++ bool ea_using_eaptls;
++#endif
+ };
+
+ /*
+@@ -139,7 +164,12 @@
+ * Timeouts.
+ */
+ #define EAP_DEFTIMEOUT 3 /* Timeout (seconds) for rexmit */
++#ifdef USE_EAPTLS
++#define EAP_DEFTRANSMITS 30 /* max # times to transmit */
++ /* certificates can be long ... */
++#else
+ #define EAP_DEFTRANSMITS 10 /* max # times to transmit */
++#endif /* USE_EAPTLS */
+ #define EAP_DEFREQTIME 20 /* Time to wait for peer request */
+ #define EAP_DEFALLOWREQ 20 /* max # times to accept requests */
+
+diff -Naur ppp-2.4.7/pppd/md5.c ppp-2.4.7-eaptls-mppe-1.101b/pppd/md5.c
+--- ppp-2.4.7/pppd/md5.c 2014-08-09 14:31:39.000000000 +0200
++++ ppp-2.4.7-eaptls-mppe-1.101b/pppd/md5.c 2018-06-02 01:42:04.023165433 +0200
+@@ -33,6 +33,8 @@
+ ***********************************************************************
+ */
+
++#ifndef USE_EAPTLS
++
+ #include <string.h>
+ #include "md5.h"
+
+@@ -305,3 +307,5 @@
+ ** End of md5.c **
+ ******************************** (cut) ********************************
+ */
++#endif /* USE_EAPTLS */
++
+diff -Naur ppp-2.4.7/pppd/md5.h ppp-2.4.7-eaptls-mppe-1.101b/pppd/md5.h
+--- ppp-2.4.7/pppd/md5.h 2014-08-09 14:31:39.000000000 +0200
++++ ppp-2.4.7-eaptls-mppe-1.101b/pppd/md5.h 2018-06-02 01:42:04.024165430 +0200
+@@ -36,6 +36,7 @@
+ ** documentation and/or software. **
+ ***********************************************************************
+ */
++#ifndef USE_EAPTLS
+
+ #ifndef __MD5_INCLUDE__
+
+@@ -63,3 +64,5 @@
+
+ #define __MD5_INCLUDE__
+ #endif /* __MD5_INCLUDE__ */
++
++#endif /* USE_EAPTLS */
+diff -Naur ppp-2.4.7/pppd/pathnames.h ppp-2.4.7-eaptls-mppe-1.101b/pppd/pathnames.h
+--- ppp-2.4.7/pppd/pathnames.h 2014-08-09 14:31:39.000000000 +0200
++++ ppp-2.4.7-eaptls-mppe-1.101b/pppd/pathnames.h 2018-06-02 01:42:04.024165430 +0200
+@@ -21,6 +21,13 @@
+ #define _PATH_UPAPFILE _ROOT_PATH "/etc/ppp/pap-secrets"
+ #define _PATH_CHAPFILE _ROOT_PATH "/etc/ppp/chap-secrets"
+ #define _PATH_SRPFILE _ROOT_PATH "/etc/ppp/srp-secrets"
++
++#ifdef USE_EAPTLS
++#define _PATH_EAPTLSCLIFILE _ROOT_PATH "/etc/ppp/eaptls-client"
++#define _PATH_EAPTLSSERVFILE _ROOT_PATH "/etc/ppp/eaptls-server"
++#define _PATH_OPENSSLCONFFILE _ROOT_PATH "/etc/ppp/openssl.cnf"
++#endif /* USE_EAPTLS */
++
+ #define _PATH_SYSOPTIONS _ROOT_PATH "/etc/ppp/options"
+ #define _PATH_IPUP _ROOT_PATH "/etc/ppp/ip-up"
+ #define _PATH_IPDOWN _ROOT_PATH "/etc/ppp/ip-down"
+diff -Naur ppp-2.4.7/pppd/plugins/Makefile.linux ppp-2.4.7-eaptls-mppe-1.101b/pppd/plugins/Makefile.linux
+--- ppp-2.4.7/pppd/plugins/Makefile.linux 2014-08-09 14:31:39.000000000 +0200
++++ ppp-2.4.7-eaptls-mppe-1.101b/pppd/plugins/Makefile.linux 2018-06-02 01:42:04.024165430 +0200
+@@ -4,6 +4,9 @@
+ LDFLAGS = -shared
+ INSTALL = install
+
++# EAP-TLS
++CFLAGS += -DUSE_EAPTLS=1
++
+ DESTDIR = $(INSTROOT)@DESTDIR@
+ BINDIR = $(DESTDIR)/sbin
+ MANDIR = $(DESTDIR)/share/man/man8
+diff -Naur ppp-2.4.7/pppd/plugins/passprompt.c ppp-2.4.7-eaptls-mppe-1.101b/pppd/plugins/passprompt.c
+--- ppp-2.4.7/pppd/plugins/passprompt.c 2014-08-09 14:31:39.000000000 +0200
++++ ppp-2.4.7-eaptls-mppe-1.101b/pppd/plugins/passprompt.c 2018-06-02 01:42:04.024165430 +0200
+@@ -107,4 +107,7 @@
+ {
+ add_options(options);
+ pap_passwd_hook = promptpass;
++#ifdef USE_EAPTLS
++ eaptls_passwd_hook = promptpass;
++#endif
+ }
+diff -Naur ppp-2.4.7/pppd/plugins/passwordfd.c ppp-2.4.7-eaptls-mppe-1.101b/pppd/plugins/passwordfd.c
+--- ppp-2.4.7/pppd/plugins/passwordfd.c 2014-08-09 14:31:39.000000000 +0200
++++ ppp-2.4.7-eaptls-mppe-1.101b/pppd/plugins/passwordfd.c 2018-06-02 01:42:04.024165430 +0200
+@@ -79,4 +79,8 @@
+
+ chap_check_hook = pwfd_check;
+ chap_passwd_hook = pwfd_passwd;
++
++#ifdef USE_EAPTLS
++ eaptls_passwd_hook = pwfd_passwd;
++#endif
+ }
+diff -Naur ppp-2.4.7/pppd/pppd.8 ppp-2.4.7-eaptls-mppe-1.101b/pppd/pppd.8
+--- ppp-2.4.7/pppd/pppd.8 2014-08-09 14:31:39.000000000 +0200
++++ ppp-2.4.7-eaptls-mppe-1.101b/pppd/pppd.8 2018-06-02 01:42:04.025165427 +0200
+@@ -248,6 +248,12 @@
+ compression in the corresponding direction. Use \fInobsdcomp\fR or
+ \fIbsdcomp 0\fR to disable BSD-Compress compression entirely.
+ .TP
++.B ca \fIca-file
++(EAP-TLS) Use the file \fIca-file\fR as the X.509 Certificate Authority
++(CA) file (in PEM format), needed for setting up an EAP-TLS connection.
++This option is used on the client-side in conjunction with the \fBcert\fR
++and \fBkey\fR options.
++.TP
+ .B cdtrcts
+ Use a non-standard hardware flow control (i.e. DTR/CTS) to control
+ the flow of data on the serial port. If neither the \fIcrtscts\fR,
+@@ -259,6 +265,12 @@
+ bi-directional flow control. The sacrifice is that this flow
+ control mode does not permit using DTR as a modem control line.
+ .TP
++.B cert \fIcertfile
++(EAP-TLS) Use the file \fIcertfile\fR as the X.509 certificate (in PEM
++format), needed for setting up an EAP-TLS connection. This option is
++used on the client-side in conjunction with the \fBca\fR and
++\fBkey\fR options.
++.TP
+ .B chap\-interval \fIn
+ If this option is given, pppd will rechallenge the peer every \fIn\fR
+ seconds.
+@@ -287,6 +299,18 @@
+ 1000 (1 second). This wait period only applies if the \fBconnect\fR
+ or \fBpty\fR option is used.
+ .TP
++.B crl \fIfilename
++(EAP-TLS) Use the file \fIfilename\fR as the Certificate Revocation List
++to check for the validity of the peer's certificate. This option is not
++mandatory for setting up an EAP-TLS connection. Also see the \fBcrl-dir\fR
++option.
++.TP
++.B crl-dir \fIdirectory
++(EAP-TLS) Use the directory \fIdirectory\fR to scan for CRL files in
++has format ($hash.r0) to check for the validity of the peer's certificate.
++This option is not mandatory for setting up an EAP-TLS connection.
++Also see the \fBcrl\fR option.
++.TP
+ .B debug
+ Enables connection debugging facilities.
+ If this option is given, pppd will log the contents of all
+@@ -551,6 +575,12 @@
+ the kernel are logged by syslog(1) to a file as directed in the
+ /etc/syslog.conf configuration file.
+ .TP
++.B key \fIkeyfile
++(EAP-TLS) Use the file \fIkeyfile\fR as the private key file (in PEM
++format), needed for setting up an EAP-TLS connection. This option is
++used on the client-side in conjunction with the \fBca\fR and
++\fBcert\fR options.
++.TP
+ .B ktune
+ Enables pppd to alter kernel settings as appropriate. Under Linux,
+ pppd will enable IP forwarding (i.e. set /proc/sys/net/ipv4/ip_forward
+@@ -709,6 +739,9 @@
+ Disable Address/Control compression in both directions (send and
+ receive).
+ .TP
++.B need-peer-eap
++(EAP-TLS) Require the peer to verify our authentication credentials.
++.TP
+ .B noauth
+ Do not require the peer to authenticate itself. This option is
+ privileged.
+diff -Naur ppp-2.4.7/pppd/pppd.h ppp-2.4.7-eaptls-mppe-1.101b/pppd/pppd.h
+--- ppp-2.4.7/pppd/pppd.h 2014-08-09 14:31:39.000000000 +0200
++++ ppp-2.4.7-eaptls-mppe-1.101b/pppd/pppd.h 2018-06-02 01:42:04.025165427 +0200
+@@ -325,6 +325,11 @@
+ extern bool dryrun; /* check everything, print options, exit */
+ extern int child_wait; /* # seconds to wait for children at end */
+
++#ifdef USE_EAPTLS
++extern char *crl_dir;
++extern char *crl_file;
++#endif /* USE_EAPTLS */
++
+ #ifdef MAXOCTETS
+ extern unsigned int maxoctets; /* Maximum octetes per session (in bytes) */
+ extern int maxoctets_dir; /* Direction :
+@@ -741,6 +746,10 @@
+ extern int (*chap_passwd_hook) __P((char *user, char *passwd));
+ extern void (*multilink_join_hook) __P((void));
+
++#ifdef USE_EAPTLS
++extern int (*eaptls_passwd_hook) __P((char *user, char *passwd));
++#endif
++
+ /* Let a plugin snoop sent and received packets. Useful for L2TP */
+ extern void (*snoop_recv_hook) __P((unsigned char *p, int len));
+ extern void (*snoop_send_hook) __P((unsigned char *p, int len));
+
+
+
diff --git a/user/ppp/85_all_dhcp-make-vars.patch b/user/ppp/85_all_dhcp-make-vars.patch
new file mode 100644
index 000000000..68af3aaf3
--- /dev/null
+++ b/user/ppp/85_all_dhcp-make-vars.patch
@@ -0,0 +1,19 @@
+--- ppp-2.4.3/pppd/plugins/dhcp/Makefile.linux
++++ ppp-2.4.3/pppd/plugins/dhcp/Makefile.linux
+@@ -1,6 +1,6 @@
+
+ PLUGIN=dhcpc.so
+-CFLAGS=-I../.. -I../../../include -O2
++CFLAGS=$(COPTS) -I../.. -I../../../include -fPIC
+
+ all: $(PLUGIN)
+
+@@ -9,7 +9,7 @@
+ $(INSTALL) -s -c -m 755 dhcpc.so $(LIBDIR)
+
+ dhcpc.so: dhcpc.o clientpacket.o packet.o socket.o options.o
+- gcc -o dhcpc.so -shared dhcpc.o clientpacket.o packet.o socket.o options.o
++ $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $^
+
+
+ clean:
diff --git a/user/ppp/86_all_dhcp-sys_error_to_strerror.patch b/user/ppp/86_all_dhcp-sys_error_to_strerror.patch
new file mode 100644
index 000000000..e0d0937b2
--- /dev/null
+++ b/user/ppp/86_all_dhcp-sys_error_to_strerror.patch
@@ -0,0 +1,128 @@
+--- ppp-2.4.2/pppd/plugins/dhcp/dhcpc.c
++++ ppp-2.4.2/pppd/plugins/dhcp/dhcpc.c
+@@ -144,7 +144,7 @@
+ fd = raw_socket(client_config.ifindex);
+
+ if (listen_mode != LISTEN_NONE && fd < 0) {
+- fatal("DHCPC: couldn't listen on socket, %s", sys_errlist[errno]);
++ fatal("DHCPC: couldn't listen on socket, %s", strerror(errno));
+ }
+
+ }
+@@ -208,7 +208,7 @@
+ len = get_packet(&packet, fd);
+
+ if (len == -1 && errno != EINTR) {
+- dbglog("DHCPC: error on read, %s, reopening socket", sys_errlist[errno]);
++ dbglog("DHCPC: error on read, %s, reopening socket", strerror(errno));
+ change_mode(LISTEN_KERNEL);
+ }
+ if (len < 0) continue;
+@@ -380,7 +380,7 @@
+ else len = get_raw_packet(&packet, fd);
+
+ if (len == -1 && errno != EINTR) {
+- dbglog("DHCPC: error on read, %s, reopening socket", sys_errlist[errno]);
++ dbglog("DHCPC: error on read, %s, reopening socket", strerror(errno));
+ change_mode(listen_mode); /* just close and reopen */
+ }
+ if (len < 0) continue;
+@@ -445,7 +445,7 @@
+
+ } else {
+ /* An error occured */
+- dbglog("DHCPC: error on select, %s, reopening socket", sys_errlist[errno]);
++ dbglog("DHCPC: error on select, %s, reopening socket", strerror(errno));
+ change_mode(listen_mode); /* just close and reopen */
+ }
+
+--- ppp-2.4.2/pppd/plugins/dhcp/packet.c
++++ ppp-2.4.2/pppd/plugins/dhcp/packet.c
+@@ -125,7 +125,7 @@
+ return kernel_packet(payload,payload->giaddr,CLIENT_PORT,dest_ip,dest_port);
+
+ if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
+- DEBUG(LOG_ERR, "socket call failed: %s", sys_errlist[errno]);
++ DEBUG(LOG_ERR, "socket call failed: %s", strerror(errno));
+ return -1;
+ }
+
+@@ -138,7 +138,7 @@
+ dest.sll_halen = 6;
+ memcpy(dest.sll_addr, dest_arp, 6);
+ if (bind(fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_ll)) < 0) {
+- DEBUG(LOG_ERR, "bind call failed: %s", sys_errlist[errno]);
++ DEBUG(LOG_ERR, "bind call failed: %s", strerror(errno));
+ close(fd);
+ return -1;
+ }
+@@ -161,7 +161,7 @@
+
+ result = sendto(fd, &packet, sizeof(struct udp_dhcp_packet), 0, (struct sockaddr *) &dest, sizeof(dest));
+ if (result <= 0) {
+- DEBUG(LOG_ERR, "write on socket failed: %s", sys_errlist[errno]);
++ DEBUG(LOG_ERR, "write on socket failed: %s", strerror(errno));
+ }
+ close(fd);
+ return result;
+--- ppp-2.4.2/pppd/plugins/dhcp/socket.c
++++ ppp-2.4.2/pppd/plugins/dhcp/socket.c
+@@ -60,7 +60,7 @@
+ *addr = sin->sin_addr.s_addr;
+ DEBUG(LOG_INFO, "%s (our ip) = %s", ifr.ifr_name, inet_ntoa(sin->sin_addr));
+ } else {
+- LOG(LOG_ERR, "SIOCGIFADDR failed!: %s", sys_errlist[errno]);
++ LOG(LOG_ERR, "SIOCGIFADDR failed!: %s", strerror(errno));
+ return -1;
+ }
+ }
+@@ -69,7 +69,7 @@
+ DEBUG(LOG_INFO, "adapter index %d", ifr.ifr_ifindex);
+ *ifindex = ifr.ifr_ifindex;
+ } else {
+- LOG(LOG_ERR, "SIOCGIFINDEX failed!: %s", sys_errlist[errno]);
++ LOG(LOG_ERR, "SIOCGIFINDEX failed!: %s", strerror(errno));
+ return -1;
+ }
+ if (ioctl(fd, SIOCGIFHWADDR, &ifr) == 0) {
+@@ -77,11 +77,11 @@
+ DEBUG(LOG_INFO, "adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x",
+ arp[0], arp[1], arp[2], arp[3], arp[4], arp[5]);
+ } else {
+- LOG(LOG_ERR, "SIOCGIFHWADDR failed!: %s", sys_errlist[errno]);
++ LOG(LOG_ERR, "SIOCGIFHWADDR failed!: %s", strerror(errno));
+ return -1;
+ }
+ } else {
+- LOG(LOG_ERR, "socket failed!: %s", sys_errlist[errno]);
++ LOG(LOG_ERR, "socket failed!: %s", strerror(errno));
+ return -1;
+ }
+ close(fd);
+@@ -98,7 +98,7 @@
+
+ DEBUG(LOG_INFO, "Opening listen socket on 0x%08x:%d %s\n", ip, port, inf ? inf : "*");
+ if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+- DEBUG(LOG_ERR, "socket call failed: %s", sys_errlist[errno]);
++ DEBUG(LOG_ERR, "socket call failed: %s", strerror(errno));
+ return -1;
+ }
+
+@@ -144,7 +144,7 @@
+
+ DEBUG(LOG_INFO, "Opening raw socket on ifindex %d\n", ifindex);
+ if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
+- DEBUG(LOG_ERR, "socket call failed: %s", sys_errlist[errno]);
++ DEBUG(LOG_ERR, "socket call failed: %s", strerror(errno));
+ return -1;
+ }
+
+@@ -152,7 +152,7 @@
+ sock.sll_protocol = htons(ETH_P_IP);
+ sock.sll_ifindex = ifindex;
+ if (bind(fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) {
+- DEBUG(LOG_ERR, "bind call failed: %s", sys_errlist[errno]);
++ DEBUG(LOG_ERR, "bind call failed: %s", strerror(errno));
+ close(fd);
+ return -1;
+ }
diff --git a/user/ppp/APKBUILD b/user/ppp/APKBUILD
new file mode 100644
index 000000000..bcd4c85cf
--- /dev/null
+++ b/user/ppp/APKBUILD
@@ -0,0 +1,125 @@
+# Contributor: A. Wilcox <awilfox@adelielinux.org>
+# Maintainer: A. Wilcox <awilfox@adelielinux.org>
+pkgname=ppp
+pkgver=2.4.7
+pkgrel=0
+pkgdesc="Point-to-Point Protocol (PPP) implementation for serial networking"
+url="https://ppp.samba.org/"
+arch="all"
+options="!check" # No test suite.
+license="BSD-4-Clause AND GPL-2.0-only AND GPL-2.0+ AND zlib AND LGPL-2.0+"
+depends=""
+makedepends="bsd-compat-headers linux-pam-dev libpcap-dev openssl-dev utmps-dev"
+subpackages="$pkgname-dev $pkgname-doc $pkgname-openrc"
+source="https://download.samba.org/pub/ppp/ppp-$pkgver.tar.gz
+ http://distfiles.gentoo.org/distfiles/ppp-dhcpc.tgz
+ 02_all_make-vars.patch
+ 03_all_use_internal_logwtmp.patch
+ 04_all_mpls.patch
+ 06_all_killaddr-smarter.patch
+ 08_all_wait-children.patch
+ 10_all_defaultgateway.patch
+ 12_all_linkpidfile.patch
+ 16_all_auth-fail.patch
+ 18_all_defaultmetric.patch
+ 19_all_radius_pid_overflow.patch
+ 20_all_dev-ppp.patch
+ 21_all_custom_iface_names.patch
+ 24_all_passwordfd-read-early.patch
+ 26_all_pppd-usepeerwins.patch
+ 28_all_connect-errors.patch
+ 30_all_Makefile.patch
+ 32_all_pado-timeout.patch
+ 34_all_lcp-echo-adaptive.patch
+ 50_all_linux-headers.patch
+ 51_all_glibc-2.28.patch
+ 80_all_eaptls-mppe-1.101a.patch
+ 85_all_dhcp-make-vars.patch
+ 86_all_dhcp-sys_error_to_strerror.patch
+ adelie.patch
+ dhcp.patch
+ install-path.patch
+ musl-fix-headers.patch
+ utmpx.patch
+
+ ppp.mod
+ ppp.pamd
+ pppd.initd
+ "
+
+prepare() {
+ mv "$srcdir"/dhcp "$builddir"/pppd/plugins
+ default_prepare
+}
+
+build() {
+ ./configure \
+ --build=$CBUILD \
+ --host=$CHOST \
+ --prefix=/usr \
+ --sysconfdir=/etc \
+ --mandir=/usr/share/man \
+ --localstatedir=/var
+ make COPTS="$CFLAGS -D_GNU_SOURCE" \
+ LIBS="-lutmps -lskarnet -lcrypto -lssl -lpam -lpcap"
+ make -C contrib/pppgetpass pppgetpass.vt
+}
+
+package() {
+ make INSTROOT="$pkgdir" install
+
+ install -Dm 0644 -t "$pkgdir"/usr/include/net/ include/net/ppp_defs.h
+
+ install -d "$pkgdir"/etc/ppp/peers
+ install -m 0600 etc.ppp/pap-secrets \
+ "$pkgdir"/etc/ppp/pap-secrets.example
+ install -m 0600 etc.ppp/chap-secrets \
+ "$pkgdir"/etc/ppp/chap-secrets.example
+ install -m 0644 etc.ppp/options "$pkgdir"/etc/ppp/options
+
+ install -Dm 0644 "$srcdir"/ppp.pamd "$pkgdir"/etc/pam.d/ppp
+ install -Dm 0755 -t "$pkgdir"/usr/bin/ scripts/p{on,off,log}
+ install -Dm 0644 -t "$pkgdir"/usr/share/man/man1/ scripts/pon.1
+
+ install -Dm 0755 contrib/pppgetpass/pppgetpass.vt \
+ "$pkgdir"/usr/sbin/pppgetpass
+ install -Dm 0644 -t "$pkgdir"/usr/share/man/man8/ \
+ contrib/pppgetpass/pppgetpass.8
+
+ install -Dm 0644 "$srcdir"/ppp.mod "$pkgdir"/etc/modprobe.d/ppp.conf
+ install -Dm 0755 "$srcdir"/pppd.initd "$pkgdir"/etc/init.d/pppd
+}
+
+sha512sums="e34ce24020af6a73e7a26c83c4f73a9c83fa455b7b363794dba27bf01f70368be06bff779777843949bd77f4bc9385d6ad455ea48bf8fff4e0d73cc8fef16ae2 ppp-2.4.7.tar.gz
+aeaf791b14f5a09c0e2079072a157e65132cbff46e608bc0724e6a5827a01da934f5006e2774eb7105f83e607a52cb4987238f4385cf6f5cc86cbe305a556738 ppp-dhcpc.tgz
+8444d7edfe902a83f6cce96d29b9b7fb45ac68bdbe44494797d2a98470b80017489d36feb50cf945cbe72486bac69f45b23790e15cfbd33e07913a857ee80ab7 02_all_make-vars.patch
+4c4a5cc6fd8ce3203c41ff07fc0ce5f0468985c779fe05030898d36c404d2086ce7a49336ac58e6502fc2fd14c4de9006028fe19c500d2cac890a16a55c723e8 03_all_use_internal_logwtmp.patch
+1d63795949da00a19712aef39a54f338183b6917b246083e04a0b9ee43d346af5adeeb9357cb165587722790fa19b13375d55008646a4e9e2acdf8724bf3c7cc 04_all_mpls.patch
+b49086401c1b395ee6caba0418272b2d1b2ab9dcf6f1fc7e7f1280e94fcf17c8fdb884a19f4ef911bd7849a9cceb4cc07fc75438726340cd8c17265d4c2bd4d8 06_all_killaddr-smarter.patch
+807707ee9795ef4300b92bacdeba6b9e7332b6ce5a355de3ce77ddcc6dafce069f024131fd3ef282e38be3499e4230ad50fdda2b96e00891f5df1696234b775b 08_all_wait-children.patch
+c084237458ceb8704541f6e8424855788dbc2883559c4bf1ff35060e277c2b2ddfadcdb6dedc0bf42a5e83e98cfe7241fae8f6dc59d1ed963ed50356c9fd83ed 10_all_defaultgateway.patch
+122b9e3dbc3a9accacb31c653b3c0d368e8cdf3d954a6c93d04ac26ca8f3cb5bfcf8a01881d1cf08e855a1d2d0bd86e7fadba22bb5ada1a86f78e6b9820e6687 12_all_linkpidfile.patch
+3a23ef3619b2840eb3f1f7e14bd4765526b09acdfa8ab4d659ad8525a6f96d0cfb7c9fef042cde99ba1de8cf5caa74faa32e2a988453b4b17a70d5cc9a4bcf41 16_all_auth-fail.patch
+24b2cf579844bb9e1c0360227a5d35c3510471c0de6f16031d5e192d0ae7b1913aba93c2d99ea5fd3724deb6754f9831c1adb30671a31617268c77c65fc8beaf 18_all_defaultmetric.patch
+9fdb3346ef13b250f91f1af55c0efa0f836a60abe9e62fceed30df4e431a3bccdd33b083c2662c45e2091085438ba2221cdc4ae51fc1b05a666d77f74d461214 19_all_radius_pid_overflow.patch
+82c80701095a2d9707afbf5fc29bdf2fc3f92252b7de5de1d639f8607096a9d34ce90ffd0a2f770512b590a27dec56f2b03e5e9f4c9e56e1f362a2387d9fb568 20_all_dev-ppp.patch
+314e0939b546af5229db34888284a06e07d7b4c94190bf95d4382d3ff39935f18ecc6172f62309e4f63a00fdfceca73d908da8d82c95fd0b926b1832968ee3cc 21_all_custom_iface_names.patch
+2508cf1285a086c917ba5deffc96c1c29a511f1c1a0ef94c811b2bf139aed0218f34d7c1f1004890e105c47dffc5834a049dbe7686611d0fc8b8607ccdc86105 24_all_passwordfd-read-early.patch
+3eb55fb681e7fecf4e09b53683f509d2db3779599dd60fb89f88cd644c92d779f4720114546ba458262e8239581061e4a450143338c4725ada18b7ca314e12b0 26_all_pppd-usepeerwins.patch
+2e0bd81124bcd7c1234089f11e0b607b19047d279dc436ced3a4b8d793bcee4fcececd948b6a0755a02f68542c5c5e30b6f8541f90b998c09da8d50362827520 28_all_connect-errors.patch
+e495a489ee98258a3a4549127faca2c41feff27dff296065c2e41bfc696ced2ad1062ea0aa5bf3cc2425c85b4494ebbcbaaabacd8a3ea8ce8fab28acea028336 30_all_Makefile.patch
+77c0585b46f4fc090a67198d800d67dab2ce75eadcf2153c6e800e274b53ced6b512fd6eb4767c632f765bacd6c332f8d2a68233abb3781d6c62321d6bbb6052 32_all_pado-timeout.patch
+0bd928f45708f10835250fd6a6162f6e148dca172c810511c1f4b1fe56602c4869e7f622e95a3f4a41e5502ddefd0cf6054cd57211bc83426d5da5b5f10dac26 34_all_lcp-echo-adaptive.patch
+cda8e347eef7f26589cf1a12243f4d77de34d5736e3cb04fda9063adc0d931ef7ec7dbb2f142f1dfabc6d3ee04a252d2dd67d2c99ad9c01f2bd343bec88abe97 50_all_linux-headers.patch
+fc012971a062456fa4e253f5b4a5e2ce56ae1852293d0245ecfd165ba162fa76ec2c28e1035dd89de3e9d43941d528e2d95a40552eb8037a5ba084c1717c20d1 51_all_glibc-2.28.patch
+977b247e87557c4c57a871470c40670457e285ca59357dabab854ab16cc5578526ddf880410aa2efc7078e16d32d7afea4b69928af14ac4449523f6a591284f1 80_all_eaptls-mppe-1.101a.patch
+2d294bfe455648949cedb47a12a07913f0395aadbe2566c1e90d70fc37baa8635a667ab45195a697567f8d52de88771c499adffee82cde2e9e318ed858b6007b 85_all_dhcp-make-vars.patch
+44d5528c057d0abf2b45ba04943a52b6b94209434a06aa565f8a74acdd660efd86fe13280d540383168eaedad9f627673410bb8468860b64adb3145030e12889 86_all_dhcp-sys_error_to_strerror.patch
+2ba9ba8856e569c204a0e058a3e7a4a74f331118cb33bbca445a87b54bb0e4f0da2a968df5f394633911603359284831a80a4d9c793d795eef8477d00bab63f1 adelie.patch
+6d38f9779945bce2277f2d52d66dd79d2696f02c44186e1750d236f2d77d692746a8e8c164d925d5bb32dbfd02a723cabb59304f05954e0b5f7adada208ee220 dhcp.patch
+fb4ae2c2ba4ecdd1c85f6e5f730fd9659cf1fbc7a8a004b09042adafee7e4af6238df8deb3dbd3dc9c69407d9ebc4c82e1792a43b4aaf8ac18ebe18268b50597 install-path.patch
+2f071ea9db15e4abf1bed6cce8130dc81b710a31bfef5fa8f9370c353f845dbc47674b1551b8e040478e5156add6f98d480530206125e8bb308f0f4288d1eec6 musl-fix-headers.patch
+723ff3dd0aee13f9878559aa433b314af6043523a2bafd5957258809a645942f7d34b5bd659869a1528cf7b1a462ad7cc2dbf18e7986220f5f685f2c1ea1d36b utmpx.patch
+58bf5d6d286a08bd6dd595b39ee425efedd5745dddf33a9c90505891546eb46f4cf1306d83911bef61bc4611816aa0f6aef5d3e0f14c2f4ddd0a588780570041 ppp.mod
+e30a397392d467ac3c78f6533f3adff5de7d38f0372d8d6f7b186db4ec69ddf12463d467d8a86eb5867effeb7dd6bd16942a98fb3a3ab59ff754a123e16d0938 ppp.pamd
+bd6f43588b037367ffdb57f5e331492dcaa5969003e219c2dc8b90e6be1aa407282ff6114b91d1379ebeff766983fa0622456520cc0ac592b4f0b1496acf21bf pppd.initd"
diff --git a/user/ppp/adelie.patch b/user/ppp/adelie.patch
new file mode 100644
index 000000000..06bb6edf9
--- /dev/null
+++ b/user/ppp/adelie.patch
@@ -0,0 +1,88 @@
+--- ppp-2.4.7/pppd/Makefile.linux.old 2019-05-09 20:32:30.959257140 +0000
++++ ppp-2.4.7/pppd/Makefile.linux 2019-05-09 20:34:48.964184093 +0000
+@@ -32,7 +32,7 @@
+
+ # CC = gcc
+ #
+-COPTS+= -Wall
++COPTS+= -Wall -D_GNU_SOURCE
+ LIBS =
+
+ # Uncomment the next line to include support for Microsoft's
+@@ -61,14 +61,14 @@
+ USE_TDB=y
+
+ HAS_SHADOW=y
+-#USE_PAM=y
++USE_PAM=y
+ HAVE_INET6=y
+
+ # Enable plugins
+ PLUGIN=y
+
+ # Enable Microsoft proprietary Callback Control Protocol
+-#CBCP=y
++CBCP=y
+
+ # Enable EAP SRP-SHA1 authentication (requires libsrp)
+ #USE_SRP=y
+@@ -102,8 +102,8 @@
+
+ # EAP SRP-SHA1
+ ifdef USE_SRP
+-CFLAGS += -DUSE_SRP -DOPENSSL -I/usr/local/ssl/include
+-LIBS += -lsrp -L/usr/local/ssl/lib -lcrypto
++CFLAGS += -DUSE_SRP -DOPENSSL
++LIBS += -lsrp `$(PKG_CONFIG) --libs libcrypto`
+ TARGETS += srp-entry
+ EXTRAINSTALL = $(INSTALL) -s -c -m 555 srp-entry $(BINDIR)/srp-entry
+ MANPAGES += srp-entry.8
+--- ppp-2.4.7/pppd/plugins/radius/pathnames.h.old 2014-08-09 12:31:39.000000000 +0000
++++ ppp-2.4.7/pppd/plugins/radius/pathnames.h 2019-05-09 20:35:39.258690873 +0000
+@@ -22,7 +22,7 @@
+
+ /* normally defined in the Makefile */
+ #ifndef _PATH_ETC_RADIUSCLIENT_CONF
+-#define _PATH_ETC_RADIUSCLIENT_CONF "/etc/radiusclient.conf"
++#define _PATH_ETC_RADIUSCLIENT_CONF "/etc/radiusclient/radiusclient.conf"
+ #endif
+
+ #endif /* PATHNAMES_H */
+--- ppp-2.4.7/pppd/plugins/radius/etc/radiusclient.conf.old 2014-08-09 12:31:39.000000000 +0000
++++ ppp-2.4.7/pppd/plugins/radius/etc/radiusclient.conf 2019-05-09 20:37:29.676630906 +0000
+@@ -22,7 +22,7 @@
+
+ # name of the issue file. it's only display when no username is passed
+ # on the radlogin command line (default /etc/radiusclient/issue)
+-issue /usr/local/etc/radiusclient/issue
++issue /etc/radiusclient/issue
+
+ # RADIUS settings
+
+@@ -43,22 +43,22 @@
+
+ # file holding shared secrets used for the communication
+ # between the RADIUS client and server
+-servers /usr/local/etc/radiusclient/servers
++servers /etc/radiusclient/servers
+
+ # dictionary of allowed attributes and values
+ # just like in the normal RADIUS distributions
+-dictionary /usr/local/etc/radiusclient/dictionary
++dictionary /etc/radiusclient/dictionary
+
+ # program to call for a RADIUS authenticated login
+ # (default /usr/sbin/login.radius)
+-login_radius /usr/local/sbin/login.radius
++login_radius /usr/sbin/login.radius
+
+ # file which holds sequence number for communication with the
+ # RADIUS server
+ seqfile /var/run/radius.seq
+
+ # file which specifies mapping between ttyname and NAS-Port attribute
+-mapfile /usr/local/etc/radiusclient/port-id-map
++mapfile /etc/radiusclient/port-id-map
+
+ # default authentication realm to append to all usernames if no
+ # realm was explicitly specified by the user
diff --git a/user/ppp/dhcp.patch b/user/ppp/dhcp.patch
new file mode 100644
index 000000000..611882326
--- /dev/null
+++ b/user/ppp/dhcp.patch
@@ -0,0 +1,324 @@
+--- ppp-2.4.7/pppd/plugins/Makefile.linux.old 2019-05-09 23:06:56.499058276 +0000
++++ ppp-2.4.7/pppd/plugins/Makefile.linux 2019-05-09 23:11:21.040252628 +0000
+@@ -16,7 +16,7 @@
+ MANDIR = $(DESTDIR)/share/man/man8
+ LIBDIR = $(DESTDIR)/lib/pppd/$(VERSION)
+
+-SUBDIRS := rp-pppoe pppoatm pppol2tp
++SUBDIRS := dhcp rp-pppoe pppoatm pppol2tp
+ # Uncomment the next line to include the radius authentication plugin
+ SUBDIRS += radius
+ PLUGINS := minconn.so passprompt.so passwordfd.so winbind.so
+--- ppp-2.4.7/pppd/plugins/dhcp/README.old 2002-09-30 11:33:49.000000000 +0000
++++ ppp-2.4.7/pppd/plugins/dhcp/README 2019-05-09 23:11:37.408470308 +0000
+@@ -37,7 +37,7 @@
+
+ This option specified the local IP address of the system running
+ this proxy, as should be identified to the DHCP server in the
+- 'giaddr' field of DHCP requests. Normal server behavor should
++ 'giaddr' field of DHCP requests. Normal server behaviour should
+ be to send DHCP responses to this address. The default is the
+ primary address bound to the dhcp interface.
+
+diff -Naur ppp-2.4.7/pppd/plugins/dhcp.old/clientpacket.c ppp-2.4.7/pppd/plugins/dhcp/clientpacket.c
+--- ppp-2.4.7/pppd/plugins/dhcp.old/clientpacket.c 2002-08-31 12:19:20.000000000 +0000
++++ ppp-2.4.7/pppd/plugins/dhcp/clientpacket.c 2019-05-09 23:42:33.566347764 +0000
+@@ -179,8 +179,8 @@
+ {
+ int bytes;
+ struct udp_dhcp_packet packet;
+- u_int32_t source, dest;
+- u_int16_t check;
++ uint32_t source, dest;
++ uint16_t check;
+
+ memset(&packet, 0, sizeof(struct udp_dhcp_packet));
+ bytes = read(fd, &packet, sizeof(struct udp_dhcp_packet));
+diff -Naur ppp-2.4.7/pppd/plugins/dhcp.old/dhcpc.c ppp-2.4.7/pppd/plugins/dhcp/dhcpc.c
+--- ppp-2.4.7/pppd/plugins/dhcp.old/dhcpc.c 2019-05-09 23:41:38.732319544 +0000
++++ ppp-2.4.7/pppd/plugins/dhcp/dhcpc.c 2019-05-09 23:42:33.566347764 +0000
+@@ -56,11 +56,11 @@
+ #include "socket.h"
+ #include "debug.h"
+
+-static void (*dhcp_old_ip_choose_hook)(u_int32_t *addrp);
++static void (*dhcp_old_ip_choose_hook)(uint32_t *addrp);
+
+ static int dhcp_state;
+-static u_int32_t requested_ip; /* = 0 */
+-u_int32_t assigned_ip; /* value supplied to remote ppp */
++static uint32_t requested_ip; /* = 0 */
++uint32_t assigned_ip; /* value supplied to remote ppp */
+ static unsigned long server_addr;
+ unsigned long lease, renew_timeout;
+ unsigned long xid = 0;
+@@ -118,7 +118,7 @@
+ void dhcp_release(void *ptr, int arg);
+ void dhcp_renew(void *dummy);
+ void dhcp_request_new();
+-void dhcp_ip_choose(u_int32_t *addrp);
++void dhcp_ip_choose(uint32_t *addrp);
+ void dhcp_read_options(void);
+
+
+@@ -453,8 +453,8 @@
+ return;
+ }
+
+-void dhcp_ip_choose(u_int32_t *addrp) {
+- u_int32_t entryvalue;
++void dhcp_ip_choose(uint32_t *addrp) {
++ uint32_t entryvalue;
+
+ dbglog("DHCPC: ip_choose_hook entered with peer name %s",peer_authname);
+
+diff -Naur ppp-2.4.7/pppd/plugins/dhcp.old/dhcpc.h ppp-2.4.7/pppd/plugins/dhcp/dhcpc.h
+--- ppp-2.4.7/pppd/plugins/dhcp.old/dhcpc.h 2002-08-31 11:54:23.000000000 +0000
++++ ppp-2.4.7/pppd/plugins/dhcp/dhcpc.h 2019-05-09 23:42:33.566347764 +0000
+@@ -24,9 +24,9 @@
+ unsigned char *hostname; /* Optional hostname to use */
+ int ifindex; /* Index number of the interface to use */
+ unsigned char arp[6]; /* Our arp address */
+- u_int32_t giaddr; /* Fill in this value on all packets we generate */
+- u_int32_t siaddr; /* If defined, only talk to this server (never broadcast) */
+- u_int32_t subnet_selection; /* If non zero, send and require SS option */
++ uint32_t giaddr; /* Fill in this value on all packets we generate */
++ uint32_t siaddr; /* If defined, only talk to this server (never broadcast) */
++ uint32_t subnet_selection; /* If non zero, send and require SS option */
+ };
+
+ extern struct client_config_t client_config;
+diff -Naur ppp-2.4.7/pppd/plugins/dhcp.old/dhcpd.h ppp-2.4.7/pppd/plugins/dhcp/dhcpd.h
+--- ppp-2.4.7/pppd/plugins/dhcp.old/dhcpd.h 2002-08-31 11:52:31.000000000 +0000
++++ ppp-2.4.7/pppd/plugins/dhcp/dhcpd.h 2019-05-09 23:42:33.566347764 +0000
+@@ -101,9 +101,9 @@
+ };
+
+ struct server_config_t {
+- u_int32_t server; /* Our IP, in network order */
+- u_int32_t start; /* Start address of leases, network order */
+- u_int32_t end; /* End of leases, network order */
++ uint32_t server; /* Our IP, in network order */
++ uint32_t start; /* Start address of leases, network order */
++ uint32_t end; /* End of leases, network order */
+ struct option_set *options; /* List of DHCP options loaded from the config file */
+ char *interface; /* The name of the interface to use */
+ int ifindex; /* Index number of the interface to use */
+@@ -122,7 +122,7 @@
+ char *lease_file;
+ char *pidfile;
+ char *notify_file; /* What to run whenever leases are written */
+- u_int32_t siaddr; /* next server bootp option */
++ uint32_t siaddr; /* next server bootp option */
+ char *sname; /* bootp server name */
+ char *boot_file; /* bootp boot file option */
+ };
+diff -Naur ppp-2.4.7/pppd/plugins/dhcp.old/leases.h ppp-2.4.7/pppd/plugins/dhcp/leases.h
+--- ppp-2.4.7/pppd/plugins/dhcp.old/leases.h 2002-08-23 13:17:14.000000000 +0000
++++ ppp-2.4.7/pppd/plugins/dhcp/leases.h 2019-05-09 23:42:33.566347764 +0000
+@@ -4,20 +4,20 @@
+
+
+ struct dhcpOfferedAddr {
+- u_int8_t chaddr[16];
+- u_int32_t yiaddr; /* network order */
+- u_int32_t expires; /* host order */
++ uint8_t chaddr[16];
++ uint32_t yiaddr; /* network order */
++ uint32_t expires; /* host order */
+ };
+
+
+-void clear_lease(u_int8_t *chaddr, u_int32_t yiaddr);
+-struct dhcpOfferedAddr *add_lease(u_int8_t *chaddr, u_int32_t yiaddr, unsigned long lease);
++void clear_lease(uint8_t *chaddr, uint32_t yiaddr);
++struct dhcpOfferedAddr *add_lease(uint8_t *chaddr, uint32_t yiaddr, unsigned long lease);
+ int lease_expired(struct dhcpOfferedAddr *lease);
+ struct dhcpOfferedAddr *oldest_expired_lease(void);
+-struct dhcpOfferedAddr *find_lease_by_chaddr(u_int8_t *chaddr);
+-struct dhcpOfferedAddr *find_lease_by_yiaddr(u_int32_t yiaddr);
+-u_int32_t find_address(int check_expired);
+-int check_ip(u_int32_t addr);
++struct dhcpOfferedAddr *find_lease_by_chaddr(uint8_t *chaddr);
++struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr);
++uint32_t find_address(int check_expired);
++int check_ip(uint32_t addr);
+
+
+ #endif
+diff -Naur ppp-2.4.7/pppd/plugins/dhcp.old/options.c ppp-2.4.7/pppd/plugins/dhcp/options.c
+--- ppp-2.4.7/pppd/plugins/dhcp.old/options.c 2002-08-31 11:52:37.000000000 +0000
++++ ppp-2.4.7/pppd/plugins/dhcp/options.c 2019-05-09 23:42:33.566347764 +0000
+@@ -148,17 +148,17 @@
+
+
+ /* add a one to four byte option to a packet */
+-int add_simple_option(unsigned char *optionptr, unsigned char code, u_int32_t data)
++int add_simple_option(unsigned char *optionptr, unsigned char code, uint32_t data)
+ {
+ char length = 0;
+ int i;
+ unsigned char option[2 + 4];
+ unsigned char *u8;
+- u_int16_t *u16;
+- u_int32_t *u32;
+- u_int32_t aligned;
++ uint16_t *u16;
++ uint32_t *u32;
++ uint32_t aligned;
+ u8 = (unsigned char *) &aligned;
+- u16 = (u_int16_t *) &aligned;
++ u16 = (uint16_t *) &aligned;
+ u32 = &aligned;
+
+ for (i = 0; options[i].code; i++)
+diff -Naur ppp-2.4.7/pppd/plugins/dhcp.old/options.h ppp-2.4.7/pppd/plugins/dhcp/options.h
+--- ppp-2.4.7/pppd/plugins/dhcp.old/options.h 2002-08-23 13:06:28.000000000 +0000
++++ ppp-2.4.7/pppd/plugins/dhcp/options.h 2019-05-09 23:42:33.566347764 +0000
+@@ -33,7 +33,7 @@
+ unsigned char *get_option(struct dhcpMessage *packet, int code);
+ int end_option(unsigned char *optionptr);
+ int add_option_string(unsigned char *optionptr, unsigned char *string);
+-int add_simple_option(unsigned char *optionptr, unsigned char code, u_int32_t data);
++int add_simple_option(unsigned char *optionptr, unsigned char code, uint32_t data);
+ struct option_set *find_option(struct option_set *opt_list, char code);
+ void attach_option(struct option_set **opt_list, struct dhcp_option *option, char *buffer, int length);
+
+diff -Naur ppp-2.4.7/pppd/plugins/dhcp.old/packet.c ppp-2.4.7/pppd/plugins/dhcp/packet.c
+--- ppp-2.4.7/pppd/plugins/dhcp.old/packet.c 2019-05-09 23:41:38.732319544 +0000
++++ ppp-2.4.7/pppd/plugins/dhcp/packet.c 2019-05-09 23:42:33.566347764 +0000
+@@ -83,13 +83,13 @@
+ }
+
+
+-u_int16_t checksum(void *addr, int count)
++uint16_t checksum(void *addr, int count)
+ {
+ /* Compute Internet Checksum for "count" bytes
+ * beginning at location "addr".
+ */
+ register int32_t sum = 0;
+- u_int16_t *source = (u_int16_t *) addr;
++ uint16_t *source = (uint16_t *) addr;
+
+ while( count > 1 ) {
+ /* This is the inner loop */
+@@ -110,8 +110,8 @@
+
+
+ /* Constuct a ip/udp header for a packet, and specify the source and dest hardware address */
+-int raw_packet(struct dhcpMessage *payload, u_int32_t source_ip, int source_port,
+- u_int32_t dest_ip, int dest_port, unsigned char *dest_arp, int ifindex)
++int raw_packet(struct dhcpMessage *payload, uint32_t source_ip, int source_port,
++ uint32_t dest_ip, int dest_port, unsigned char *dest_arp, int ifindex)
+ {
+ int fd;
+ int result;
+@@ -169,8 +169,8 @@
+
+
+ /* Let the kernel do all the work for packet generation */
+-int kernel_packet(struct dhcpMessage *payload, u_int32_t source_ip, int source_port,
+- u_int32_t dest_ip, int dest_port)
++int kernel_packet(struct dhcpMessage *payload, uint32_t source_ip, int source_port,
++ uint32_t dest_ip, int dest_port)
+ {
+ int n = 1;
+ int fd, result;
+diff -Naur ppp-2.4.7/pppd/plugins/dhcp.old/packet.h ppp-2.4.7/pppd/plugins/dhcp/packet.h
+--- ppp-2.4.7/pppd/plugins/dhcp.old/packet.h 2002-08-23 13:04:56.000000000 +0000
++++ ppp-2.4.7/pppd/plugins/dhcp/packet.h 2019-05-09 23:42:33.566347764 +0000
+@@ -5,22 +5,22 @@
+ #include <netinet/ip.h>
+
+ struct dhcpMessage {
+- u_int8_t op;
+- u_int8_t htype;
+- u_int8_t hlen;
+- u_int8_t hops;
+- u_int32_t xid;
+- u_int16_t secs;
+- u_int16_t flags;
+- u_int32_t ciaddr;
+- u_int32_t yiaddr;
+- u_int32_t siaddr;
+- u_int32_t giaddr;
+- u_int8_t chaddr[16];
+- u_int8_t sname[64];
+- u_int8_t file[128];
+- u_int32_t cookie;
+- u_int8_t options[308]; /* 312 - cookie */
++ uint8_t op;
++ uint8_t htype;
++ uint8_t hlen;
++ uint8_t hops;
++ uint32_t xid;
++ uint16_t secs;
++ uint16_t flags;
++ uint32_t ciaddr;
++ uint32_t yiaddr;
++ uint32_t siaddr;
++ uint32_t giaddr;
++ uint8_t chaddr[16];
++ uint8_t sname[64];
++ uint8_t file[128];
++ uint32_t cookie;
++ uint8_t options[308]; /* 312 - cookie */
+ };
+
+ struct udp_dhcp_packet {
+@@ -31,11 +31,11 @@
+
+ void init_header(struct dhcpMessage *packet, char type);
+ int get_packet(struct dhcpMessage *packet, int fd);
+-u_int16_t checksum(void *addr, int count);
+-int raw_packet(struct dhcpMessage *payload, u_int32_t source_ip, int source_port,
+- u_int32_t dest_ip, int dest_port, unsigned char *dest_arp, int ifindex);
+-int kernel_packet(struct dhcpMessage *payload, u_int32_t source_ip, int source_port,
+- u_int32_t dest_ip, int dest_port);
++uint16_t checksum(void *addr, int count);
++int raw_packet(struct dhcpMessage *payload, uint32_t source_ip, int source_port,
++ uint32_t dest_ip, int dest_port, unsigned char *dest_arp, int ifindex);
++int kernel_packet(struct dhcpMessage *payload, uint32_t source_ip, int source_port,
++ uint32_t dest_ip, int dest_port);
+
+
+ #endif
+diff -Naur ppp-2.4.7/pppd/plugins/dhcp.old/socket.c ppp-2.4.7/pppd/plugins/dhcp/socket.c
+--- ppp-2.4.7/pppd/plugins/dhcp.old/socket.c 2019-05-09 23:41:38.732319544 +0000
++++ ppp-2.4.7/pppd/plugins/dhcp/socket.c 2019-05-09 23:42:33.566347764 +0000
+@@ -43,7 +43,7 @@
+
+ #include "debug.h"
+
+-int read_interface(char *interface, int *ifindex, u_int32_t *addr, unsigned char *arp)
++int read_interface(char *interface, int *ifindex, uint32_t *addr, unsigned char *arp)
+ {
+ int fd;
+ struct ifreq ifr;
+diff -Naur ppp-2.4.7/pppd/plugins/dhcp.old/socket.h ppp-2.4.7/pppd/plugins/dhcp/socket.h
+--- ppp-2.4.7/pppd/plugins/dhcp.old/socket.h 2002-08-23 13:06:28.000000000 +0000
++++ ppp-2.4.7/pppd/plugins/dhcp/socket.h 2019-05-09 23:42:33.566347764 +0000
+@@ -2,7 +2,7 @@
+ #ifndef _SOCKET_H
+ #define _SOCKET_H
+
+-int read_interface(char *interface, int *ifindex, u_int32_t *addr, unsigned char *arp);
++int read_interface(char *interface, int *ifindex, uint32_t *addr, unsigned char *arp);
+ int listen_socket(unsigned int ip, int port, char *inf);
+ int raw_socket(int ifindex);
+
+--- ppp-2.4.7/pppd/plugins/dhcp/Makefile.linux.old 2019-05-09 23:54:56.595427092 +0000
++++ ppp-2.4.7/pppd/plugins/dhcp/Makefile.linux 2019-05-09 23:56:53.012746364 +0000
+@@ -1,6 +1,11 @@
+
+ PLUGIN=dhcpc.so
+ CFLAGS=$(COPTS) -I../.. -I../../../include -fPIC
++INSTALL = install
++DESTDIR = $(INSTROOT)/usr
++LIBDIR = $(DESTDIR)/lib/pppd/$(VERSION)
++
++VERSION = $(shell awk -F '"' '/VERSION/ { print $$2; }' ../../patchlevel.h)
+
+ all: $(PLUGIN)
+
diff --git a/user/ppp/install-path.patch b/user/ppp/install-path.patch
new file mode 100644
index 000000000..845729fd5
--- /dev/null
+++ b/user/ppp/install-path.patch
@@ -0,0 +1,11 @@
+--- ppp-2.4.7/pppd/plugins/pppol2tp/Makefile.linux.old 2019-05-09 22:28:24.640793389 +0000
++++ ppp-2.4.7/pppd/plugins/pppol2tp/Makefile.linux 2019-05-09 23:02:56.955142166 +0000
+@@ -4,7 +4,7 @@
+
+ #***********************************************************************
+
+-DESTDIR = @DESTDIR@
++DESTDIR = $(INSTROOT)@DESTDIR@
+ LIBDIR = $(DESTDIR)/lib/pppd/$(VERSION)
+
+ VERSION = $(shell awk -F '"' '/VERSION/ { print $$2; }' ../../patchlevel.h)
diff --git a/user/ppp/musl-fix-headers.patch b/user/ppp/musl-fix-headers.patch
new file mode 100644
index 000000000..d24f62896
--- /dev/null
+++ b/user/ppp/musl-fix-headers.patch
@@ -0,0 +1,137 @@
+diff --git a/include/net/ppp_defs.h b/include/net/ppp_defs.h
+index b06eda5..dafa36c 100644
+--- a/include/net/ppp_defs.h
++++ b/include/net/ppp_defs.h
+@@ -38,6 +38,8 @@
+ #ifndef _PPP_DEFS_H_
+ #define _PPP_DEFS_H_
+
++#include <sys/time.h>
++
+ /*
+ * The basic PPP frame.
+ */
+diff --git a/pppd/Makefile.linux b/pppd/Makefile.linux
+index a74c914..7acd2cf 100644
+--- a/pppd/Makefile.linux
++++ b/pppd/Makefile.linux
+@@ -126,7 +126,7 @@ LIBS += -lcrypt
+ endif
+
+ ifdef USE_LIBUTIL
+-CFLAGS += -DHAVE_LOGWTMP=1
++#CFLAGS += -DHAVE_LOGWTMP=1
+ LIBS += -lutil
+ endif
+
+diff --git a/pppd/magic.h b/pppd/magic.h
+index c81213b..305aece 100644
+--- a/pppd/magic.h
++++ b/pppd/magic.h
+@@ -42,6 +42,8 @@
+ * $Id: magic.h,v 1.5 2003/06/11 23:56:26 paulus Exp $
+ */
+
++#include <sys/cdefs.h>
++
+ void magic_init __P((void)); /* Initialize the magic number generator */
+ u_int32_t magic __P((void)); /* Returns the next magic number */
+
+diff --git a/pppd/plugins/rp-pppoe/if.c b/pppd/plugins/rp-pppoe/if.c
+index 91e9a57..9c0fac3 100644
+--- a/pppd/plugins/rp-pppoe/if.c
++++ b/pppd/plugins/rp-pppoe/if.c
+@@ -30,10 +30,6 @@ static char const RCSID[] =
+ #include <linux/if_packet.h>
+ #endif
+
+-#ifdef HAVE_NET_ETHERNET_H
+-#include <net/ethernet.h>
+-#endif
+-
+ #ifdef HAVE_ASM_TYPES_H
+ #include <asm/types.h>
+ #endif
+diff --git a/pppd/plugins/rp-pppoe/plugin.c b/pppd/plugins/rp-pppoe/plugin.c
+index a8c2bb4..ca34d79 100644
+--- a/pppd/plugins/rp-pppoe/plugin.c
++++ b/pppd/plugins/rp-pppoe/plugin.c
+@@ -46,7 +46,6 @@ static char const RCSID[] =
+ #include <unistd.h>
+ #include <fcntl.h>
+ #include <signal.h>
+-#include <net/ethernet.h>
+ #include <net/if_arp.h>
+ #include <linux/ppp_defs.h>
+ #include <linux/if_pppox.h>
+diff --git a/pppd/plugins/rp-pppoe/pppoe-discovery.c b/pppd/plugins/rp-pppoe/pppoe-discovery.c
+index 3d3bf4e..b5f82d3 100644
+--- a/pppd/plugins/rp-pppoe/pppoe-discovery.c
++++ b/pppd/plugins/rp-pppoe/pppoe-discovery.c
+@@ -27,10 +27,6 @@
+ #include <linux/if_packet.h>
+ #endif
+
+-#ifdef HAVE_NET_ETHERNET_H
+-#include <net/ethernet.h>
+-#endif
+-
+ #ifdef HAVE_ASM_TYPES_H
+ #include <asm/types.h>
+ #endif
+@@ -55,6 +51,8 @@ void die(int status)
+ exit(status);
+ }
+
++#define error(x...) fprintf(stderr, x)
++
+ /* Initialize frame types to RFC 2516 values. Some broken peers apparently
+ use different frame types... sigh... */
+
+diff --git a/pppd/plugins/rp-pppoe/pppoe.h b/pppd/plugins/rp-pppoe/pppoe.h
+index 9ab2eee..4d68147 100644
+--- a/pppd/plugins/rp-pppoe/pppoe.h
++++ b/pppd/plugins/rp-pppoe/pppoe.h
+@@ -86,18 +86,6 @@ typedef unsigned long UINT32_t;
+
+ #include <netinet/in.h>
+
+-#ifdef HAVE_NETINET_IF_ETHER_H
+-#include <sys/types.h>
+-
+-#ifdef HAVE_SYS_SOCKET_H
+-#include <sys/socket.h>
+-#endif
+-#ifndef HAVE_SYS_DLPI_H
+-#include <netinet/if_ether.h>
+-#endif
+-#endif
+-
+-
+
+ /* Ethernet frame types according to RFC 2516 */
+ #define ETH_PPPOE_DISCOVERY 0x8863
+diff --git a/pppd/sys-linux.c b/pppd/sys-linux.c
+index 6d71530..86d224e 100644
+--- a/pppd/sys-linux.c
++++ b/pppd/sys-linux.c
+@@ -102,19 +102,11 @@
+ #define MAX_ADDR_LEN 7
+ #endif
+
+-#if __GLIBC__ >= 2
+ #include <asm/types.h> /* glibc 2 conflicts with linux/types.h */
+ #include <net/if.h>
+ #include <net/if_arp.h>
+ #include <net/route.h>
+ #include <netinet/if_ether.h>
+-#else
+-#include <linux/types.h>
+-#include <linux/if.h>
+-#include <linux/if_arp.h>
+-#include <linux/route.h>
+-#include <linux/if_ether.h>
+-#endif
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+
diff --git a/user/ppp/ppp.mod b/user/ppp/ppp.mod
new file mode 100644
index 000000000..e936041c6
--- /dev/null
+++ b/user/ppp/ppp.mod
@@ -0,0 +1,10 @@
+alias char-major-108 ppp_generic
+alias /dev/ppp ppp_generic
+alias tty-ldisc-3 ppp_async
+alias tty-ldisc-13 n_hdlc
+alias tty-ldisc-14 ppp_synctty
+alias ppp-compress-18 ppp_mppe
+alias ppp-compress-21 bsd_comp
+alias ppp-compress-24 ppp_deflate
+alias ppp-compress-26 ppp_deflate
+alias net-pf-24 pppoe
diff --git a/user/ppp/ppp.pamd b/user/ppp/ppp.pamd
new file mode 100644
index 000000000..ac86d9512
--- /dev/null
+++ b/user/ppp/ppp.pamd
@@ -0,0 +1,7 @@
+# Welcome to Adélie Linux.
+
+# This file ensures PPP uses the system-wide PAM configuration.
+
+auth include base-auth
+account include base-account
+session include base-session-noninteractive
diff --git a/user/ppp/pppd.initd b/user/ppp/pppd.initd
new file mode 100644
index 000000000..30bd641da
--- /dev/null
+++ b/user/ppp/pppd.initd
@@ -0,0 +1,13 @@
+#!/sbin/openrc-run
+
+name="pppd"
+command="/usr/sbin/${SVCNAME}"
+command_args="nodetach ${PPPD_OPTS}"
+pidfile="/var/run/$SVCNAME.pid"
+command_background=true
+
+start_pre() {
+ checkpath --directory /var/run/ppp
+ modprobe pptp
+}
+
diff --git a/user/ppp/utmpx.patch b/user/ppp/utmpx.patch
new file mode 100644
index 000000000..2914bc4be
--- /dev/null
+++ b/user/ppp/utmpx.patch
@@ -0,0 +1,142 @@
+--- ppp-2.4.7/pppd/utils.c.old 2014-08-09 12:31:39.000000000 +0000
++++ ppp-2.4.7/pppd/utils.c 2019-05-09 22:13:47.546342436 +0000
+@@ -41,7 +41,7 @@
+ #include <syslog.h>
+ #include <netdb.h>
+ #include <time.h>
+-#include <utmp.h>
++#include <utmpx.h>
+ #include <pwd.h>
+ #include <sys/param.h>
+ #include <sys/types.h>
+--- ppp-2.4.7/pppd/auth.c.old 2019-05-09 22:07:26.737835517 +0000
++++ ppp-2.4.7/pppd/auth.c 2019-05-09 22:14:11.833696617 +0000
+@@ -81,7 +81,7 @@
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <sys/socket.h>
+-#include <utmp.h>
++#include <utmpx.h>
+ #include <fcntl.h>
+ #if defined(_PATH_LASTLOG) && defined(__linux__)
+ #include <lastlog.h>
+--- ppp-2.4.7/pppd/sys-linux.c.old 2019-05-09 22:07:26.747834427 +0000
++++ ppp-2.4.7/pppd/sys-linux.c 2019-05-09 22:15:20.616203578 +0000
+@@ -85,7 +85,7 @@
+ #include <string.h>
+ #include <time.h>
+ #include <memory.h>
+-#include <utmp.h>
++#include <utmpx.h>
+ #include <mntent.h>
+ #include <signal.h>
+ #include <fcntl.h>
+@@ -2230,75 +2230,6 @@
+ * Update the wtmp file with the appropriate user name and tty device.
+ */
+
+-void logwtmp (const char *line, const char *name, const char *host)
+-{
+- struct utmp ut, *utp;
+- pid_t mypid = getpid();
+-#if __GLIBC__ < 2
+- int wtmp;
+-#endif
+-
+-/*
+- * Update the signon database for users.
+- * Christoph Lameter: Copied from poeigl-1.36 Jan 3, 1996
+- */
+- utmpname(_PATH_UTMP);
+- setutent();
+- while ((utp = getutent()) && (utp->ut_pid != mypid))
+- /* nothing */;
+-
+- if (utp)
+- memcpy(&ut, utp, sizeof(ut));
+- else
+- /* some gettys/telnetds don't initialize utmp... */
+- memset(&ut, 0, sizeof(ut));
+-
+- if (ut.ut_id[0] == 0)
+- strncpy(ut.ut_id, line + 3, sizeof(ut.ut_id));
+-
+- strncpy(ut.ut_user, name, sizeof(ut.ut_user));
+- strncpy(ut.ut_line, line, sizeof(ut.ut_line));
+-
+- time(&ut.ut_time);
+-
+- ut.ut_type = USER_PROCESS;
+- ut.ut_pid = mypid;
+-
+- /* Insert the host name if one is supplied */
+- if (*host)
+- strncpy (ut.ut_host, host, sizeof(ut.ut_host));
+-
+- /* Insert the IP address of the remote system if IP is enabled */
+- if (ipcp_protent.enabled_flag && ipcp_hisoptions[0].neg_addr)
+- memcpy(&ut.ut_addr, (char *) &ipcp_hisoptions[0].hisaddr,
+- sizeof(ut.ut_addr));
+-
+- /* CL: Makes sure that the logout works */
+- if (*host == 0 && *name==0)
+- ut.ut_host[0]=0;
+-
+- pututline(&ut);
+- endutent();
+-/*
+- * Update the wtmp file.
+- */
+-#if __GLIBC__ >= 2
+- updwtmp(_PATH_WTMP, &ut);
+-#else
+- wtmp = open(_PATH_WTMP, O_APPEND|O_WRONLY);
+- if (wtmp >= 0) {
+- flock(wtmp, LOCK_EX);
+-
+- if (write (wtmp, (char *)&ut, sizeof(ut)) != sizeof(ut))
+- warn("error writing %s: %m", _PATH_WTMP);
+-
+- flock(wtmp, LOCK_UN);
+-
+- close (wtmp);
+- }
+-#endif
+-}
+-
+
+ /********************************************************************
+ *
+--- ppp-2.4.7/pppd/tty.c.old 2014-08-09 12:31:39.000000000 +0000
++++ ppp-2.4.7/pppd/tty.c 2019-05-09 22:15:34.854652468 +0000
+@@ -81,7 +81,7 @@
+ #include <fcntl.h>
+ #include <syslog.h>
+ #include <netdb.h>
+-#include <utmp.h>
++#include <utmpx.h>
+ #include <pwd.h>
+ #include <setjmp.h>
+ #include <sys/param.h>
+--- ppp-2.4.7/pppd/session.c.old 2014-08-09 12:31:39.000000000 +0000
++++ ppp-2.4.7/pppd/session.c 2019-05-09 22:15:52.692709222 +0000
+@@ -77,7 +77,7 @@
+ #include <shadow.h>
+ #endif
+ #include <time.h>
+-#include <utmp.h>
++#include <utmpx.h>
+ #include <fcntl.h>
+ #include <unistd.h>
+ #include "pppd.h"
+--- ppp-2.4.7/pppd/main.c.old 2019-05-09 22:07:26.717837696 +0000
++++ ppp-2.4.7/pppd/main.c 2019-05-09 22:16:06.881163559 +0000
+@@ -78,7 +78,7 @@
+ #include <fcntl.h>
+ #include <syslog.h>
+ #include <netdb.h>
+-#include <utmp.h>
++#include <utmpx.h>
+ #include <pwd.h>
+ #include <setjmp.h>
+ #include <sys/param.h>