Fix long-standing bug where unix Groupcmp didn't work
[freeradius.git] / src / modules / rlm_unix / rlm_unix.c
index 995b3bb..e0ca724 100644 (file)
  *
  *   You should have received a copy of the GNU General Public License
  *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  *
- * Copyright 2000  The FreeRADIUS server project
+ * Copyright 2000,2006  The FreeRADIUS server project
  * Copyright 2000  Jeff Carneal <jeff@apex.net>
  * Copyright 2000  Alan Curry <pacman@world.std.com>
  */
-static const char rcsid[] = "$Id$";
 
-#include       "autoconf.h"
-#include       "libradius.h"
+#include       <freeradius-devel/ident.h>
+RCSID("$Id$")
+
+#include       <freeradius-devel/radiusd.h>
 
-#include       <stdlib.h>
-#include       <string.h>
 #include       <grp.h>
 #include       <pwd.h>
-#include       <sys/types.h>
 #include       <sys/stat.h>
 
 #include "config.h"
@@ -51,142 +49,24 @@ static const char rcsid[] = "$Id$";
 #  include     <siad.h>
 #endif
 
-#include       "radiusd.h"
-#include       "modules.h"
-#include       "sysutmp.h"
-#include       "cache.h"
-#include       "conffile.h"
-#include       "compat.h"
+#include       <freeradius-devel/modules.h>
+#include       <freeradius-devel/sysutmp.h>
 
 static char trans[64] =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 #define ENC(c) trans[c]
 
 struct unix_instance {
-       int cache_passwd;
-       const char *passwd_file;
-       const char *shadow_file;
-       const char *group_file;
        const char *radwtmp;
-       int usegroup;
-       struct pwcache *cache;
-       time_t cache_reload;
-       time_t next_reload;
-       time_t last_reload;
 };
 
