]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/auth.c
pppd.8: Document netmask option
[ppp.git] / pppd / auth.c
index ffa0e14afb097e775e18cc0257f0e56d7256d9a9..ecd30badc73978987c4be63be10233346f663c5c 100644 (file)
@@ -17,7 +17,7 @@
  * 3. Redistributions of any form whatsoever must retain the following
  *    acknowledgment:
  *    "This product includes software developed by Paul Mackerras
- *     <paulus@samba.org>".
+ *     <paulus@ozlabs.org>".
  *
  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 
 #define RCSID  "$Id: auth.c,v 1.117 2008/07/01 12:27:56 paulus Exp $"
 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
 #include <stdio.h>
 #include <stddef.h>
 #include <stdlib.h>
@@ -93,7 +97,7 @@
 #include <arpa/inet.h>
 
 
-#ifdef HAS_SHADOW
+#ifdef HAVE_SHADOW_H
 #include <shadow.h>
 #ifndef PW_PPP
 #define PW_PPP PW_LOGIN
 #endif
 #include <time.h>
 
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
 #ifdef SYSTEMD
 #include <systemd/sd-daemon.h>
 #endif
 
-#include "pppd.h"
+#include "pppd-private.h"
+#include "options.h"
 #include "fsm.h"
 #include "lcp.h"
 #include "ccp.h"
 #include "ecp.h"
 #include "ipcp.h"
 #include "upap.h"
-#include "chap-new.h"
+#include "chap.h"
 #include "eap.h"
-#ifdef USE_EAPTLS
+#ifdef PPP_WITH_EAPTLS
 #include "eap-tls.h"
 #endif
-#ifdef CBCP_SUPPORT
+#ifdef PPP_WITH_CBCP
 #include "cbcp.h"
 #endif
+#include "multilink.h"
 #include "pathnames.h"
 #include "session.h"
 
@@ -171,28 +181,26 @@ static bool default_auth;
 int (*idle_time_hook)(struct ppp_idle *) = NULL;
 
 /* Hook for a plugin to say whether we can possibly authenticate any peer */
-int (*pap_check_hook)(void) = NULL;
+pap_check_hook_fn *pap_check_hook = NULL;
 
 /* Hook for a plugin to check the PAP user and password */
-int (*pap_auth_hook)(char *user, char *passwd, char **msgp,
-                    struct wordlist **paddrs,
-                    struct wordlist **popts) = NULL;
+pap_auth_hook_fn *pap_auth_hook = NULL;
 
 /* Hook for a plugin to know about the PAP user logout */
-void (*pap_logout_hook)(void) = NULL;
+pap_logout_hook_fn *pap_logout_hook = NULL;
 
 /* Hook for a plugin to get the PAP password for authenticating us */
-int (*pap_passwd_hook)(char *user, char *passwd) = NULL;
+pap_passwd_hook_fn *pap_passwd_hook = NULL;
 
 /* Hook for a plugin to say if we can possibly authenticate a peer using CHAP */
-int (*chap_check_hook)(void) = NULL;
+chap_check_hook_fn *chap_check_hook = NULL;
 
 /* Hook for a plugin to get the CHAP password for authenticating us */
-int (*chap_passwd_hook)(char *user, char *passwd) = NULL;
+chap_passwd_hook_fn *chap_passwd_hook = NULL;
 
-#ifdef USE_EAPTLS
+#ifdef PPP_WITH_EAPTLS
 /* Hook for a plugin to get the EAP-TLS password for authenticating us */
-int (*eaptls_passwd_hook)(char *user, char *passwd) = NULL;
+eaptls_passwd_hook_fn *eaptls_passwd_hook = NULL;
 #endif
 
 /* Hook for a plugin to say whether it is OK if the peer
@@ -202,11 +210,6 @@ int (*null_auth_hook)(struct wordlist **paddrs,
 
 int (*allowed_address_hook)(u_int32_t addr) = NULL;
 
-#ifdef HAVE_MULTILINK
-/* Hook for plugin to hear when an interface joins a multilink bundle */
-void (*multilink_join_hook)(void) = NULL;
-#endif
-
 /* A notifier for when the peer has authenticated itself,
    and we are proceeding to the network phase. */
 struct notifier *auth_up_notifier = NULL;
@@ -236,7 +239,7 @@ bool cryptpap = 0;          /* Passwords in pap-secrets are encrypted */
 bool refuse_pap = 0;           /* Don't wanna auth. ourselves with PAP */
 bool refuse_chap = 0;          /* Don't wanna auth. ourselves with CHAP */
 bool refuse_eap = 0;           /* Don't wanna auth. ourselves with EAP */
