--- /dev/null
+diff -up ppp-2.4.4/pppd/auth.c.fd_leak ppp-2.4.4/pppd/auth.c
+--- ppp-2.4.4/pppd/auth.c.fd_leak 2006-06-18 13:26:00.000000000 +0200
++++ ppp-2.4.4/pppd/auth.c 2009-10-08 21:22:59.789547513 +0200
+@@ -428,7 +428,7 @@ setupapfile(argv)
+ option_error("unable to reset uid before opening %s: %m", fname);
+ return 0;
+ }
+- ufile = fopen(fname, "r");
++ ufile = fopen_r(fname);
+ if (seteuid(euid) == -1)
+ fatal("unable to regain privileges: %m");
+ if (ufile == NULL) {
+@@ -1414,7 +1414,7 @@ check_passwd(unit, auser, userlen, apass
+ filename = _PATH_UPAPFILE;
+ addrs = opts = NULL;
+ ret = UPAP_AUTHNAK;
+- f = fopen(filename, "r");
++ f = fopen_r(filename);
+ if (f == NULL) {
+ error("Can't open PAP password file %s: %m", filename);
+
+@@ -1511,7 +1511,7 @@ null_login(unit)
+ if (ret <= 0) {
+ filename = _PATH_UPAPFILE;
+ addrs = NULL;
+- f = fopen(filename, "r");
++ f = fopen_r(filename);
+ if (f == NULL)
+ return 0;
+ check_access(f, filename);
+@@ -1558,7 +1558,7 @@ get_pap_passwd(passwd)
+ }
+
+ filename = _PATH_UPAPFILE;
+- f = fopen(filename, "r");
++ f = fopen_r(filename);
+ if (f == NULL)
+ return 0;
+ check_access(f, filename);
+@@ -1596,7 +1596,7 @@ have_pap_secret(lacks_ipp)
+ }
+
+ filename = _PATH_UPAPFILE;
+- f = fopen(filename, "r");
++ f = fopen_r(filename);
+ if (f == NULL)
+ return 0;
+
+@@ -1641,7 +1641,7 @@ have_chap_secret(client, server, need_ip
+ }
+
+ filename = _PATH_CHAPFILE;
+- f = fopen(filename, "r");
++ f = fopen_r(filename);
+ if (f == NULL)
+ return 0;
+
+@@ -1683,7 +1683,7 @@ have_srp_secret(client, server, need_ip,
+ struct wordlist *addrs;
+
+ filename = _PATH_SRPFILE;
+- f = fopen(filename, "r");
++ f = fopen_r(filename);
+ if (f == NULL)
+ return 0;
+
+@@ -1739,7 +1739,7 @@ get_secret(unit, client, server, secret,
+ addrs = NULL;
+ secbuf[0] = 0;
+
+- f = fopen(filename, "r");
++ f = fopen_r(filename);
+ if (f == NULL) {
+ error("Can't open chap secret file %s: %m", filename);
+ return 0;
+@@ -1796,7 +1796,7 @@ get_srp_secret(unit, client, server, sec
+ filename = _PATH_SRPFILE;
+ addrs = NULL;
+
+- fp = fopen(filename, "r");
++ fp = fopen_r(filename);
+ if (fp == NULL) {
+ error("Can't open srp secret file %s: %m", filename);
+ return 0;
+@@ -2202,7 +2202,7 @@ scan_authfile(f, client, server, secret,
+ */
+ if (word[0] == '@' && word[1] == '/') {
+ strlcpy(atfile, word+1, sizeof(atfile));
+- if ((sf = fopen(atfile, "r")) == NULL) {
++ if ((sf = fopen_r(atfile)) == NULL) {
+ warn("can't open indirect secret file %s", atfile);
+ continue;
+ }
+diff -up ppp-2.4.4/pppd/eap.c.fd_leak ppp-2.4.4/pppd/eap.c
+--- ppp-2.4.4/pppd/eap.c.fd_leak 2004-11-09 23:39:25.000000000 +0100
++++ ppp-2.4.4/pppd/eap.c 2009-10-08 21:22:59.791544181 +0200
+@@ -1226,7 +1226,7 @@ mode_t modebits;
+
+ if ((path = name_of_pn_file()) == NULL)
+ return (-1);
+- fd = open(path, modebits, S_IRUSR | S_IWUSR);
++ fd = open_fd(path, modebits, S_IRUSR | S_IWUSR);
+ err = errno;
+ free(path);
+ errno = err;
+diff -up ppp-2.4.4/pppd/main.c.fd_leak ppp-2.4.4/pppd/main.c
+--- ppp-2.4.4/pppd/main.c.fd_leak 2009-10-08 21:22:59.769544859 +0200
++++ ppp-2.4.4/pppd/main.c 2009-10-08 21:30:32.356546561 +0200
+@@ -201,6 +201,8 @@ int ngroups; /* How many groups valid
+
+ static struct timeval start_time; /* Time when link was started. */
+
++static int cloexec_works; /* controlls setting FD_CLOEXEC flag up */
++
+ static struct pppd_stats old_link_stats;
+ struct pppd_stats link_stats;
+ unsigned link_connect_time;
+@@ -245,6 +247,7 @@ static void holdoff_end __P((void *));
+ static void forget_child __P((int pid, int status));
+ static int reap_kids __P((void));
+ static void childwait_end __P((void *));
++static void check_cloexec __P((int));
+
+ #ifdef USE_TDB
+ static void update_db_entry __P((void));
+@@ -419,7 +422,7 @@ main(argc, argv)
+ die(0);
+
+ /* Make sure fds 0, 1, 2 are open to somewhere. */
+- fd_devnull = open(_PATH_DEVNULL, O_RDWR);
++ fd_devnull = open_fd(_PATH_DEVNULL, O_RDWR);
+ if (fd_devnull < 0)
+ fatal("Couldn't open %s: %m", _PATH_DEVNULL);
+ while (fd_devnull <= 2) {
+@@ -865,6 +866,104 @@ holdoff_end(arg)
+ new_phase(PHASE_DORMANT);
+ }
+
++
++/*
++ * check_cloexec - checks for FD_CLOEXEC flag and adds it if necessary
++ */
++static void
++check_cloexec(int fd)
++{
++ if (cloexec_works == 0) {
++ int fl = fcntl(fd, F_GETFD);
++ cloexec_works = (fl & FD_CLOEXEC) ? 1 : -1;
++ }
++ if (cloexec_works > 0)
++ return;
++ fcntl(fd, F_SETFD, FD_CLOEXEC);
++ return;
++}
++
++/*
++ * socket_fd - create an endpoint for communication. uses FD_CLOEXEC if supported
++ */
++int
++socket_fd(int domain, int type, int protocol)
++{
++ int fd;
++
++#ifdef SOCK_CLOEXEC
++ if (cloexec_works != -1)
++ type |= SOCK_CLOEXEC;
++#endif
++ fd = socket(domain, type, protocol);
++ if (fd == -1)
++ return -1;
++ check_cloexec(fd);
++ return fd;
++}
++
++/*
++ * open_fd - open file with FD_CLOEXEC flag
++ */
++int
++open_fd(const char *path, int flags)
++{
++ int fd;
++
++#if defined(O_CLOEXEC) && defined(SOCK_CLOEXEC)
++ if (cloexec_works != -1)
++ flags |= O_CLOEXEC;
++#endif
++ fd = open(path, flags);
++ if (fd == -1)
++ return -1;
++ check_cloexec(fd);
++ return fd;
++}
++
++/*
++ * open_fd_mmode - open file with FD_CLOEXEC flag
++ */
++int
++open_fd_mode(const char *path, int flags, int mode)
++{
++ int fd;
++
++#if defined(O_CLOEXEC) && defined(SOCK_CLOEXEC)
++ if (cloexec_works != -1)
++ flags |= O_CLOEXEC;
++#endif
++ fd = open(path, flags, mode);
++ if (fd == -1)
++ return -1;
++ check_cloexec(fd);
++ return fd;
++}
++
++/*
++ * fopen_r - open file with FD_CLOEXEC flag
++ */
++FILE *
++fopen_r(const char *path)
++{
++ FILE *f;
++
++#if defined(O_CLOEXEC) && defined(SOCK_CLOEXEC)
++ if (cloexec_works != -1) {
++ f = fopen(path, "re");
++ if (f != NULL) {
++ check_cloexec(fileno(f));
++ return f;
++ }
++ }
++#endif
++ f = fopen(path, "r");
++ if (f == NULL)
++ return NULL;
++ check_cloexec(fileno(f));
++ return f;
++}
++
+ /* List of protocol names, to make our messages a little more informative. */
+ struct protocol_list {
+ u_short proto;
+@@ -1618,7 +1717,7 @@ device_script(program, in, out, dont_wai
+ if (log_to_fd >= 0)
+ errfd = log_to_fd;
+ else
+- errfd = open(_PATH_CONNERRS, O_WRONLY | O_APPEND | O_CREAT, 0600);
++ errfd = open_fd_mode(_PATH_CONNERRS, O_WRONLY | O_APPEND | O_CREAT, 0600);
+
+ ++conn_running;
+ pid = safe_fork(in, out, errfd);
+diff -up ppp-2.4.4/pppd/options.c.fd_leak ppp-2.4.4/pppd/options.c
+--- ppp-2.4.4/pppd/options.c.fd_leak 2006-06-18 13:26:00.000000000 +0200
++++ ppp-2.4.4/pppd/options.c 2009-10-08 21:22:59.797544174 +0200
+@@ -409,7 +409,7 @@ options_from_file(filename, must_exist,
+ option_error("unable to drop privileges to open %s: %m", filename);
+ return 0;
+ }
+- f = fopen(filename, "r");
++ f = fopen_r(filename);
+ err = errno;
+ if (check_prot && seteuid(euid) == -1)
+ fatal("unable to regain privileges");
+@@ -1528,9 +1528,9 @@ setlogfile(argv)
+ option_error("unable to drop permissions to open %s: %m", *argv);
+ return 0;
+ }
+- fd = open(*argv, O_WRONLY | O_APPEND | O_CREAT | O_EXCL, 0644);
++ fd = open_fd_mode(*argv, O_WRONLY | O_APPEND | O_CREAT | O_EXCL, 0644);
+ if (fd < 0 && errno == EEXIST)
+- fd = open(*argv, O_WRONLY | O_APPEND);
++ fd = open_fd(*argv, O_WRONLY | O_APPEND);
+ err = errno;
+ if (!privileged_option && seteuid(euid) == -1)
+ fatal("unable to regain privileges: %m");
+diff -up ppp-2.4.4/pppd/pppd.h.fd_leak ppp-2.4.4/pppd/pppd.h
+--- ppp-2.4.4/pppd/pppd.h.fd_leak 2005-08-26 01:59:34.000000000 +0200
++++ ppp-2.4.4/pppd/pppd.h 2009-10-08 21:22:59.800544904 +0200
+@@ -494,6 +494,10 @@ int ppp_send_config __P((int, int, u_in
+ int ppp_recv_config __P((int, int, u_int32_t, int, int));
+ const char *protocol_name __P((int));
+ void remove_pidfiles __P((void));
++int socket_fd __P((int, int, int));
++int open_fd __P((const char *, int));
++int open_fd_mode __P((const char *, int, int));
++FILE *fopen_r __P((const char *));
+ void lock_db __P((void));
+ void unlock_db __P((void));
+
+diff -up ppp-2.4.4/pppd/sys-linux.c.fd_leak ppp-2.4.4/pppd/sys-linux.c
+--- ppp-2.4.4/pppd/sys-linux.c.fd_leak 2009-10-08 21:22:59.778544744 +0200
++++ ppp-2.4.4/pppd/sys-linux.c 2009-10-08 21:22:59.803544377 +0200
+@@ -308,12 +308,12 @@ static int modify_flags(int fd, int clea
+ void sys_init(void)
+ {
+ /* Get an internet socket for doing socket ioctls. */
+- sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
++ sock_fd = socket_fd(AF_INET, SOCK_DGRAM, 0);
+ if (sock_fd < 0)
+ fatal("Couldn't create IP socket: %m(%d)", errno);
+
+ #ifdef INET6
+- sock6_fd = socket(AF_INET6, SOCK_DGRAM, 0);
++ sock6_fd = socket_fd(AF_INET6, SOCK_DGRAM, 0);
+ if (sock6_fd < 0)
+ sock6_fd = -errno; /* save errno for later */
+ #endif
+@@ -459,7 +459,7 @@ int generic_establish_ppp (int fd)
+ goto err;
+ }
+ dbglog("using channel %d", chindex);
+- fd = open("/dev/ppp", O_RDWR);
++ fd = open_fd("/dev/ppp", O_RDWR);
+ if (fd < 0) {
+ error("Couldn't reopen /dev/ppp: %m");
+ goto err;
+@@ -619,7 +619,7 @@ static int make_ppp_unit()
+ dbglog("in make_ppp_unit, already had /dev/ppp open?");
+ close(ppp_dev_fd);
+ }
+- ppp_dev_fd = open("/dev/ppp", O_RDWR);
++ ppp_dev_fd = open_fd("/dev/ppp", O_RDWR);
+ if (ppp_dev_fd < 0)
+ fatal("Couldn't open /dev/ppp: %m");
+ flags = fcntl(ppp_dev_fd, F_GETFL);
+@@ -693,7 +693,7 @@ int bundle_attach(int ifnum)
+ if (!new_style_driver)
+ return -1;
+
+- master_fd = open("/dev/ppp", O_RDWR);
++ master_fd = open_fd("/dev/ppp", O_RDWR);
+ if (master_fd < 0)
+ fatal("Couldn't open /dev/ppp: %m");
+ if (ioctl(master_fd, PPPIOCATTACH, &ifnum) < 0) {
+@@ -1412,7 +1412,7 @@ static char *path_to_procfs(const char *
+ /* Default the mount location of /proc */
+ strlcpy (proc_path, "/proc", sizeof(proc_path));
+ proc_path_len = 5;
+- fp = fopen(MOUNTED, "r");
++ fp = fopen_r(MOUNTED);
+ if (fp != NULL) {
+ while ((mntent = getmntent(fp)) != NULL) {
+ if (strcmp(mntent->mnt_type, MNTTYPE_IGNORE) == 0)
+@@ -1472,7 +1472,7 @@ static int open_route_table (void)
+ close_route_table();
+
+ path = path_to_procfs("/net/route");
+- route_fd = fopen (path, "r");
++ route_fd = fopen_r(path);
+ if (route_fd == NULL) {
+ error("can't open routing table %s: %m", path);
+ return 0;
+@@ -1713,7 +1713,7 @@ int sifproxyarp (int unit, u_int32_t his
+ if (tune_kernel) {
+ forw_path = path_to_procfs("/sys/net/ipv4/ip_forward");
+ if (forw_path != 0) {
+- int fd = open(forw_path, O_WRONLY);
++ int fd = open_fd(forw_path, O_WRONLY);
+ if (fd >= 0) {
+ if (write(fd, "1", 1) != 1)
+ error("Couldn't enable IP forwarding: %m");
+@@ -1857,7 +1857,7 @@ get_if_hwaddr(u_char *addr, char *name)
+ struct ifreq ifreq;
+ int ret, sock_fd;
+
+- sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
++ sock_fd = socket_fd(AF_INET, SOCK_DGRAM, 0);
+ if (sock_fd < 0)
+ return 0;
+ memset(&ifreq.ifr_hwaddr, 0, sizeof(struct sockaddr));
+@@ -2030,7 +2030,7 @@ int ppp_available(void)
+ sscanf(utsname.release, "%d.%d.%d", &osmaj, &osmin, &ospatch);
+ kernel_version = KVERSION(osmaj, osmin, ospatch);
+
+- fd = open("/dev/ppp", O_RDWR);
++ fd = open_fd("/dev/ppp", O_RDWR);
+ if (fd >= 0) {
+ new_style_driver = 1;
+
+@@ -2068,7 +2068,7 @@ int ppp_available(void)
+ /*
+ * Open a socket for doing the ioctl operations.
+ */
+- s = socket(AF_INET, SOCK_DGRAM, 0);
++ s = socket_fd(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0)
+ return 0;
+
+@@ -2318,7 +2318,7 @@ int sifaddr (int unit, u_int32_t our_adr
+ int fd;
+
+ path = path_to_procfs("/sys/net/ipv4/ip_dynaddr");
+- if (path != 0 && (fd = open(path, O_WRONLY)) >= 0) {
++ if (path != 0 && (fd = open_fd(path, O_WRONLY)) >= 0) {
+ if (write(fd, "1", 1) != 1)
+ error("Couldn't enable dynamic IP addressing: %m");
+ close(fd);
+@@ -2494,7 +2494,7 @@ get_pty(master_fdp, slave_fdp, slave_nam
+ /*
+ * Try the unix98 way first.
+ */
+- mfd = open("/dev/ptmx", O_RDWR);
++ mfd = open_fd("/dev/ptmx", O_RDWR);
+ if (mfd >= 0) {
+ int ptn;
+ if (ioctl(mfd, TIOCGPTN, &ptn) >= 0) {
+@@ -2505,7 +2505,7 @@ get_pty(master_fdp, slave_fdp, slave_nam
+ if (ioctl(mfd, TIOCSPTLCK, &ptn) < 0)
+ warn("Couldn't unlock pty slave %s: %m", pty_name);
+ #endif
+- if ((sfd = open(pty_name, O_RDWR | O_NOCTTY)) < 0)
++ if ((sfd = open_fd(pty_name, O_RDWR | O_NOCTTY)) < 0)
+ warn("Couldn't open pty slave %s: %m", pty_name);
+ }
+ }
+@@ -2516,10 +2516,10 @@ get_pty(master_fdp, slave_fdp, slave_nam
+ for (i = 0; i < 64; ++i) {
+ slprintf(pty_name, sizeof(pty_name), "/dev/pty%c%x",
+ 'p' + i / 16, i % 16);
+- mfd = open(pty_name, O_RDWR, 0);
++ mfd = open_fd_mode(pty_name, O_RDWR, 0);
+ if (mfd >= 0) {
+ pty_name[5] = 't';
+- sfd = open(pty_name, O_RDWR | O_NOCTTY, 0);
++ sfd = open_fd_mode(pty_name, O_RDWR | O_NOCTTY, 0);
+ if (sfd >= 0) {
+ fchown(sfd, uid, -1);
+ fchmod(sfd, S_IRUSR | S_IWUSR);
+@@ -2784,7 +2784,7 @@ ether_to_eui64(eui64_t *p_eui64)
+ int skfd;
+ const unsigned char *ptr;
+
+- skfd = socket(PF_INET6, SOCK_DGRAM, 0);
++ skfd = socket_fd(PF_INET6, SOCK_DGRAM, 0);
+ if(skfd == -1)
+ {
+ warn("could not open IPv6 socket");
+diff -up ppp-2.4.4/pppd/tdb.c.fd_leak ppp-2.4.4/pppd/tdb.c
+--- ppp-2.4.4/pppd/tdb.c.fd_leak 2004-11-13 08:13:07.000000000 +0100
++++ ppp-2.4.4/pppd/tdb.c 2009-10-08 21:22:59.806583590 +0200
+@@ -1724,7 +1724,7 @@ TDB_CONTEXT *tdb_open_ex(const char *nam
+ goto internal;
+ }
+
+- if ((tdb->fd = open(name, open_flags, mode)) == -1) {
++ if ((tdb->fd = open_fd_mode(name, open_flags, mode)) == -1) {
+ TDB_LOG((tdb, 5, "tdb_open_ex: could not open file %s: %s\n",
+ name, strerror(errno)));
+ goto fail; /* errno set by open(2) */
+@@ -1967,7 +1967,7 @@ int tdb_reopen(TDB_CONTEXT *tdb)
+ }
+ if (close(tdb->fd) != 0)
+ TDB_LOG((tdb, 0, "tdb_reopen: WARNING closing tdb->fd failed!\n"));
+- tdb->fd = open(tdb->name, tdb->open_flags & ~(O_CREAT|O_TRUNC), 0);
++ tdb->fd = open_fd_mode(tdb->name, tdb->open_flags & ~(O_CREAT|O_TRUNC), 0);
+ if (tdb->fd == -1) {
+ TDB_LOG((tdb, 0, "tdb_reopen: open failed (%s)\n", strerror(errno)));
+ goto fail;
+diff -up ppp-2.4.4/pppd/tty.c.fd_leak ppp-2.4.4/pppd/tty.c
+--- ppp-2.4.4/pppd/tty.c.fd_leak 2006-06-04 09:04:57.000000000 +0200
++++ ppp-2.4.4/pppd/tty.c 2009-10-08 21:22:59.809544300 +0200
+@@ -569,7 +569,7 @@ int connect_tty()
+ status = EXIT_OPEN_FAILED;
+ goto errret;
+ }
+- real_ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0);
++ real_ttyfd = open_fd_mode(devnam, O_NONBLOCK | O_RDWR, 0);
+ err = errno;
+ if (prio < OPRIO_ROOT && seteuid(0) == -1)
+ fatal("Unable to regain privileges");
+@@ -723,7 +723,7 @@ int connect_tty()
+ if (connector == NULL && modem && devnam[0] != 0) {
+ int i;
+ for (;;) {
+- if ((i = open(devnam, O_RDWR)) >= 0)
++ if ((i = open_fd(devnam, O_RDWR)) >= 0)
+ break;
+ if (errno != EINTR) {
+ error("Failed to reopen %s: %m", devnam);
+@@ -896,7 +896,8 @@ open_socket(dest)
+ *sep = ':';
+
+ /* get a socket and connect it to the other end */
+- sock = socket(PF_INET, SOCK_STREAM, 0);
++ //sock = socket(PF_INET, SOCK_STREAM, 0);
++ sock = socket_fd(PF_INET, SOCK_STREAM, 0);
+ if (sock < 0) {
+ error("Can't create socket: %m");
+ return -1;
+diff -up ppp-2.4.4/pppd/utils.c.fd_leak ppp-2.4.4/pppd/utils.c
+--- ppp-2.4.4/pppd/utils.c.fd_leak 2009-10-08 21:22:59.620325739 +0200
++++ ppp-2.4.4/pppd/utils.c 2009-10-08 21:22:59.811573725 +0200
+@@ -931,14 +931,14 @@ lock(dev)
+ slprintf(lock_file, sizeof(lock_file), "%s/LCK..%s", LOCK_DIR, dev);
+ #endif
+
+- while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
++ while ((fd = open_fd_mode(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
+ if (errno != EEXIST) {
+ error("Can't create lock file %s: %m", lock_file);
+ break;
+ }
+
+ /* Read the lock file to find out who has the device locked. */
+- fd = open(lock_file, O_RDONLY, 0);
++ fd = open_fd_mode(lock_file, O_RDONLY, 0);
+ if (fd < 0) {
+ if (errno == ENOENT) /* This is just a timing problem. */
+ continue;
+@@ -1017,7 +1017,7 @@ relock(pid)
+
+ if (lock_file[0] == 0)
+ return -1;
+- fd = open(lock_file, O_WRONLY, 0);
++ fd = open_fd_mode(lock_file, O_WRONLY, 0);
+ if (fd < 0) {
+ error("Couldn't reopen lock file %s: %m", lock_file);
+ lock_file[0] = 0;
+diff -up ppp-2.4.5/pppd/plugins/pppoatm/pppoatm.c.test ppp-2.4.5/pppd/plugins/pppoatm/pppoatm.c
+--- ppp-2.4.5/pppd/plugins/pppoatm/pppoatm.c.test 2010-11-16 09:56:56.083707000 +0100
++++ ppp-2.4.5/pppd/plugins/pppoatm/pppoatm.c 2010-11-16 09:56:59.382707272 +0100
+@@ -137,7 +137,11 @@ static int connect_pppoatm(void)
+
+ if (!device_got_set)
+ no_device_given_pppoatm();
++#ifdef SOCK_CLOEXEC
++ fd = socket(AF_ATMPVC, SOCK_DGRAM | SOCK_CLOEXEC, 0);
++#else
+ fd = socket(AF_ATMPVC, SOCK_DGRAM, 0);
++#endif
+ if (fd < 0)
+ fatal("failed to create socket: %m");
+ memset(&qos, 0, sizeof qos);
+diff -up ppp-2.4.5/pppd/plugins/pppol2tp/openl2tp.c.test ppp-2.4.5/pppd/plugins/pppol2tp/openl2tp.c
+--- ppp-2.4.5/pppd/plugins/pppol2tp/openl2tp.c.test 2010-11-16 09:58:17.499711288 +0100
++++ ppp-2.4.5/pppd/plugins/pppol2tp/openl2tp.c 2010-11-16 10:00:15.791706960 +0100
+@@ -83,7 +83,11 @@ static int openl2tp_client_create(void)
+ int result;
+
+ if (openl2tp_fd < 0) {
++#ifdef SOCK_CLOEXEC
++ openl2tp_fd = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
++#else
+ openl2tp_fd = socket(PF_UNIX, SOCK_DGRAM, 0);
++#endif
+ if (openl2tp_fd < 0) {
+ error("openl2tp connection create: %m");
+ return -ENOTCONN;
+diff -up ppp-2.4.5/pppd/plugins/pppol2tp/pppol2tp.c.test ppp-2.4.5/pppd/plugins/pppol2tp/pppol2tp.c
+--- ppp-2.4.5/pppd/plugins/pppol2tp/pppol2tp.c.test 2010-11-16 09:57:44.448709467 +0100
++++ ppp-2.4.5/pppd/plugins/pppol2tp/pppol2tp.c 2010-11-16 09:59:32.877707001 +0100
+@@ -208,7 +208,11 @@ static void send_config_pppol2tp(int mtu
+ struct ifreq ifr;
+ int fd;
+
++#ifdef SOCK_CLOEXEC
++ fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
++#else
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
++#endif
+ if (fd >= 0) {
+ memset (&ifr, '\0', sizeof (ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+diff -up ppp-2.4.5/pppd/plugins/rp-pppoe/if.c.test ppp-2.4.5/pppd/plugins/rp-pppoe/if.c
+--- ppp-2.4.5/pppd/plugins/rp-pppoe/if.c.test 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5/pppd/plugins/rp-pppoe/if.c 2010-11-16 09:54:03.973706239 +0100
+@@ -116,6 +116,10 @@ openInterface(char const *ifname, UINT16
+ stype = SOCK_PACKET;
+ #endif
+
++#ifdef SOCK_CLOEXEC
++ stype |= SOCK_CLOEXEC;
++#endif
++
+ if ((fd = socket(domain, stype, htons(type))) < 0) {
+ /* Give a more helpful message for the common error case */
+ if (errno == EPERM) {
+diff -up ppp-2.4.5/pppd/plugins/rp-pppoe/plugin.c.test ppp-2.4.5/pppd/plugins/rp-pppoe/plugin.c
+--- ppp-2.4.5/pppd/plugins/rp-pppoe/plugin.c.test 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5/pppd/plugins/rp-pppoe/plugin.c 2010-11-16 09:40:23.355707001 +0100
+@@ -158,7 +158,11 @@ PPPOEConnectDevice(void)
+ ppp_session_number = ntohs(conn->session);
+
+ /* Make the session socket */
++#ifdef SOCK_CLOEXEC
++ conn->sessionSocket = socket(AF_PPPOX, SOCK_STREAM | SOCK_CLOEXEC, PX_PROTO_OE);
++#else
+ conn->sessionSocket = socket(AF_PPPOX, SOCK_STREAM, PX_PROTO_OE);
++#endif
+ if (conn->sessionSocket < 0) {
+ error("Failed to create PPPoE socket: %m");
+ goto errout;
+@@ -289,7 +293,11 @@ PPPoEDevnameHook(char *cmd, char **argv,
+ }
+
+ /* Open a socket */
++#ifdef SOCK_CLOEXEC
++ if ((fd = socket(PF_PACKET, SOCK_RAW | SOCK_CLOEXEC, 0)) < 0) {
++#else
+ if ((fd = socket(PF_PACKET, SOCK_RAW, 0)) < 0) {
++#endif
+ r = 0;
+ }
+
+diff -up ppp-2.4.5/pppd/plugins/rp-pppoe/pppoe-discovery.c.test ppp-2.4.5/pppd/plugins/rp-pppoe/pppoe-discovery.c
+--- ppp-2.4.5/pppd/plugins/rp-pppoe/pppoe-discovery.c.test 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5/pppd/plugins/rp-pppoe/pppoe-discovery.c 2010-11-16 09:55:08.726707003 +0100
+@@ -121,6 +121,10 @@ openInterface(char const *ifname, UINT16
+ stype = SOCK_PACKET;
+ #endif
+
++#ifdef SOCK_CLOEXEC
++ stype |= SOCK_CLOEXEC;
++#endif
++
+ if ((fd = socket(domain, stype, htons(type))) < 0) {
+ /* Give a more helpful message for the common error case */
+ if (errno == EPERM) {
--- /dev/null
+diff -Naur ppp-2.4.5/README.eap-tls ppp-2.4.5-eaptls-mppe-0.99/README.eap-tls
+--- ppp-2.4.5/README.eap-tls 1970-01-01 01:00:00.000000000 +0100
++++ ppp-2.4.5-eaptls-mppe-0.99/README.eap-tls 2010-10-01 15:17:54.205272328 +0200
+@@ -0,0 +1,169 @@
++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-dir <dir>
++ Use CRL files from 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. Notes
++
++ This is experimental code.
++ Send suggestions and comments to Jan Just Keijser <janjust@nikhef.nl>
++
+diff -Naur ppp-2.4.5/etc.ppp/eaptls-client ppp-2.4.5-eaptls-mppe-0.99/etc.ppp/eaptls-client
+--- ppp-2.4.5/etc.ppp/eaptls-client 1970-01-01 01:00:00.000000000 +0100
++++ ppp-2.4.5-eaptls-mppe-0.99/etc.ppp/eaptls-client 2010-10-01 15:17:54.205272328 +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.5/etc.ppp/eaptls-server ppp-2.4.5-eaptls-mppe-0.99/etc.ppp/eaptls-server
+--- ppp-2.4.5/etc.ppp/eaptls-server 1970-01-01 01:00:00.000000000 +0100
++++ ppp-2.4.5-eaptls-mppe-0.99/etc.ppp/eaptls-server 2010-10-01 15:17:54.205272328 +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.5/etc.ppp/openssl.cnf ppp-2.4.5-eaptls-mppe-0.99/etc.ppp/openssl.cnf
+--- ppp-2.4.5/etc.ppp/openssl.cnf 1970-01-01 01:00:00.000000000 +0100
++++ ppp-2.4.5-eaptls-mppe-0.99/etc.ppp/openssl.cnf 2010-10-01 15:17:54.206272162 +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.5/linux/Makefile.top ppp-2.4.5-eaptls-mppe-0.99/linux/Makefile.top
+--- ppp-2.4.5/linux/Makefile.top 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5-eaptls-mppe-0.99/linux/Makefile.top 2010-10-01 15:17:54.206272162 +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.5/pppd/Makefile.linux ppp-2.4.5-eaptls-mppe-0.99/pppd/Makefile.linux
+--- ppp-2.4.5/pppd/Makefile.linux 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5-eaptls-mppe-0.99/pppd/Makefile.linux 2010-10-01 15:17:54.207272272 +0200
+@@ -73,6 +73,9 @@
+ # Enable EAP SRP-SHA1 authentication (requires libsrp)
+ #USE_SRP=y
+
++# Enable EAP-TLS authentication (requires libssl and libcurl)
++USE_EAPTLS=y
++
+ MAXOCTETS=y
+
+ INCLUDE_DIRS= -I../include
+@@ -112,6 +115,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.5/pppd/auth.c ppp-2.4.5-eaptls-mppe-0.99/pppd/auth.c
+--- ppp-2.4.5/pppd/auth.c 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5-eaptls-mppe-0.99/pppd/auth.c 2010-10-01 15:17:54.210272021 +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,13 @@
+ 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 */
++bool need_peer_eap = 0; /* Require peer to authenticate us */
++#endif
+
+ static char *uafname; /* name of most recent +ua file */
+
+@@ -254,6 +269,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 +429,14 @@
+ "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" },
++ { "need-peer-eap", o_bool, &need_peer_eap,
++ "Require the peer to authenticate us", 1 },
++#endif /* USE_EAPTLS */
+ { NULL }
+ };
+
+@@ -731,6 +767,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;
+
+@@ -765,6 +804,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) {
+@@ -1278,6 +1333,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(
+@@ -1332,7 +1396,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))
+@@ -1347,8 +1415,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;
++
+ }
+
+
+@@ -1706,6 +1780,7 @@
+ }
+
+
++
+ /*
+ * get_secret - open the CHAP secret file and return the secret
+ * for authenticating the given client on the given server.
+@@ -2358,3 +2433,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.5/pppd/ccp.c ppp-2.4.5-eaptls-mppe-0.99/pppd/ccp.c
+--- ppp-2.4.5/pppd/ccp.c 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5-eaptls-mppe-0.99/pppd/ccp.c 2010-10-01 15:17:54.211272258 +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.5/pppd/chap-md5.c ppp-2.4.5-eaptls-mppe-0.99/pppd/chap-md5.c
+--- ppp-2.4.5/pppd/chap-md5.c 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5-eaptls-mppe-0.99/pppd/chap-md5.c 2010-10-01 15:17:54.212272142 +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.5/pppd/eap-tls.c ppp-2.4.5-eaptls-mppe-0.99/pppd/eap-tls.c
+--- ppp-2.4.5/pppd/eap-tls.c 1970-01-01 01:00:00.000000000 +0100
++++ ppp-2.4.5-eaptls-mppe-0.99/pppd/eap-tls.c 2010-10-05 15:12:45.881615580 +0200
+@@ -0,0 +1,1174 @@
++/*
++ * 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
++
++/*
++ * 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;
++
++ HMAC_CTX_init(&ctx_a);
++ HMAC_CTX_init(&ctx_out);
++ 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_cleanup(&ctx_a);
++ HMAC_CTX_cleanup(&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;
++
++ prf_size = strlen(prf_label);
++
++ memcpy(p, prf_label, prf_size);
++ p += prf_size;
++
++ memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
++ p += SSL3_RANDOM_SIZE;
++ prf_size += SSL3_RANDOM_SIZE;
++
++ memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE);
++ prf_size += SSL3_RANDOM_SIZE;
++
++ PRF(s->session->master_key, s->session->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(TLSv1_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 ( 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;
++ }
++
++ SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
++ 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 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,
++ esp->es_client.ea_peer, clicertfile,
++ servcertfile, cacertfile, pkfile, 0)) {
++ error( "EAP-TLS: Cannot get secret/password for client \"%s\", server \"%s\"",
++ esp->es_client.ea_name, esp->es_client.ea_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;
++ u_char dummy[65536];
++
++ GETCHAR(flags, inp);
++ len--;
++
++ if (flags & EAP_TLS_FLAGS_LI && !ets->data) {
++
++ /*
++ * This is the first packet of a message
++ */
++
++ GETLONG(tlslen, inp);
++ len -= 4;
++
++ if (tlslen > EAP_TLS_MAX_LEN) {
++ error("Error: 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 if (flags & EAP_TLS_FLAGS_LI && ets->data) {
++ /*
++ * Non first with LI (strange...)
++ */
++
++ GETLONG(tlslen, inp);
++ len -= 4;
++
++ }
++ 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 + 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;
++
++ if(write_p)
++ strcpy(string, " -> ");
++ else
++ strcpy(string, " <- ");
++
++
++ switch(content_type) {
++
++ case SSL3_RT_ALERT:
++ strcat(string, "Alert: ");
++ code = ((const unsigned char *)buf)[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 = ((const unsigned char *)buf)[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;
++ 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.5/pppd/eap-tls.h ppp-2.4.5-eaptls-mppe-0.99/pppd/eap-tls.h
+--- ppp-2.4.5/pppd/eap-tls.h 1970-01-01 01:00:00.000000000 +0100
++++ ppp-2.4.5-eaptls-mppe-0.99/pppd/eap-tls.h 2010-10-01 15:17:54.213271816 +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.5/pppd/eap.c ppp-2.4.5-eaptls-mppe-0.99/pppd/eap.c
+--- ppp-2.4.5/pppd/eap.c 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5-eaptls-mppe-0.99/pppd/eap.c 2010-01-29 16:31:29.000000000 +0100
+@@ -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,81 @@
+ 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(SSL_is_init_finished(ets->ssl)) {
++ esp->es_server.ea_state = eapTlsRecvClient;
++ break;
++ }
++
++ if(ets->frag)
++ esp->es_server.ea_state = eapTlsRecvAck;
++ 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 +810,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 +1020,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 +1328,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 +1557,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 +1698,90 @@
+ esp->es_client.ea_namelen);
+ break;
+
++#ifdef USE_EAPTLS
++ case EAPT_TLS:
++
++ switch(esp->es_client.ea_state) {
++
++ case eapListen:
++
++ 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:
++ 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 +2063,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 +2107,60 @@
+ 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 */
++
++ 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 */
++ eaptls_receive(esp->es_server.ea_session, inp, len);
++ warn("Server authentication failed");
++ eap_send_failure(esp);
++ }
++
++ 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 +2192,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 +2410,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 +2556,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 +2623,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 +2752,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 +2872,4 @@
+
+ return (inp - pstart);
+ }
++
+diff -Naur ppp-2.4.5/pppd/eap.h ppp-2.4.5-eaptls-mppe-0.99/pppd/eap.h
+--- ppp-2.4.5/pppd/eap.h 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5-eaptls-mppe-0.99/pppd/eap.h 2010-10-01 15:17:54.214270927 +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.5/pppd/md5.c ppp-2.4.5-eaptls-mppe-0.99/pppd/md5.c
+--- ppp-2.4.5/pppd/md5.c 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5-eaptls-mppe-0.99/pppd/md5.c 2010-10-01 15:17:54.214270927 +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.5/pppd/md5.h ppp-2.4.5-eaptls-mppe-0.99/pppd/md5.h
+--- ppp-2.4.5/pppd/md5.h 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5-eaptls-mppe-0.99/pppd/md5.h 2010-10-01 15:17:54.215271014 +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.5/pppd/options.c ppp-2.4.5-eaptls-mppe-0.99/pppd/options.c
+--- ppp-2.4.5/pppd/options.c 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5-eaptls-mppe-0.99/pppd/options.c 2010-10-01 15:17:54.215271014 +0200
+@@ -119,6 +119,10 @@
+ bool dryrun; /* print out option values and exit */
+ char *domain; /* domain name set by domain option */
+ int child_wait = 5; /* # seconds to wait for children at exit */
++#ifdef USE_EAPTLS
++bool only_update_crl_server = 0; /* update server crl and exit */
++bool only_update_crl_client = 0; /* update client crl and exit */
++#endif /* USE_EAPTLS */
+
+ #ifdef MAXOCTETS
+ unsigned int maxoctets = 0; /* default - no limit */
+@@ -320,6 +324,12 @@
+ { "mo-timeout", o_int, &maxoctets_timeout,
+ "Check for traffic limit every N seconds", OPT_PRIO | OPT_LLIMIT | 1 },
+ #endif
++#ifdef USE_EAPTLS
++ { "only-update-crl-server", o_bool, &only_update_crl_server,
++ "Update server CA CRLs and exit", 1 },
++ { "only-update-crl-client", o_bool, &only_update_crl_client,
++ "Update client CA CRLs and exit", 1 },
++#endif /* USE_EAPTLS */
+
+ { NULL }
+ };
+diff -Naur ppp-2.4.5/pppd/pathnames.h ppp-2.4.5-eaptls-mppe-0.99/pppd/pathnames.h
+--- ppp-2.4.5/pppd/pathnames.h 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5-eaptls-mppe-0.99/pppd/pathnames.h 2010-10-01 15:17:54.215271014 +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.5/pppd/plugins/Makefile.linux ppp-2.4.5-eaptls-mppe-0.99/pppd/plugins/Makefile.linux
+--- ppp-2.4.5/pppd/plugins/Makefile.linux 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5-eaptls-mppe-0.99/pppd/plugins/Makefile.linux 2010-10-01 15:17:54.215271014 +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.5/pppd/plugins/passprompt.c ppp-2.4.5-eaptls-mppe-0.99/pppd/plugins/passprompt.c
+--- ppp-2.4.5/pppd/plugins/passprompt.c 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5-eaptls-mppe-0.99/pppd/plugins/passprompt.c 2010-10-01 15:17:54.215271014 +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.5/pppd/plugins/passwordfd.c ppp-2.4.5-eaptls-mppe-0.99/pppd/plugins/passwordfd.c
+--- ppp-2.4.5/pppd/plugins/passwordfd.c 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5-eaptls-mppe-0.99/pppd/plugins/passwordfd.c 2010-10-01 15:17:54.216270820 +0200
+@@ -79,4 +79,9 @@
+
+ chap_check_hook = pwfd_check;
+ chap_passwd_hook = pwfd_passwd;
++
++#ifdef USE_EAPTLS
++ eaptls_check_hook = pwfd_check;
++ eaptls_passwd_hook = pwfd_passwd;
++#endif
+ }
+diff -Naur ppp-2.4.5/pppd/pppd.h ppp-2.4.5-eaptls-mppe-0.99/pppd/pppd.h
+--- ppp-2.4.5/pppd/pppd.h 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5-eaptls-mppe-0.99/pppd/pppd.h 2010-10-01 15:17:54.216270820 +0200
+@@ -320,6 +320,10 @@
+ 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;
++#endif /* USE_EAPTLS */
++
+ #ifdef MAXOCTETS
+ extern unsigned int maxoctets; /* Maximum octetes per session (in bytes) */
+ extern int maxoctets_dir; /* Direction :
+@@ -717,6 +721,11 @@
+ extern int (*chap_passwd_hook) __P((char *user, char *passwd));
+ extern void (*multilink_join_hook) __P((void));
+
++#ifdef USE_EAPTLS
++extern int (*eaptls_check_hook) __P((void));
++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));