]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/auth.c
Minor patches as suggested by Frank Cusack <fcusack@fcusack.com> to ensure
[ppp.git] / pppd / auth.c
index 9a6bfb1a8a4a1b38c7778eeb6ed7869aac908361..a5fc1bd6bc32dfaaea6af37ada412400df08c572 100644 (file)
@@ -32,7 +32,7 @@
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
-#define RCSID  "$Id: auth.c,v 1.68 2001/03/08 05:11:10 paulus Exp $"
+#define RCSID  "$Id: auth.c,v 1.73 2002/01/22 16:02:58 dfs Exp $"
 
 #include <stdio.h>
 #include <stddef.h>
@@ -64,6 +64,7 @@
 #define PW_PPP PW_LOGIN
 #endif
 #endif
+#include <time.h>
 
 #include "pppd.h"
 #include "fsm.h"
@@ -132,6 +133,20 @@ void (*pap_logout_hook) __P((void)) = NULL;
 /* Hook for a plugin to get the PAP password for authenticating us */
 int (*pap_passwd_hook) __P((char *user, char *passwd)) = NULL;
 
+/* Hook for a plugin to say whether it is OK if the peer
+   refuses to authenticate. */
+int (*null_auth_hook) __P((struct wordlist **paddrs,
+                          struct wordlist **popts)) = NULL;
+
+int (*allowed_address_hook) __P((u_int32_t addr)) = NULL;
+
+/* A notifier for when the peer has authenticated itself,
+   and we are proceeding to the network phase. */
+struct notifier *auth_up_notifier = NULL;
+
+/* A notifier for when the link goes down. */
+struct notifier *link_down_notifier = NULL;
+
 /*
  * This is used to ensure that we don't start an auth-up/down
  * script while one is already running.
@@ -407,6 +422,7 @@ link_down(unit)
     int i;
     struct protent *protp;
 
+    notify(link_down_notifier, 0);
     auth_state = s_down;
     if (auth_script_state == s_up && auth_script_pid == 0) {
        update_link_stats(unit);
@@ -424,7 +440,7 @@ link_down(unit)
     num_np_open = 0;
     num_np_up = 0;
     if (phase != PHASE_DEAD)
-       new_phase(PHASE_TERMINATE);
+       new_phase(PHASE_ESTABLISH);
 }
 
 /*
@@ -509,6 +525,7 @@ network_phase(unit)
      * If the peer had to authenticate, run the auth-up script now.
      */
     if (go->neg_chap || go->neg_upap) {
+       notify(auth_up_notifier, 0);
        auth_state = s_up;
        if (auth_script_state == s_down && auth_script_pid == 0) {
            auth_script_state = s_up;
@@ -727,6 +744,7 @@ np_down(unit, proto)
 {
     if (--num_np_up == 0) {
        UNTIMEOUT(check_idle, NULL);
+       UNTIMEOUT(connect_time_expired, NULL);
        new_phase(PHASE_NETWORK);
     }
 }
@@ -933,6 +951,9 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg)
            BZERO(passwd, sizeof(passwd));
            if (addrs != 0)
                free_wordlist(addrs);
+           if (opts != 0) {
+               free_wordlist(opts);
+           }
            return ret? UPAP_AUTHACK: UPAP_AUTHNAK;
        }
     }
@@ -1120,7 +1141,7 @@ plogin(user, passwd, msg)
     if (pam_error == PAM_SUCCESS && !PAM_error) {    
         pam_error = pam_acct_mgmt (pamh, PAM_SILENT);
         if (pam_error == PAM_SUCCESS)
-           pam_open_session (pamh, PAM_SILENT);
+           pam_error = pam_open_session (pamh, PAM_SILENT);
     }
 
     *msg = (char *) pam_strerror (pamh, pam_error);
@@ -1250,19 +1271,29 @@ null_login(unit)
     struct wordlist *addrs, *opts;
     char secret[MAXWORDLEN];
 
+    /*
+     * Check if a plugin wants to handle this.
+     */
+    ret = -1;
+    if (null_auth_hook)
+       ret = (*null_auth_hook)(&addrs, &opts);
+
     /*
      * Open the file of pap secrets and scan for a suitable secret.
      */
-    filename = _PATH_UPAPFILE;
-    addrs = NULL;
-    f = fopen(filename, "r");
-    if (f == NULL)
-       return 0;
-    check_access(f, filename);
+    if (ret <= 0) {
+       filename = _PATH_UPAPFILE;
+       addrs = NULL;
+       f = fopen(filename, "r");
+       if (f == NULL)
+           return 0;
+       check_access(f, filename);
 
-    i = scan_authfile(f, "", our_name, secret, &addrs, &opts, filename);
-    ret = i >= 0 && secret[0] == 0;
-    BZERO(secret, sizeof(secret));
+       i = scan_authfile(f, "", our_name, secret, &addrs, &opts, filename);
+       ret = i >= 0 && secret[0] == 0;
+       BZERO(secret, sizeof(secret));
+       fclose(f);
+    }
 
     if (ret)
        set_allowed_addrs(unit, addrs, opts);
@@ -1271,7 +1302,6 @@ null_login(unit)
     if (addrs != 0)
        free_wordlist(addrs);
 
-    fclose(f);
     return ret;
 }
 
@@ -1376,6 +1406,13 @@ have_chap_secret(client, server, need_ip, lacks_ipp)
     char *filename;
     struct wordlist *addrs;
 
+    if (chap_check_hook) {
+       ret = (*chap_check_hook)();
+       if (ret >= 0) {
+           return ret;
+       }
+    }
+
     filename = _PATH_CHAPFILE;
     f = fopen(filename, "r");
     if (f == NULL)
@@ -1422,6 +1459,12 @@ get_secret(unit, client, server, secret, secret_len, am_server)
 
     if (!am_server && passwd[0] != 0) {
        strlcpy(secbuf, passwd, sizeof(secbuf));
+    } else if (!am_server && chap_passwd_hook) {
+       if ( (*chap_passwd_hook)(client, secbuf) < 0) {
+           error("Unable to obtain CHAP password for %s on %s from plugin",
+                 client, server);
+           return 0;
+       }
     } else {
        filename = _PATH_CHAPFILE;
        addrs = NULL;
@@ -1605,8 +1648,15 @@ set_allowed_addrs(unit, addrs, opts)
      * which is a single host, then use that if we find one.
      */
     if (suggested_ip != 0
-       && (wo->hisaddr == 0 || !auth_ip_addr(unit, wo->hisaddr)))
+       && (wo->hisaddr == 0 || !auth_ip_addr(unit, wo->hisaddr))) {
        wo->hisaddr = suggested_ip;
+       /*
+        * Do we insist on this address?  No, if there are other
+        * addresses authorized than the suggested one.
+        */
+       if (n > 1)
+           wo->accept_remote = 1;
+    }
 }
 
 /*
@@ -1624,11 +1674,17 @@ auth_ip_addr(unit, addr)
     if (bad_ip_adrs(addr))
        return 0;
 
+    if (allowed_address_hook) {
+       ok = allowed_address_hook(addr);
+       if (ok >= 0) return ok;
+    }
+
     if (addresses[unit] != NULL) {
        ok = ip_addr_check(addr, addresses[unit]);
        if (ok >= 0)
            return ok;
     }
+
     if (auth_required)
        return 0;               /* no addresses authorized */
     return allow_any_ip || privileged || !have_route_to(addr);