-#ifdef CHAPMS
+#ifdef PPP_WITH_CHAPMS
 bool refuse_mschap = 0;                /* Don't wanna auth. ourselves with MS-CHAP */
 bool refuse_mschap_v2 = 0;     /* Don't wanna auth. ourselves with MS-CHAPv2 */
 #else
@@ -250,20 +253,25 @@ bool explicit_remote = 0; /* User specified explicit remote name */
 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 *ca_path      = NULL;     /* directory with CA certificates */
-char *cert_file    = NULL;     /* client certificate file (pem format) */
-char *privkey_file = NULL;     /* client private key file (pem format) */
-char *crl_dir      = NULL;     /* directory containing CRL files */
-char *crl_file     = NULL;     /* Certificate Revocation List (CRL) file (pem format) */
-char *max_tls_version = NULL;  /* Maximum TLS protocol version (default=1.2) */
-bool need_peer_eap = 0;                        /* Require peer to authenticate us */
+
+#if defined(PPP_WITH_EAPTLS) || defined(PPP_WITH_PEAP)
+char *cacert_file  = NULL;  /* CA certificate file (pem format) */
+char *ca_path      = NULL;  /* Directory with CA certificates */
+char *crl_dir      = NULL;  /* Directory containing CRL files */
+char *crl_file     = NULL;  /* Certificate Revocation List (CRL) file (pem format) */
+char *max_tls_version = NULL;   /* Maximum TLS protocol version (default=1.2) */
+char *tls_verify_method = NULL; /* Verify certificate method */
+bool  tls_verify_key_usage = 0; /* Verify peer certificate key usage */
 #endif
 
-static char *uafname;          /* name of most recent +ua file */
+#if defined(PPP_WITH_EAPTLS)
+char *cert_file    = NULL;  /* Client certificate file (pem format) */
+char *privkey_file = NULL;  /* Client private key file (pem format) */
+char *pkcs12_file  = NULL;  /* Client private key envelope file (pkcs12 format) */
+bool need_peer_eap = 0;            /* Require peer to authenticate us */
+#endif
 
-extern char *crypt (const char *, const char *);
+static char *uafname;          /* name of most recent +ua file */
 
 /* Prototypes for procedures local to this file. */
 
@@ -277,7 +285,7 @@ static int  have_chap_secret (char *, char *, int, int *);
 static int  have_srp_secret(char *client, char *server, int need_ip,
     int *lacks_ipp);
 
-#ifdef USE_EAPTLS
+#ifdef PPP_WITH_EAPTLS
 static int  have_eaptls_secret_server
 (char *client, char *server, int need_ip, int *lacks_ipp);
 static int  have_eaptls_secret_client (char *client, char *server);
@@ -304,15 +312,12 @@ static int  set_noauth_addr (char **);
 static int  set_permitted_number (char **);
 static void check_access (FILE *, char *);
 static int  wordlist_count (struct wordlist *);
-
-#ifdef MAXOCTETS
 static void check_maxoctets (void *);
-#endif
 
 /*
  * Authentication-related options.
  */