-static CONF_PARSER module_config[] = {
-       /*
-        *      Cache the password by default.
-        */
-       { "cache",    PW_TYPE_BOOLEAN,
-         offsetof(struct unix_instance,cache_passwd), NULL, "no" },
-       { "passwd",   PW_TYPE_STRING_PTR,
-         offsetof(struct unix_instance,passwd_file), NULL,  NULL },
-       { "shadow",   PW_TYPE_STRING_PTR,
-         offsetof(struct unix_instance,shadow_file), NULL,  NULL },
-       { "group",    PW_TYPE_STRING_PTR,
-         offsetof(struct unix_instance,group_file), NULL,   NULL },
+static const CONF_PARSER module_config[] = {
        { "radwtmp",  PW_TYPE_STRING_PTR,
          offsetof(struct unix_instance,radwtmp), NULL,   "NULL" },
-       { "usegroup", PW_TYPE_BOOLEAN,
-         offsetof(struct unix_instance,usegroup), NULL,     "no" },
-       { "cache_reload", PW_TYPE_INTEGER,
-         offsetof(struct unix_instance,cache_reload), NULL, "600" },
 
        { NULL, -1, 0, NULL, NULL }             /* end the list */
 };
 
-/*
- * groupcmp is part of autz. But it uses the data from an auth instance. So
- * here is where it gets it. By default this will be the first configured
- * auth instance. That can be changed by putting "usegroup = yes" inside an
- * auth instance to explicitly bind all Group checks to it.
- */
-
-/* binds "Group=" to an instance (a particular passwd file) */
-static struct unix_instance *group_inst;
-
-/* Tells if the above binding was explicit (usegroup=yes specified in config
- * file) or not ("Group=" was bound to the first instance of rlm_unix */
-static int group_inst_explicit;
-
-#ifdef HAVE_GETSPNAM
-#if defined(M_UNIX)
-static inline const char *get_shadow_name(shadow_pwd_t *spwd) {
-       if (spwd == NULL) return NULL;
-       return (spwd->pw_name);
-}
-
-static inline const char *get_shadow_encrypted_pwd(shadow_pwd_t *spwd) {
-       if (spwd == NULL) return NULL;
-       return (spwd->pw_passwd);
-}
-#else /* M_UNIX */
-       static inline const char *get_shadow_name(shadow_pwd_t *spwd) {
-               if (spwd == NULL) return NULL;
-               return (spwd->sp_namp);
-       }
-       static inline const char *get_shadow_encrypted_pwd(shadow_pwd_t *spwd) {
-               if (spwd == NULL) return NULL;
-               return (spwd->sp_pwdp);
-       }
-#endif /* M_UNIX */
-#endif /* HAVE_GETSPNAM */
-
-static struct passwd *fgetpwnam(const char *fname, const char *name) {
-       FILE            *file = fopen(fname, "ro");
-       struct passwd   *pwd = NULL;
-
-       if(file == NULL) return NULL;
-       do {
-               pwd = fgetpwent(file);
-               if(pwd == NULL) {
-                       fclose(file);
-                       return NULL;
-               }
-       } while (strcmp(name, pwd->pw_name) != 0);
-
-       fclose(file);
-       return pwd;
-}
-
-static struct group *fgetgrnam(const char *fname, const char *name) {
-       FILE            *file = fopen(fname, "ro");
-       struct group    *grp = NULL;
-
-       if(file == NULL) return NULL;
-
-       do {
-               grp = fgetgrent(file);
-               if(grp == NULL) {
-                       fclose(file);
-                       return NULL;
-               }
-       } while(strcmp(name, grp->gr_name) != 0);
-       fclose(file);
-       return grp;
-}
-
-#ifdef HAVE_GETSPNAM
-
-static shadow_pwd_t *fgetspnam(const char *fname, const char *name) {
-       FILE            *file = fopen(fname, "ro");
-       shadow_pwd_t    *spwd = NULL;
-
-       if(file == NULL) return NULL;
-       do {
-               spwd = fgetspent(file);
-               if(spwd == NULL) {
-                       fclose(file);
-                       return NULL;
-               }
-       } while(strcmp(name, get_shadow_name(spwd)) != 0);
-       fclose(file);
-       return spwd;
-}
-
-#endif
 
 /*
  *     The Group = handler.
@@ -206,41 +86,21 @@ static int groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request,
        check_pairs = check_pairs;
        reply_pairs = reply_pairs;
 
-       if (!group_inst) {
-               radlog(L_ERR, "groupcmp: no group list known.");
-               return 1;
-       }
-
        /*
         *      No user name, doesn't compare.
         */
-       vp = pairfind(request, PW_STRIPPED_USER_NAME);
-       if (!vp) {
-               vp = pairfind(request, PW_USER_NAME);
-               if (!vp) {
-                       return -1;
-               }
+       if (!req->username) {
+               return -1;
        }
-       username = (char *)vp->strvalue;
 
-       if (group_inst->cache_passwd &&
-           (retval = H_groupcmp(group_inst->cache, check, username)) != -2)
-               return retval;
-
-       if (group_inst->passwd_file)
-               pwd = fgetpwnam(group_inst->passwd_file, username);
-       else
-               pwd = getpwnam(username);
+       pwd = getpwnam(req->username->vp_strvalue);
        if (pwd == NULL)
                return -1;
 
-       if (group_inst->group_file)
-               grp = fgetgrnam(group_inst->group_file, (char *)check->strvalue);
-       else
-               grp = getgrnam((char *)check->strvalue);
+       grp = getgrnam(check->vp_strvalue);
        if (grp == NULL)
                return -1;
-
+       
        retval = (pwd->pw_gid == grp->gr_gid) ? 0 : -1;
        if (retval < 0) {
                for (member = grp->gr_mem; *member && retval; member++) {
@@ -253,20 +113,24 @@ static int groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request,
 
 
 /*
- *     FIXME:  We really should have an 'init' which makes
- *     System auth == Unix
+ *     Detach.
  */
-static int unix_init(void)
+static int unix_detach(void *instance)
 {
-       /* FIXME - delay these until a group file has been read so we know
-        * groupcmp can actually do something */
-       paircompare_register(PW_GROUP, PW_USER_NAME, groupcmp, NULL);
-#ifdef PW_GROUP_NAME /* compat */
-       paircompare_register(PW_GROUP_NAME, PW_USER_NAME, groupcmp, NULL);
+#define inst ((struct unix_instance *)instance)
+
+       paircompare_unregister(PW_GROUP, groupcmp);
+#ifdef PW_GROUP_NAME
+       paircompare_unregister(PW_GROUP_NAME, groupcmp);
 #endif
+#undef inst
+       free(instance);
        return 0;
 }
 
+/*
+ *     Read the config
+ */
 static int unix_instantiate(CONF_SECTION *conf, void **instance)
 {
        struct unix_instance *inst;
@@ -284,234 +148,70 @@ static int unix_instantiate(CONF_SECTION *conf, void **instance)
         *      Parse the configuration, failing if we can't do so.
         */
        if (cf_section_parse(conf, inst, module_config) < 0) {
-               free(inst);
+               unix_detach(inst);
                return -1;
        }
 
-       if (inst->cache_passwd) {
-               radlog(L_INFO, "HASH:  Reinitializing hash structures "
-                       "and lists for caching...");
-               if ((inst->cache = unix_buildpwcache(inst->passwd_file,
-                                                    inst->shadow_file,
-                                                    inst->group_file))==NULL)
-                {
-                       radlog(L_ERR, "HASH:  unable to create user "
-                               "hash table.  disable caching and run debugs");
-                       if (inst->passwd_file)
-                               free((char *) inst->passwd_file);
-                       if (inst->shadow_file)
-                               free((char *) inst->shadow_file);
-                       if (inst->group_file)
-                               free((char *) inst->group_file);
-                       if (inst->radwtmp)
-                               free((char *) inst->radwtmp);
-                       free(inst);
-                       return -1;
-               }
-
-               if (inst->cache_reload) {
-                       inst->last_reload = 0;
-                       inst->next_reload = time(NULL) + inst->cache_reload;
-               }
-       } else {
-               inst->cache = NULL;
-       }
-
-       if (inst->usegroup) {
-               if (group_inst_explicit) {
-                       radlog(L_ERR, "Only one group list may be active");
-               } else {
-                       group_inst = inst;
-                       group_inst_explicit = 1;
-               }
-       } else if (!group_inst) {
-               group_inst = inst;
-       }
-#undef inst
-
-       return 0;
-}
+       /* FIXME - delay these until a group file has been read so we know
+        * groupcmp can actually do something */
+       paircompare_register(PW_GROUP, PW_USER_NAME, groupcmp, NULL);
+#ifdef PW_GROUP_NAME /* compat */
+       paircompare_register(PW_GROUP_NAME, PW_USER_NAME, groupcmp, NULL);
+#endif
 
-/*
- *     Detach.
- */
-static int unix_detach(void *instance)
-{
-#define inst ((struct unix_instance *)instance)
-       if (group_inst == inst) {
-               group_inst = NULL;
-               group_inst_explicit = 0;
-       }
-       if (inst->passwd_file)
-               free((char *) inst->passwd_file);
-       if (inst->shadow_file)
-               free((char *) inst->shadow_file);
-       if (inst->group_file)
-               free((char *) inst->group_file);
-       if (inst->radwtmp)
-               free((char *) inst->radwtmp);
-       if (inst->cache) {
-               unix_freepwcache(inst->cache);
-       }
 #undef inst
-       free(instance);
-       return 0;
-}
 
-static int unix_destroy(void)
-{
-       paircompare_unregister(PW_GROUP, groupcmp);
-#ifdef PW_GROUP_NAME
-       paircompare_unregister(PW_GROUP_NAME, groupcmp);
-#endif
        return 0;
 }
 
 
 /*
- *     Check the users password against the standard UNIX
- *     password table.
+ *     Pull the users password from where-ever, and add it to
+ *     the given vp list.
  */
-static int unix_authenticate(void *instance, REQUEST *request)
+static int unix_getpw(UNUSED void *instance, REQUEST *request,
+                     VALUE_PAIR **vp_list)
 {
-#define inst ((struct unix_instance *)instance)
-       char *name, *passwd;
-       struct passwd   *pwd;
+       const char      *name;
        const char      *encrypted_pass;
-       int             ret;
 #ifdef HAVE_GETSPNAM
-       shadow_pwd_t    *spwd = NULL;
+       struct spwd     *spwd = NULL;
 #endif
 #ifdef OSFC2
        struct pr_passwd *pr_pw;
-#endif
-#ifdef OSFSIA
-       char            *info[2];
-       char            *progname = "radius";
-       SIAENTITY       *ent = NULL;
+#else
+       struct passwd   *pwd;
 #endif
 #ifdef HAVE_GETUSERSHELL
        char            *shell;
 #endif
-
-       /* See if we should refresh the cache */
-       if (inst->cache && inst->cache_reload
-        && (inst->next_reload < request->timestamp)) {
-               /* Time to refresh, maybe ? */
-               int must_reload = 0;
-               struct stat statbuf;
-
-               DEBUG2("rlm_users : Time to refresh cache.");
-               /* Check if any of the files has changed */
-               if (inst->passwd_file
-                && (stat(inst->passwd_file, &statbuf) != -1)
-                && (statbuf.st_mtime > inst->last_reload)) {
-                       must_reload++;
-               }
-
-               if (inst->shadow_file
-                && (stat(inst->shadow_file, &statbuf) != -1)
-                && (statbuf.st_mtime > inst->last_reload)) {
-                       must_reload++;
-               }
-
-               if (inst->group_file
-                && (stat(inst->group_file, &statbuf) != -1)
-                && (statbuf.st_mtime > inst->last_reload)) {
-                       must_reload++;
-               }
-
-               if (must_reload) {
-                       /* Build a new cache to replace old one */
-                       struct pwcache *oldcache;
-                       struct pwcache *newcache = unix_buildpwcache(
-                                                       inst->passwd_file,
-                                                       inst->shadow_file,
-                                                       inst->group_file);
-
-                       if (newcache) {
-                               oldcache = inst->cache;
-                               inst->cache = newcache;
-                               unix_freepwcache(oldcache);
-
-                               inst->last_reload = time(NULL);
-                       }
-               } else {
-                       DEBUG2("rlm_users : Files were unchanged. Not reloading.");
-               }
-
-               /* Schedule next refresh */
-               inst->next_reload = time(NULL) + inst->cache_reload;
-       }
+       VALUE_PAIR      *vp;
 
        /*
         *      We can only authenticate user requests which HAVE
         *      a User-Name attribute.
         */
        if (!request->username) {
-               radlog(L_AUTH, "rlm_unix: Attribute \"User-Name\" is required for authentication.");
-               return RLM_MODULE_INVALID;
-       }
-
-       /*
-        *      We can only authenticate user requests which HAVE
-        *      a User-Password attribute.
-        */
-       if (!request->password) {
-               radlog(L_AUTH, "rlm_unix: Attribute \"User-Password\" is required for authentication.");
-               return RLM_MODULE_INVALID;
-       }
-
-       /*
-        *  Ensure that we're being passed a plain-text password,
-        *  and not anything else.
-        */
-       if (request->password->attribute != PW_PASSWORD) {
-               radlog(L_AUTH, "rlm_unix: Attribute \"User-Password\" is required for authentication.  Cannot use \"%s\".", request->password->name);
-               return RLM_MODULE_INVALID;
+               return RLM_MODULE_NOOP;
        }
 
-       name = (char *)request->username->strvalue;
-       passwd = (char *)request->password->strvalue;
-
-       if (inst->cache_passwd &&
-           (ret = H_unix_pass(inst->cache, name, passwd, &request->reply->vps)) != -2)
-               return (ret == 0) ? RLM_MODULE_OK : RLM_MODULE_REJECT;
-
-#ifdef OSFSIA
-       info[0] = progname;
-       info[1] = NULL;
-       if (sia_ses_init (&ent, 1, info, NULL, name, NULL, 0, NULL) !=
-           SIASUCCESS)
-               return RLM_MODULE_NOTFOUND;
-       if ((ret = sia_ses_authent (NULL, passwd, ent)) != SIASUCCESS) {
-               if (ret & SIASTOP)
-                       sia_ses_release (&ent);
-               return RLM_MODULE_NOTFOUND;
-       }
-       if (sia_ses_estab (NULL, ent) == SIASUCCESS) {
-               sia_ses_release (&ent);
-               return RLM_MODULE_OK;
-       }
+       name = (char *)request->username->vp_strvalue;
+       encrypted_pass = NULL;
 
-       return RLM_MODULE_NOTFOUND;
-#else /* OSFSIA */
 #ifdef OSFC2
        if ((pr_pw = getprpwnam(name)) == NULL)
                return RLM_MODULE_NOTFOUND;
        encrypted_pass = pr_pw->ufld.fd_encrypt;
-#else /* OSFC2 */
+
        /*
-        *      Get encrypted password from password file
-        *
-        *      If a password file was explicitly specified, use it,
-        *      otherwise, use the system routines to read the
-        *      system password file
+        *      Check if account is locked.
         */
-       if (inst->passwd_file != NULL) {
-               if ((pwd = fgetpwnam(inst->passwd_file, name)) == NULL)
-                       return RLM_MODULE_NOTFOUND;
-       } else if ((pwd = getpwnam(name)) == NULL) {
+       if (pr_pw->uflg.fg_lock!=1) {
+               radlog(L_AUTH, "rlm_unix: [%s]: account locked", name);
+               return RLM_MODULE_USERLOCK;
+       }
+#else /* OSFC2 */
+       if ((pwd = getpwnam(name)) == NULL) {
                return RLM_MODULE_NOTFOUND;
        }
        encrypted_pass = pwd->pw_passwd;
@@ -521,33 +221,31 @@ static int unix_authenticate(void *instance, REQUEST *request)
        /*
         *      See if there is a shadow password.
         *
-        *      If a shadow file was explicitly specified, use it,
-        *      otherwise, use the system routines to read the
-        *      system shadow file.
-        *
-        *      Also, if we explicitly specify the password file,
-        *      only query the _system_ shadow file if the encrypted
+        *      Only query the _system_ shadow file if the encrypted
         *      password from the passwd file is < 10 characters (i.e.
         *      a valid password would never crypt() to it).  This will
         *      prevents users from using NULL password fields as things
         *      stand right now.
         */
-       if (inst->shadow_file != NULL) {
-               if ((spwd = fgetspnam(inst->shadow_file, name)) != NULL)
-                       encrypted_pass = get_shadow_encrypted_pwd(spwd);
-       } else if ((encrypted_pass == NULL) || (strlen(encrypted_pass) < 10)) {
-               if ((spwd = getspnam(name)) != NULL)
-                       encrypted_pass = get_shadow_encrypted_pwd(spwd);
+       if ((encrypted_pass == NULL) || (strlen(encrypted_pass) < 10)) {
+               if ((spwd = getspnam(name)) == NULL) {
+                       return RLM_MODULE_NOTFOUND;
+               }
+               encrypted_pass = spwd->sp_pwdp;
        }
 #endif /* HAVE_GETSPNAM */
 
+/*
+ *     These require 'pwd != NULL', which isn't true on OSFC2
+ */
+#ifndef OSFC2
 #ifdef DENY_SHELL
        /*
-        *      Undocumented temporary compatibility for iphil.NET
-        *      Users with a certain shell are always denied access.
+        *      Users with a particular shell are denied access
         */
        if (strcmp(pwd->pw_shell, DENY_SHELL) == 0) {
-               radlog(L_AUTH, "rlm_unix: [%s]: invalid shell", name);
+               radlog_request(L_AUTH, 0, request,
+                              "rlm_unix: [%s]: invalid shell", name);
                return RLM_MODULE_REJECT;
        }
 #endif
@@ -565,11 +263,12 @@ static int unix_authenticate(void *instance, REQUEST *request)
        }
        endusershell();
        if (shell == NULL) {
-               radlog(L_AUTH, "rlm_unix: [%s]: invalid shell [%s]",
-                       name, pwd->pw_shell);
+               radlog_request(L_AUTH, 0, request, "[%s]: invalid shell [%s]",
+                      name, pwd->pw_shell);
                return RLM_MODULE_REJECT;
        }
 #endif
+#endif /* OSFC2 */
 
 #if defined(HAVE_GETSPNAM) && !defined(M_UNIX)
        /*
@@ -577,7 +276,7 @@ static int unix_authenticate(void *instance, REQUEST *request)
         */
        if (spwd && spwd->sp_expire > 0 &&
            (request->timestamp / 86400) > spwd->sp_expire) {
-               radlog(L_AUTH, "rlm_unix: [%s]: password has expired", name);
+               radlog_request(L_AUTH, 0, request, "[%s]: password has expired", name);
                return RLM_MODULE_REJECT;
        }
 #endif
@@ -588,39 +287,91 @@ static int unix_authenticate(void *instance, REQUEST *request)
         */
        if ((pwd->pw_expire > 0) &&
            (request->timestamp > pwd->pw_expire)) {
-               radlog(L_AUTH, "rlm_unix: [%s]: password has expired", name);
+               radlog_request(L_AUTH, 0, request, "[%s]: password has expired", name);
                return RLM_MODULE_REJECT;
        }
 #endif
 
-#ifdef OSFC2
-       /*
-        *      Check if account is locked.
-        */
-       if (pr_pw->uflg.fg_lock!=1) {
-               radlog(L_AUTH, "rlm_unix: [%s]: account locked", name);
-               return RLM_MODULE_USERLOCK;
-       }
-#endif /* OSFC2 */
-
        /*
         *      We might have a passwordless account.
+        *
+        *      FIXME: Maybe add Auth-Type := Accept?
         */
        if (encrypted_pass[0] == 0)
-               return RLM_MODULE_OK;
+               return RLM_MODULE_NOOP;
+
+       vp = pairmake("Crypt-Password", encrypted_pass, T_OP_SET);
+       if (!vp) return RLM_MODULE_FAIL;
+
+       pairmove(vp_list, &vp);
+       pairfree(&vp);          /* might not be NULL; */
+
+       return RLM_MODULE_UPDATED;
+}
+
+
+/*
+ *     Pull the users password from where-ever, and add it to
+ *     the given vp list.
+ */
+static int unix_authorize(void *instance, REQUEST *request)
+{
+       return unix_getpw(instance, request, &request->config_items);
+}
+
+/*
+ *     Pull the users password from where-ever, and add it to
+ *     the given vp list.
+ */
+static int unix_authenticate(void *instance, REQUEST *request)
+{
+#ifdef OSFSIA
+       char            *info[2];
+       char            *progname = "radius";
+       SIAENTITY       *ent = NULL;
+
+       info[0] = progname;
+       info[1] = NULL;
+       if (sia_ses_init (&ent, 1, info, NULL, name, NULL, 0, NULL) !=
+           SIASUCCESS)
+               return RLM_MODULE_NOTFOUND;
+       if ((ret = sia_ses_authent (NULL, passwd, ent)) != SIASUCCESS) {
+               if (ret & SIASTOP)
+                       sia_ses_release (&ent);
+               return RLM_MODULE_NOTFOUND;
+       }
+       if (sia_ses_estab (NULL, ent) != SIASUCCESS) {
+               sia_ses_release (&ent);
+               return RLM_MODULE_NOTFOUND;
+       }
+#else  /* OSFSIA */
+       int rcode;
+       VALUE_PAIR *vp = NULL;
+
+       if (!request->password ||
+           (request->password->attribute != PW_USER_PASSWORD)) {
+               radlog_request(L_AUTH, 0, request, "Attribute \"User-Password\" is required for authentication.");
+               return RLM_MODULE_INVALID;
+       }
+
+       rcode = unix_getpw(instance, request, &vp);
+       if (rcode != RLM_MODULE_UPDATED) return rcode;
 
        /*
-        *      Check encrypted password.
+        *      0 means "ok"
         */
-       if (lrad_crypt_check(passwd, encrypted_pass)) {
-               radlog(L_AUTH, "rlm_unix: [%s]: invalid password", name);
+       if (fr_crypt_check((char *) request->password->vp_strvalue,
+                            (char *) vp->vp_strvalue) != 0) {
+               radlog_request(L_AUTH, 0, request, "invalid password \"%s\"",
+                              request->username->vp_strvalue);
                return RLM_MODULE_REJECT;
        }
+#endif /* OSFFIA */
+
        return RLM_MODULE_OK;
-#endif /* OSFSIA */
-#undef inst
 }
 
+
 /*
  *     UUencode 4 bits base64. We use this to turn a 4 byte field
  *     (an IP address) into 6 bytes of ASCII. This is used for the
@@ -656,7 +407,6 @@ static char *uue(void *in)
 static int unix_accounting(void *instance, REQUEST *request)
 {
        VALUE_PAIR      *vp;
-       RADCLIENT       *cl;
        FILE            *fp;
        struct utmp     ut;
        time_t          t;
@@ -666,28 +416,34 @@ static int unix_accounting(void *instance, REQUEST *request)
        int             status = -1;
        int             nas_address = 0;
        int             framed_address = 0;
+#ifdef USER_PROCESS
        int             protocol = -1;
+#endif
        int             nas_port = 0;
        int             port_seen = 0;
-       int             nas_port_type = 0;
        struct unix_instance *inst = (struct unix_instance *) instance;
 
        /*
         *      No radwtmp.  Don't do anything.
         */
        if (!inst->radwtmp) {
-               DEBUG2("rlm_unix: No radwtmp file configured.  Ignoring accounting request.");
+               RDEBUG2("No radwtmp file configured.  Ignoring accounting request.");
+               return RLM_MODULE_NOOP;
+       }
+
+       if (request->packet->src_ipaddr.af != AF_INET) {
+               RDEBUG2("IPv6 is not supported!");
                return RLM_MODULE_NOOP;
        }
 
        /*
         *      Which type is this.
         */
-       if ((vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE))==NULL) {
+       if ((vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0))==NULL) {
                radlog(L_ERR, "rlm_unix: no Accounting-Status-Type attribute in request.");
                return RLM_MODULE_NOOP;
        }
-       status = vp->lvalue;
+       status = vp->vp_integer;
 
        /*
         *      FIXME: handle PW_STATUS_ALIVE like 1.5.4.3 did.
@@ -700,7 +456,7 @@ static int unix_accounting(void *instance, REQUEST *request)
         *      We're only interested in accounting messages
         *      with a username in it.
         */
-       if ((vp = pairfind(request->packet->vps, PW_USER_NAME)) == NULL)
+       if (pairfind(request->packet->vps, PW_USER_NAME, 0) == NULL)
                return RLM_MODULE_NOOP;
 
        t = request->timestamp;
@@ -713,30 +469,29 @@ static int unix_accounting(void *instance, REQUEST *request)
                switch (vp->attribute) {
                        case PW_USER_NAME:
                                if (vp->length >= sizeof(ut.ut_name)) {
-                                       memcpy(ut.ut_name, (char *)vp->strvalue, sizeof(ut.ut_name));
+                                       memcpy(ut.ut_name, (char *)vp->vp_strvalue, sizeof(ut.ut_name));
                                } else {
-                                       strNcpy(ut.ut_name, (char *)vp->strvalue, sizeof(ut.ut_name));
+                                       strlcpy(ut.ut_name, (char *)vp->vp_strvalue, sizeof(ut.ut_name));
                                }
                                break;
                        case PW_LOGIN_IP_HOST:
                        case PW_FRAMED_IP_ADDRESS:
-                               framed_address = vp->lvalue;
+                               framed_address = vp->vp_ipaddr;
                                break;
+#ifdef USER_PROCESS
                        case PW_FRAMED_PROTOCOL:
-                               protocol = vp->lvalue;
+                               protocol = vp->vp_integer;
                                break;
+#endif
                        case PW_NAS_IP_ADDRESS:
-                               nas_address = vp->lvalue;
+                               nas_address = vp->vp_ipaddr;
                                break;
                        case PW_NAS_PORT:
-                               nas_port = vp->lvalue;
+                               nas_port = vp->vp_integer;
                                port_seen = 1;
                                break;
                        case PW_ACCT_DELAY_TIME:
-                               delay = vp->lvalue;
-                               break;
-                       case PW_NAS_PORT_TYPE:
-                               nas_port_type = vp->lvalue;
+                               delay = vp->vp_ipaddr;
                                break;
                }
        }
@@ -752,8 +507,11 @@ static int unix_accounting(void *instance, REQUEST *request)
         *      If we didn't find out the NAS address, use the
         *      originator's IP address.
         */
-       if (nas_address == 0)
-               nas_address = request->packet->src_ipaddr;
+       if (nas_address == 0) {
+               nas_address = request->packet->src_ipaddr.ipaddr.ip4addr.s_addr;
+       }
+       s = request->client->shortname;
+       if (!s || s[0] == 0) s = uue(&(nas_address));
 
 #ifdef __linux__
        /*
@@ -765,12 +523,8 @@ static int unix_accounting(void *instance, REQUEST *request)
         *      We use the tty field to store the terminal servers' port
         *      and address so that the tty field is unique.
         */
-       s = "";
-       if ((cl = client_find(nas_address)) != NULL)
-               s = cl->shortname;
-       if (s == NULL || s[0] == 0) s = uue(&(nas_address));
-       sprintf(buf, "%03d:%s", nas_port, s);
-       strNcpy(ut.ut_line, buf, sizeof(ut.ut_line));
+       snprintf(buf, sizeof(buf), "%03d:%s", nas_port, s);
+       strlcpy(ut.ut_line, buf, sizeof(ut.ut_line));
 
        /*
         *      We store the dynamic IP address in the hostname field.
@@ -778,7 +532,7 @@ static int unix_accounting(void *instance, REQUEST *request)
 #ifdef UT_HOSTSIZE
        if (framed_address) {
                ip_ntoa(buf, framed_address);
-               strncpy(ut.ut_host, buf, sizeof(ut.ut_host));
+               strlcpy(ut.ut_host, buf, sizeof(ut.ut_host));
        }
 #endif
 #ifdef HAVE_UTMPX_H
@@ -823,21 +577,19 @@ static int unix_accounting(void *instance, REQUEST *request)
 
 /* globally exported name */
 module_t rlm_unix = {
-  "System",
-  RLM_TYPE_THREAD_UNSAFE,        /* type: reserved */
-  unix_init,                    /* initialization */
-  unix_instantiate,            /* instantiation */
-  {
-         unix_authenticate,    /* authentication */
-         NULL,                 /* authorization */
-         NULL,                 /* preaccounting */
-         unix_accounting,      /* accounting */
-         NULL,                  /* checksimul */
-         NULL,                 /* pre-proxy */
-         NULL,                 /* post-proxy */
-         NULL                  /* post-auth */
-  },
-  unix_detach,                         /* detach */
-  unix_destroy,                  /* destroy */
+       RLM_MODULE_INIT,
+       "System",
+       RLM_TYPE_THREAD_UNSAFE | RLM_TYPE_CHECK_CONFIG_SAFE,
+       unix_instantiate,               /* instantiation */
+       unix_detach,                    /* detach */
+       {
+               unix_authenticate,    /* authentication */
+               unix_authorize,       /* authorization */
+               NULL,                 /* preaccounting */
+               unix_accounting,      /* accounting */
+               NULL,                  /* checksimul */
+               NULL,                   /* pre-proxy */
+               NULL,                   /* post-proxy */
+               NULL                    /* post-auth */
+       },
 };
-