-option_t auth_options[] = {
+struct option auth_options[] = {
     { "auth", o_bool, &auth_required,
       "Require authentication from peer", OPT_PRIO | 1 },
     { "noauth", o_bool, &auth_required,
@@ -332,7 +337,7 @@ option_t auth_options[] = {
       "Require CHAP authentication from peer",
       OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MD5,
       &lcp_wantoptions[0].chap_mdtype },
-#ifdef CHAPMS
+#ifdef PPP_WITH_CHAPMS
     { "require-mschap", o_bool, &auth_required,
       "Require MS-CHAP authentication from peer",
       OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT,
@@ -363,7 +368,7 @@ option_t auth_options[] = {
       "Don't allow CHAP authentication with peer",
       OPT_ALIAS | OPT_A2CLRB | MDTYPE_MD5,
       &lcp_allowoptions[0].chap_mdtype },
-#ifdef CHAPMS
+#ifdef PPP_WITH_CHAPMS
     { "refuse-mschap", o_bool, &refuse_mschap,
       "Don't agree to auth to peer with MS-CHAP",
       OPT_A2CLRB | MDTYPE_MICROSOFT,
@@ -436,21 +441,59 @@ option_t auth_options[] = {
       "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" },
-    { "capath", o_string, &ca_path,   "EAP-TLS CA certificate directory" },
-    { "cert", o_string, &cert_file,   "EAP-TLS client certificate in PEM format" },
-    { "key", o_string, &privkey_file, "EAP-TLS client private key in PEM format" },
-    { "crl-dir", o_string, &crl_dir,  "Use CRLs in directory" },
-    { "crl", o_string, &crl_file,     "Use specific CRL file" },
+#if defined(PPP_WITH_EAPTLS) || defined(PPP_WITH_PEAP)
+    { "ca", o_string, &cacert_file,     "CA certificate in PEM format" },
+    { "capath", o_string, &ca_path,     "TLS CA certificate directory" },
+    { "crl-dir", o_string, &crl_dir,    "Use CRLs in directory" },
+    { "crl", o_string, &crl_file,       "Use specific CRL file" },
     { "max-tls-version", o_string, &max_tls_version,
       "Maximum TLS version (1.0/1.1/1.2 (default)/1.3)" },
+    { "tls-verify-key-usage", o_bool, &tls_verify_key_usage,
+      "Verify certificate type and extended key usage" },
+    { "tls-verify-method", o_string, &tls_verify_method,
+      "Verify peer by method (none|subject|name|suffix)" },
+#endif
+
+#if defined(PPP_WITH_EAPTLS)
+    { "cert", o_string, &cert_file,     "client certificate in PEM format" },
+    { "key", o_string, &privkey_file,   "client private key in PEM format" },
+    { "pkcs12", o_string, &pkcs12_file, "EAP-TLS client credentials in PKCS12 format" },
     { "need-peer-eap", o_bool, &need_peer_eap,
       "Require the peer to authenticate us", 1 },
-#endif /* USE_EAPTLS */
+#endif /* PPP_WITH_EAPTLS */
     { NULL }
 };
 
+const char *
+ppp_remote_name()
+{
+    return remote_name;
+}
+
+const char *
+ppp_get_remote_number(void)
+{
+    return remote_number;
+}
+
+void
+ppp_set_remote_number(const char *buf)
+{
+    if (buf) {
+        strlcpy(remote_number, buf, sizeof(remote_number));
+    }
+}
+
+const char *
+ppp_peer_authname(char *buf, size_t bufsz)
+{
+    if (buf && bufsz > 0) {
+        strlcpy(buf, peer_authname, bufsz);
+        return buf;
+    }
+    return peer_authname;
+}
+
 /*
  * setupapfile - specifies UPAP info for authenticating with peer.
  */
@@ -471,7 +514,7 @@ setupapfile(char **argv)
        novm("+ua file name");
     euid = geteuid();
     if (seteuid(getuid()) == -1) {
-       option_error("unable to reset uid before opening %s: %m", fname);
+       ppp_option_error("unable to reset uid before opening %s: %m", fname);
         free(fname);
        return 0;
     }
@@ -479,7 +522,7 @@ setupapfile(char **argv)
     if (seteuid(euid) == -1)
        fatal("unable to regain privileges: %m");
     if (ufile == NULL) {
-       option_error("unable to open user login data file %s", fname);
+       ppp_option_error("unable to open user login data file %s", fname);
         free(fname);
        return 0;
     }
@@ -490,7 +533,7 @@ setupapfile(char **argv)
     if (fgets(u, MAXNAMELEN - 1, ufile) == NULL
        || fgets(p, MAXSECRETLEN - 1, ufile) == NULL) {
        fclose(ufile);
-       option_error("unable to read user login data file %s", fname);
+       ppp_option_error("unable to read user login data file %s", fname);
         free(fname);
        return 0;
     }
@@ -529,7 +572,7 @@ privgroup(char **argv)
 
     g = getgrnam(*argv);
     if (g == 0) {
-       option_error("group %s is unknown", *argv);
+       ppp_option_error("group %s is unknown", *argv);
        return 0;
     }
     for (i = 0; i < ngroups; ++i) {
@@ -598,7 +641,7 @@ link_required(int unit)
  */
 void start_link(int unit)
 {
-    status = EXIT_CONNECT_FAILED;
+    ppp_set_status(EXIT_CONNECT_FAILED);
     new_phase(PHASE_SERIALCONN);
 
     hungup = 0;
@@ -616,7 +659,7 @@ void start_link(int unit)
      */
     fd_ppp = the_channel->establish_ppp(devfd);
     if (fd_ppp < 0) {
-       status = EXIT_FATAL_ERROR;
+       ppp_set_status(EXIT_FATAL_ERROR);
        goto disconnect;
     }
 
@@ -628,12 +671,12 @@ void start_link(int unit)
      * incoming events (reply, timeout, etc.).
      */
     if (ifunit >= 0)
-       notice("Connect: %s <--> %s", ifname, ppp_devnam);
+       notice("Connect: %s <--> %s", ifname, ppp_devname);
     else
-       notice("Starting negotiation on %s", ppp_devnam);
+       notice("Starting negotiation on %s", ppp_devname);
     add_fd(fd_ppp);
 
-    status = EXIT_NEGOTIATION_FAILED;
+    ppp_set_status(EXIT_NEGOTIATION_FAILED);
     new_phase(PHASE_ESTABLISH);
 
     lcp_lowerup(0);
@@ -657,7 +700,7 @@ void start_link(int unit)
 void
 link_terminated(int unit)
 {
-    if (phase == PHASE_DEAD || phase == PHASE_MASTER)
+    if (in_phase(PHASE_DEAD) || in_phase(PHASE_MASTER))
        return;
     new_phase(PHASE_DISCONNECT);
 
@@ -666,7 +709,7 @@ link_terminated(int unit)
     }
     session_end(devnam);
 
-    if (!doing_multilink) {
+    if (!mp_on()) {
        notice("Connection terminated.");
        print_link_stats();
     } else
@@ -677,9 +720,8 @@ link_terminated(int unit)
      * can happen that another pppd gets the same unit and then
      * we delete its pid file.
      */
-    if (!doing_multilink && !demand)
+    if (!demand && !mp_on())
        remove_pidfiles();
-
     /*
      * If we may want to bring the link up again, transfer
      * the ppp unit back to the loopback.  Set the
@@ -689,14 +731,14 @@ link_terminated(int unit)
        remove_fd(fd_ppp);
        clean_check();
        the_channel->disestablish_ppp(devfd);
-       if (doing_multilink)
+       if (mp_on())
            mp_exit_bundle();
        fd_ppp = -1;
     }
     if (!hungup)
        lcp_lowerdown(0);
-    if (!doing_multilink && !demand)
-       script_unsetenv("IFNAME");
+    if (!mp_on() && !demand)
+       ppp_script_unsetenv("IFNAME");
 
     /*
      * Run disconnector script, if requested.
@@ -709,7 +751,7 @@ link_terminated(int unit)
     if (the_channel->cleanup)
        (*the_channel->cleanup)();
 
-    if (doing_multilink && multilink_master) {
+    if (mp_on() && mp_master()) {
        if (!bundle_terminating) {
            new_phase(PHASE_MASTER);
            if (master_detach && !detached)
@@ -730,14 +772,15 @@ link_down(int unit)
        notify(link_down_notifier, 0);
        auth_state = s_down;
        if (auth_script_state == s_up && auth_script_pid == 0) {
-           update_link_stats(unit);
+           ppp_get_link_stats(NULL);
            auth_script_state = s_down;
-           auth_script(_PATH_AUTHDOWN);
+           auth_script(PPP_PATH_AUTHDOWN);
        }
     }
-    if (!doing_multilink) {
+    if (!mp_on())
+    {
        upper_layers_down(unit);
-       if (phase != PHASE_DEAD && phase != PHASE_MASTER)
+       if (!in_phase(PHASE_DEAD) && !in_phase(PHASE_MASTER))
            new_phase(PHASE_ESTABLISH);
     }
     /* XXX if doing_multilink, should do something to stop
@@ -772,7 +815,7 @@ link_established(int unit)
     lcp_options *wo = &lcp_wantoptions[unit];
     lcp_options *go = &lcp_gotoptions[unit];
     lcp_options *ho = &lcp_hisoptions[unit];
-#ifdef USE_EAPTLS
+#ifdef PPP_WITH_EAPTLS
     lcp_options *ao = &lcp_allowoptions[unit];
 #endif
     int i;
@@ -781,13 +824,11 @@ link_established(int unit)
     /*
      * Tell higher-level protocols that LCP is up.
      */
-    if (!doing_multilink) {
+    if (!mp_on())
        for (i = 0; (protp = protocols[i]) != NULL; ++i)
            if (protp->protocol != PPP_LCP && protp->enabled_flag
                && protp->lowerup != NULL)
                (*protp->lowerup)(unit);
-    }
-
     if (!auth_required && noauth_addrs != NULL)
        set_allowed_addrs(unit, NULL, NULL);
 
@@ -803,24 +844,24 @@ link_established(int unit)
            set_allowed_addrs(unit, NULL, NULL);
        } else if (!wo->neg_upap || uselogin || !null_login(unit)) {
            warn("peer refused to authenticate: terminating link");
-           status = EXIT_PEER_AUTH_FAILED;
+           ppp_set_status(EXIT_PEER_AUTH_FAILED);
            lcp_close(unit, "peer refused to authenticate");
            return;
        }
     }
 
-#ifdef USE_EAPTLS
+#ifdef PPP_WITH_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;
+       ppp_set_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;
+       ppp_set_status(EXIT_PEER_AUTH_FAILED);
        return;
     }
 #endif
@@ -876,16 +917,16 @@ network_phase(int unit)
     /*
      * If the peer had to authenticate, run the auth-up script now.
      */
+    notify(auth_up_notifier, 0);
     if (go->neg_chap || go->neg_upap || go->neg_eap) {
-       notify(auth_up_notifier, 0);
        auth_state = s_up;
        if (auth_script_state == s_down && auth_script_pid == 0) {
            auth_script_state = s_up;
-           auth_script(_PATH_AUTHUP);
+           auth_script(PPP_PATH_AUTHUP);
        }
     }
 
-#ifdef CBCP_SUPPORT
+#ifdef PPP_WITH_CBCP
     /*
      * If we negotiated callback, do it now.
      */
@@ -916,7 +957,7 @@ start_networks(int unit)
 
     new_phase(PHASE_NETWORK);
 
-#ifdef HAVE_MULTILINK
+#ifdef PPP_WITH_MULTILINK
     if (multilink) {
        if (mp_join_bundle()) {
            if (multilink_join_hook)
@@ -926,9 +967,9 @@ start_networks(int unit)
            return;
        }
     }
-#endif /* HAVE_MULTILINK */
+#endif /* PPP_WITH_MULTILINK */
 
-#ifdef PPP_FILTER
+#ifdef PPP_WITH_FILTER
     if (!demand)
        set_filters(&pass_filter, &active_filter);
 #endif
@@ -978,7 +1019,7 @@ auth_peer_fail(int unit, int protocol)
     /*
      * Authentication failure: take the link down
      */
-    status = EXIT_PEER_AUTH_FAILED;
+    ppp_set_status(EXIT_PEER_AUTH_FAILED);
     lcp_close(unit, "Authentication failed");
 }
 
@@ -998,7 +1039,7 @@ auth_peer_success(int unit, int protocol, int prot_flavor,
        case CHAP_MD5:
            bit |= CHAP_MD5_PEER;
            break;
-#ifdef CHAPMS
+#ifdef PPP_WITH_CHAPMS
        case CHAP_MICROSOFT:
            bit |= CHAP_MS_PEER;
            break;
@@ -1026,7 +1067,7 @@ auth_peer_success(int unit, int protocol, int prot_flavor,
        namelen = sizeof(peer_authname) - 1;
     BCOPY(name, peer_authname, namelen);
     peer_authname[namelen] = 0;
-    script_setenv("PEERNAME", peer_authname, 0);
+    ppp_script_setenv("PEERNAME", peer_authname, 0);
 
     /* Save the authentication method for later. */
     auth_done[unit] |= bit;
@@ -1053,7 +1094,7 @@ auth_withpeer_fail(int unit, int protocol)
      * is no point in persisting without any way to get updated
      * authentication secrets.
      */
-    status = EXIT_AUTH_TOPEER_FAILED;
+    ppp_set_status(EXIT_AUTH_TOPEER_FAILED);
     lcp_close(unit, "Failed to authenticate ourselves to peer");
 }
 
@@ -1074,7 +1115,7 @@ auth_withpeer_success(int unit, int protocol, int prot_flavor)
        case CHAP_MD5:
            bit |= CHAP_MD5_WITHPEER;
            break;
-#ifdef CHAPMS
+#ifdef PPP_WITH_CHAPMS
        case CHAP_MICROSOFT:
            bit |= CHAP_MS_WITHPEER;
            break;
@@ -1125,14 +1166,14 @@ np_up(int unit, int proto)
        /*
         * At this point we consider that the link has come up successfully.
         */
-       status = EXIT_OK;
+       ppp_set_status(EXIT_OK);
        unsuccess = 0;
        new_phase(PHASE_RUNNING);
 
        if (idle_time_hook != 0)
            tlim = (*idle_time_hook)(NULL);
        else
-           tlim = idle_time_limit;
+           tlim = ppp_get_max_idle_time();
        if (tlim > 0)
            TIMEOUT(check_idle, NULL, tlim);
 
@@ -1140,13 +1181,15 @@ np_up(int unit, int proto)
         * Set a timeout to close the connection once the maximum
         * connect time has expired.
         */
-       if (maxconnect > 0)
-           TIMEOUT(connect_time_expired, 0, maxconnect);
+       if (ppp_get_max_connect_time() > 0)
+           TIMEOUT(connect_time_expired, 0, ppp_get_max_connect_time());
 
-#ifdef MAXOCTETS
+       /*
+        * Configure a check to see if session has outlived it's limit
+        *   in terms of octets
+        */
        if (maxoctets > 0)
            TIMEOUT(check_maxoctets, NULL, maxoctets_timeout);
-#endif
 
        /*
         * Detach now, if the updetach option was given.
@@ -1173,9 +1216,7 @@ np_down(int unit, int proto)
     if (--num_np_up == 0) {
        UNTIMEOUT(check_idle, NULL);
        UNTIMEOUT(connect_time_expired, NULL);
-#ifdef MAXOCTETS
        UNTIMEOUT(check_maxoctets, NULL);
-#endif 
        new_phase(PHASE_NETWORK);
     }
 }
@@ -1192,40 +1233,46 @@ np_finished(int unit, int proto)
     }
 }
 
-#ifdef MAXOCTETS
+/*
+ * Periodic callback to check if session has reached its limit. The period defaults
+ * to 1 second and is configurable by setting "mo-timeout" in configuration
+ */
 static void
 check_maxoctets(void *arg)
 {
-    unsigned int used;
-
-    update_link_stats(ifunit);
-    link_stats_valid=0;
-    
-    switch(maxoctets_dir) {
-       case PPP_OCTETS_DIRECTION_IN:
-           used = link_stats.bytes_in;
-           break;
-       case PPP_OCTETS_DIRECTION_OUT:
-           used = link_stats.bytes_out;
-           break;
-       case PPP_OCTETS_DIRECTION_MAXOVERAL:
-       case PPP_OCTETS_DIRECTION_MAXSESSION:
-           used = (link_stats.bytes_in > link_stats.bytes_out) ? link_stats.bytes_in : link_stats.bytes_out;
-           break;
-       default:
-           used = link_stats.bytes_in+link_stats.bytes_out;
-           break;
+    unsigned int used = 0;
+    ppp_link_stats_st stats;
+
+    if (ppp_get_link_stats(&stats)) {
+        switch(maxoctets_dir) {
+            case PPP_OCTETS_DIRECTION_IN:
+                used = stats.bytes_in;
+                break;
+            case PPP_OCTETS_DIRECTION_OUT:
+                used = stats.bytes_out;
+                break;
+            case PPP_OCTETS_DIRECTION_MAXOVERAL:
+            case PPP_OCTETS_DIRECTION_MAXSESSION:
+                used = (stats.bytes_in > stats.bytes_out)
+                                ? stats.bytes_in
+                                : stats.bytes_out;
+                break;
+            default:
+                used = stats.bytes_in+stats.bytes_out;
+                break;
+        }
     }
+
     if (used > maxoctets) {
        notice("Traffic limit reached. Limit: %u Used: %u", maxoctets, used);
-       status = EXIT_TRAFFIC_LIMIT;
+       ppp_set_status(EXIT_TRAFFIC_LIMIT);
        lcp_close(0, "Traffic limit");
+       link_stats_print = 0;
        need_holdoff = 0;
     } else {
         TIMEOUT(check_maxoctets, NULL, maxoctets_timeout);
     }
 }
-#endif
 
 /*
  * check_idle - check whether the link has been idle for long
@@ -1244,12 +1291,12 @@ check_idle(void *arg)
        tlim = idle_time_hook(&idle);
     } else {
        itime = MIN(idle.xmit_idle, idle.recv_idle);
-       tlim = idle_time_limit - itime;
+       tlim = ppp_get_max_idle_time() - itime;
     }
     if (tlim <= 0) {
        /* link is idle: shut it down. */
        notice("Terminating connection due to lack of activity.");
-       status = EXIT_IDLE_TIMEOUT;
+       ppp_set_status(EXIT_IDLE_TIMEOUT);
        lcp_close(0, "Link inactive");
        need_holdoff = 0;
     } else {
@@ -1264,7 +1311,7 @@ static void
 connect_time_expired(void *arg)
 {
     info("Connect time expired");
-    status = EXIT_CONNECT_TIME;
+    ppp_set_status(EXIT_CONNECT_TIME);
     lcp_close(0, "Connect time expired");      /* Close connection */
 }
 
@@ -1280,12 +1327,20 @@ auth_check_options(void)
 
     /* Default our_name to hostname, and user to our_name */
     if (our_name[0] == 0 || usehostname)
-       strlcpy(our_name, hostname, sizeof(our_name));
+        strlcpy(our_name, hostname, sizeof(our_name));
+
     /* If a blank username was explicitly given as an option, trust
        the user and don't use our_name */
     if (user[0] == 0 && !explicit_user)
        strlcpy(user, our_name, sizeof(user));
 
+#if defined(SYSTEM_CA_PATH) && (defined(PPP_WITH_EAPTLS) || defined(PPP_WITH_PEAP))
+    /* Use system default for CA Path if not specified */
+    if (!ca_path) {
+        ca_path = SYSTEM_CA_PATH;
+    }
+#endif
+
     /*
      * If we have a default route, require the peer to authenticate
      * unless the noauth option was given or the real user is root.
@@ -1331,7 +1386,7 @@ auth_check_options(void)
                                    our_name, 1, &lacks_ip);
     }
 
-#ifdef USE_EAPTLS
+#ifdef PPP_WITH_EAPTLS
     if (!can_auth && wo->neg_eap) {
        can_auth =
            have_eaptls_secret_server((explicit_remote ? remote_name :
@@ -1342,21 +1397,21 @@ auth_check_options(void)
 
     if (auth_required && !can_auth && noauth_addrs == NULL) {
        if (default_auth) {
-           option_error(
+           ppp_option_error(
 "By default the remote system is required to authenticate itself");
-           option_error(
+           ppp_option_error(
 "(because this system has a default route to the internet)");
        } else if (explicit_remote)
-           option_error(
+           ppp_option_error(
 "The remote system (%s) is required to authenticate itself",
                         remote_name);
        else
-           option_error(
+           ppp_option_error(
 "The remote system is required to authenticate itself");
-       option_error(
+       ppp_option_error(
 "but I couldn't find any suitable secret (password) for it to use to do so.");
        if (lacks_ip)
-           option_error(
+           ppp_option_error(
 "(None of the available passwords would let it use an IP address.)");
 
        exit(1);
@@ -1394,7 +1449,7 @@ auth_reset(int unit)
        (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)
-#ifdef USE_EAPTLS
+#ifdef PPP_WITH_EAPTLS
                || have_eaptls_secret_client(user, (explicit_remote? remote_name: NULL))
 #endif
        );
@@ -1413,7 +1468,7 @@ auth_reset(int unit)
                1, NULL))) &&
        !have_srp_secret((explicit_remote? remote_name: NULL), our_name, 1,
            NULL)
-#ifdef USE_EAPTLS
+#ifdef PPP_WITH_EAPTLS
         && !have_eaptls_secret_server((explicit_remote? remote_name: NULL),
                                   our_name, 1, NULL)
 #endif
@@ -1477,7 +1532,7 @@ check_passwd(int unit,
      * Open the file of pap secrets and scan for a suitable secret
      * for authenticating this user.
      */
-    filename = _PATH_UPAPFILE;
+    filename = PPP_PATH_UPAPFILE;
     addrs = opts = NULL;
     ret = UPAP_AUTHNAK;
     f = fopen(filename, "r");
@@ -1509,8 +1564,10 @@ check_passwd(int unit,
            if (secret[0] != 0 && !login_secret) {
                /* password given in pap-secrets - must match */
                if (cryptpap || strcmp(passwd, secret) != 0) {
+#ifdef HAVE_CRYPT_H
                    char *cbuf = crypt(passwd, secret);
                    if (!cbuf || strcmp(cbuf, secret) != 0)
+#endif
                        ret = UPAP_AUTHNAK;
                }
            }
@@ -1576,7 +1633,7 @@ null_login(int unit)
      * Open the file of pap secrets and scan for a suitable secret.
      */
     if (ret <= 0) {
-       filename = _PATH_UPAPFILE;
+       filename = PPP_PATH_UPAPFILE;
        addrs = NULL;
        f = fopen(filename, "r");
        if (f == NULL)
@@ -1623,7 +1680,7 @@ get_pap_passwd(char *passwd)
            return ret;
     }
 
-    filename = _PATH_UPAPFILE;
+    filename = PPP_PATH_UPAPFILE;
     f = fopen(filename, "r");
     if (f == NULL)
        return 0;
@@ -1660,7 +1717,7 @@ have_pap_secret(int *lacks_ipp)
            return ret;
     }
 
-    filename = _PATH_UPAPFILE;
+    filename = PPP_PATH_UPAPFILE;
     f = fopen(filename, "r");
     if (f == NULL)
        return 0;
@@ -1702,7 +1759,7 @@ have_chap_secret(char *client, char *server,
        }
     }
 
-    filename = _PATH_CHAPFILE;
+    filename = PPP_PATH_CHAPFILE;
     f = fopen(filename, "r");
     if (f == NULL)
        return 0;
@@ -1740,7 +1797,7 @@ have_srp_secret(char *client, char *server, int need_ip, int *lacks_ipp)
     char *filename;
     struct wordlist *addrs;
 
-    filename = _PATH_SRPFILE;
+    filename = PPP_PATH_SRPFILE;
     f = fopen(filename, "r");
     if (f == NULL)
        return 0;
@@ -1788,7 +1845,7 @@ get_secret(int unit, char *client, char *server,
            return 0;
        }
     } else {
-       filename = _PATH_CHAPFILE;
+       filename = PPP_PATH_CHAPFILE;
        addrs = NULL;
        secbuf[0] = 0;
 
@@ -1842,7 +1899,7 @@ get_srp_secret(int unit, char *client, char *server,
     if (!am_server && passwd[0] != '\0') {
        strlcpy(secret, passwd, MAXWORDLEN);
     } else {
-       filename = _PATH_SRPFILE;
+       filename = PPP_PATH_SRPFILE;
        addrs = NULL;
 
        fp = fopen(filename, "r");
@@ -2035,7 +2092,7 @@ auth_ip_addr(int unit, u_int32_t addr)
     int ok;
 
     /* don't allow loopback or multicast address */
-    if (bad_ip_adrs(addr))
+    if (ppp_bad_ip_addr(addr))
        return 0;
 
     if (allowed_address_hook) {
@@ -2063,12 +2120,10 @@ ip_addr_check(u_int32_t addr, struct permitted_ip *addrs)
 }
 
 /*
- * bad_ip_adrs - return 1 if the IP address is one we don't want
- * to use, such as an address in the loopback net or a multicast address.
- * addr is in network byte order.
+ * Check if given addr in network byte order is in the looback network, or a multicast address.
  */
-int
-bad_ip_adrs(u_int32_t addr)
+bool
+ppp_bad_ip_addr(u_int32_t addr)
 {
     addr = ntohl(addr);
     return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET
@@ -2345,13 +2400,13 @@ auth_script_done(void *arg)
     case s_up:
        if (auth_state == s_down) {
            auth_script_state = s_down;
-           auth_script(_PATH_AUTHDOWN);
+           auth_script(PPP_PATH_AUTHDOWN);
        }
        break;
     case s_down:
        if (auth_state == s_up) {
            auth_script_state = s_up;
-           auth_script(_PATH_AUTHUP);
+           auth_script(PPP_PATH_AUTHUP);
        }
        break;
     }
@@ -2384,13 +2439,14 @@ auth_script(char *script)
     argv[3] = user_name;
     argv[4] = devnam;
     argv[5] = strspeed;
-    argv[6] = NULL;
+    argv[6] = ipparam;
+    argv[7] = NULL;
 
     auth_script_pid = run_program(script, argv, 0, auth_script_done, NULL, 0);
 }
 
 
-#ifdef USE_EAPTLS
+#ifdef PPP_WITH_EAPTLS
 static int
 have_eaptls_secret_server(char *client, char *server,
                          int need_ip, int *lacks_ipp)
@@ -2404,7 +2460,7 @@ have_eaptls_secret_server(char *client, char *server,
     char cacertfile[MAXWORDLEN];
     char pkfile[MAXWORDLEN];
 
-    filename = _PATH_EAPTLSSERVFILE;
+    filename = PPP_PATH_EAPTLSSERVFILE;
     f = fopen(filename, "r");
     if (f == NULL)
                return 0;
@@ -2458,8 +2514,10 @@ have_eaptls_secret_client(char *client, char *server)
 
        if ((cacert_file || ca_path) && cert_file && privkey_file)
                return 1;
+       if (pkcs12_file)
+               return 1;
 
-    filename = _PATH_EAPTLSCLIFILE;
+    filename = PPP_PATH_EAPTLSCLIFILE;
     f = fopen(filename, "r");
     if (f == NULL)
                return 0;
@@ -2641,7 +2699,7 @@ scan_authfile_eaptls(FILE *f, char *client, char *server,
 int
 get_eaptls_secret(int unit, char *client, char *server,
                  char *clicertfile, char *servcertfile, char *cacertfile,
-                 char *capath, char *pkfile, int am_server)
+                 char *capath, char *pkfile, char *pkcs12, int am_server)
 {
     FILE *fp;
     int ret;
@@ -2655,6 +2713,7 @@ get_eaptls_secret(int unit, char *client, char *server,
        bzero(cacertfile, MAXWORDLEN);
        bzero(capath, MAXWORDLEN);
        bzero(pkfile, MAXWORDLEN);
+       bzero(pkcs12, MAXWORDLEN);
 
        /* the ca+cert+privkey can also be specified as options */
        if (!am_server && (cacert_file || ca_path) && cert_file && privkey_file )
@@ -2666,9 +2725,17 @@ get_eaptls_secret(int unit, char *client, char *server,
                        strlcpy( capath, ca_path, MAXWORDLEN );
                strlcpy( pkfile, privkey_file, MAXWORDLEN );
        }
+    else if (!am_server && pkcs12_file)
+       {
+               strlcpy( pkcs12, pkcs12_file, MAXWORDLEN );
+               if (cacert_file)
+                       strlcpy( cacertfile, cacert_file, MAXWORDLEN );
+               if (ca_path)
+                       strlcpy( capath, ca_path, MAXWORDLEN );
+       }
        else
        {
-               filename = (am_server ? _PATH_EAPTLSSERVFILE : _PATH_EAPTLSCLIFILE);
+               filename = (am_server ? PPP_PATH_EAPTLSSERVFILE : PPP_PATH_EAPTLSCLIFILE);
                addrs = NULL;
 
                fp = fopen(filename, "r");