Fix stupid redundant getgr* and getpw* functions
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Sun, 18 Jan 2015 12:32:01 +0000 (19:32 +0700)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Sun, 18 Jan 2015 13:45:36 +0000 (20:45 +0700)
We will *always* have the _r variants, and we should always have the headers. There's no need to check, there's no need to fallback.

src/include/radiusd.h
src/lib/misc.c
src/main/command.c
src/main/mainconfig.c
src/main/radwho.c
src/main/util.c
src/modules/rlm_detail/rlm_detail.c
src/modules/rlm_linelog/rlm_linelog.c
src/modules/rlm_opendirectory/rlm_opendirectory.c
src/modules/rlm_unix/rlm_unix.c

index 1a628fd..1cacad9 100644 (file)
@@ -64,9 +64,11 @@ typedef struct rad_request REQUEST;
 #include <freeradius-devel/tmpl.h>
 #include <freeradius-devel/map.h>
 
-#ifdef HAVE_GRP_H
+/*
+ *     All POSIX systems should have these headers
+ */
+#include <pwd.h>
 #include <grp.h>
-#endif
 
 #ifdef __cplusplus
 extern "C" {
@@ -567,9 +569,11 @@ int                rad_expand_xlat(REQUEST *request, char const *cmd,
                                size_t argv_buflen, char *argv_buf);
 
 void           verify_request(char const *file, int line, REQUEST *request);   /* only for special debug builds */
-#ifdef HAVE_GRP_H
-bool           fr_getgid(char const *name, gid_t *gid);
-#endif
+int            rad_getpwuid(TALLOC_CTX *ctx, struct passwd **out, uid_t uid);
+int            rad_getpwnam(TALLOC_CTX *ctx, struct passwd **out, char const *name);
+int            rad_getgrgid(TALLOC_CTX *ctx, struct group **out, gid_t gid);
+int            rad_getgrnam(TALLOC_CTX *ctx, struct group **out, char const *name);
+int            rad_getgid(TALLOC_CTX *ctx, gid_t *out, char const *name);
 
 /* regex.c */
 
index b61caf9..729a5b4 100644 (file)
 
 RCSID("$Id$")
 
-#include       <freeradius-devel/libradius.h>
+#include <freeradius-devel/libradius.h>
 
-#include       <ctype.h>
-#include       <sys/file.h>
-#include       <fcntl.h>
+#include <ctype.h>
+#include <sys/file.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <pwd.h>
 
 #define FR_PUT_LE16(a, val)\
        do {\
index c9e22dd..d2aac19 100644 (file)
 #include <sys/stat.h>
 #endif
 
-#ifdef HAVE_PWD_H
 #include <pwd.h>
-#endif
-
-#ifdef HAVE_GRP_H
 #include <grp.h>
-#endif
 
 typedef struct fr_command_table_t fr_command_table_t;
 
@@ -2140,31 +2135,20 @@ static int command_socket_parse_unix(CONF_SECTION *cs, rad_listen_t *this)
 #if defined(HAVE_GETPEEREID) || defined (SO_PEERCRED)
        if (sock->uid_name) {
                struct passwd *pwd;
-#ifdef HAVE_GETPWNAM_R
-               struct passwd my_pwd;
-               char pwd_buffer[1024];
 
-               if (getpwnam_r(sock->uid_name, &my_pwd, pwd_buffer, sizeof(pwd_buffer), &pwd) != 0) {
-                       pwd = NULL;
-               }
-#else
-               pwd = getpwnam(sock->uid_name);
-#endif
-               if (!pwd) {
-                       ERROR("Failed getting uid for %s: %s",
-                              sock->uid_name, fr_syserror(errno));
+               if (rad_getpwnam(cs, &pwd, sock->uid_name) < 0) {
+                       ERROR("Failed getting uid for %s: %s", sock->uid_name, fr_strerror());
                        return -1;
                }
-
                sock->uid = pwd->pw_uid;
+               talloc_free(pwd);
        } else {
                sock->uid = -1;
        }
 
        if (sock->gid_name) {
-               if (!fr_getgid(sock->gid_name, &sock->gid)) {
-                       ERROR("Failed getting gid for %s: %s",
-                             sock->gid_name, fr_syserror(errno));
+               if (rad_getgid(cs, &sock->gid, sock->gid_name) < 0) {
+                       ERROR("Failed getting gid for %s: %s", sock->gid_name, fr_strerror());
                        return -1;
                }
        } else {
index 5bd1a33..25e6141 100644 (file)
@@ -28,23 +28,13 @@ RCSID("$Id$")
 #include <freeradius-devel/rad_assert.h>
 
 #include <sys/stat.h>
-
-#ifdef HAVE_PWD_H
-#  include <pwd.h>
-#endif
-
-#ifdef HAVE_GRP_H
-#  include <grp.h>
-#endif
+#include <pwd.h>
+#include <grp.h>
 
 #ifdef HAVE_SYSLOG_H
 #  include <syslog.h>
 #endif
 
-#ifdef HAVE_SYS_STAT_H
-#  include <sys/stat.h>
-#endif
-
 #ifdef HAVE_FCNTL_H
 #  include <fcntl.h>
 #endif
@@ -556,35 +546,34 @@ static int switch_users(CONF_SECTION *cs)
        }
 #endif
 
-#ifdef HAVE_PWD_H
        /*  Set UID.  */
        if (uid_name) {
-               struct passwd *pw;
+               struct passwd *user;
 
-               pw = getpwnam(uid_name);
-               if (pw == NULL) {
+               if (rad_getpwnam(cs, &user, uid_name) < 0) {
                        fprintf(stderr, "%s: Cannot get passwd entry for user %s: %s\n",
-                               progname, uid_name, fr_syserror(errno));
+                               progname, uid_name, fr_strerror());
                        return 0;
                }
 
-               if (getuid() == pw->pw_uid) {
+               if (getuid() == user->pw_uid) {
                        uid_name = NULL;
                } else {
 
-                       server_uid = pw->pw_uid;
+                       server_uid = user->pw_uid;
 #ifdef HAVE_INITGROUPS
                        if (initgroups(uid_name, server_gid) < 0) {
                                fprintf(stderr, "%s: Cannot initialize supplementary group list for user %s: %s\n",
                                        progname, uid_name, fr_syserror(errno));
+                               talloc_free(user);
                                return 0;
                        }
 #endif
                }
+               talloc_free(user);
        } else {
                server_uid = getuid();
        }
-#endif
 
        if (chroot_dir) {
                if (chroot(chroot_dir) < 0) {
index 302a404..51b4657 100644 (file)
@@ -28,12 +28,8 @@ RCSID("$Id$")
 #include <freeradius-devel/sysutmp.h>
 #include <freeradius-devel/radutmp.h>
 
-#ifdef HAVE_PWD_H
 #include <pwd.h>
-#endif
-
 #include <sys/stat.h>
-
 #include <ctype.h>
 
 /*
index 2358a29..68015e7 100644 (file)
@@ -1023,50 +1023,270 @@ void verify_request(char const *file, int line, REQUEST *request)
 }
 #endif
 
-#ifdef HAVE_GRP_H
-#ifndef HAVE_GETGRNAM_R
-bool fr_getgid(char const *name, gid_t *gid)
+/** Resolve a uid to a passwd entry
+ *
+ * Resolves a uid to a passwd entry. The memory to hold the
+ * passwd entry is talloced under ctx, and must be freed when no
+ * longer required.
+ *
+ * @param ctx to allocate passwd entry in.
+ * @param out Where to write pointer to entry.
+ * @param uid to resolve.
+ * @return 0 on success, -1 on error.
+ */
+int rad_getpwuid(TALLOC_CTX *ctx, struct passwd **out, uid_t uid)
 {
-       struct group *grp;
+       static size_t len;
+       uint8_t *buff;
+       int ret;
 
-       grp =  getgrnam(name);
-       if (!grp) return false;
+       *out = NULL;
 
-       *gid = grp->gr_gid;
+       /*
+        *      We assume this won't change between calls,
+        *      and that the value is the same, so races don't
+        *      matter.
+        */
+       if (len == 0) {
+               long int sc_len;
 
-       return true;
+#ifdef _SC_GETPW_R_SIZE_MAX
+               sc_len = sysconf(_SC_GETPW_R_SIZE_MAX);
+#endif
+               if (sc_len <= 0) sc_len = 1024;
+               len = (size_t)sc_len;
+       }
+
+       buff = talloc_array(ctx, uint8_t, sizeof(struct passwd) + len);
+       if (!buff) return -1;
+
+       /*
+        *      In some cases we may need to dynamically
+        *      grow the string buffer.
+        */
+       while ((ret = getpwuid_r(uid, (struct passwd *)buff, (char *)(buff + sizeof(struct passwd)),
+                                talloc_array_length(buff) - sizeof(struct passwd), out)) == ERANGE) {
+               buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2);
+               if (!buff) {
+                       talloc_free(buff);
+                       return -1;
+               }
+       }
+
+       if (ret != 0) {
+               fr_strerror_printf("Failed resolving UID: %s", fr_syserror(ret));
+               talloc_free(buff);
+               errno = ret;
+               return -1;
+       }
+
+       talloc_set_type(buff, struct group);
+
+       return 0;
 }
-#else  /* getgrnam_r() exists */
 
-bool fr_getgid(char const *name, gid_t *gid)
+/** Resolve a username to a passwd entry
+ *
+ * Resolves a username to a passwd entry. The memory to hold the
+ * passwd entry is talloced under ctx, and must be freed when no
+ * longer required.
+ *
+ * @param ctx to allocate passwd entry in.
+ * @param out Where to write pointer to entry.
+ * @param name to resolve.
+ * @return 0 on success, -1 on error.
+ */
+int rad_getpwnam(TALLOC_CTX *ctx, struct passwd **out, char const *name)
 {
-       struct group    *grp, my_group;
-       char            *group_buffer;
-       size_t          group_size = 1024;
-
-       grp = NULL;
-       group_buffer = talloc_array(NULL, char, group_size);
-       while (group_buffer) {
-               int err;
-
-               err = getgrnam_r(name, &my_group, group_buffer, group_size, &grp);
-               if (err == ERANGE) {
-                       group_size *= 2;
-                       group_buffer = talloc_realloc(NULL, group_buffer, char, group_size);
-                       continue;
+       static size_t len;
+       uint8_t *buff;
+       int ret;
+
+       *out = NULL;
+
+       /*
+        *      We assume this won't change between calls,
+        *      and that the value is the same, so races don't
+        *      matter.
+        */
+       if (len == 0) {
+               long int sc_len;
+
+#ifdef _SC_GETPW_R_SIZE_MAX
+               sc_len = sysconf(_SC_GETPW_R_SIZE_MAX);
+#endif
+               if (sc_len <= 0) sc_len = 1024;
+               len = (size_t)sc_len;
+       }
+
+       buff = talloc_array(ctx, uint8_t, sizeof(struct passwd) + len);
+       if (!buff) return -1;
+
+       /*
+        *      In some cases we may need to dynamically
+        *      grow the string buffer.
+        */
+       while ((ret = getpwnam_r(name, (struct passwd *)buff, (char *)(buff + sizeof(struct passwd)),
+                                talloc_array_length(buff) - sizeof(struct passwd), out)) == ERANGE) {
+               buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2);
+               if (!buff) {
+                       talloc_free(buff);
+                       return -1;
                }
+       }
+
+       if (ret != 0) {
+               fr_strerror_printf("Failed resolving UID: %s", fr_syserror(ret));
+               talloc_free(buff);
+               errno = ret;
+               return -1;
+       }
+
+       talloc_set_type(buff, struct group);
+
+       return 0;
+}
+
+/** Resolve a gid to a group database entry
+ *
+ * Resolves a gid to a group database entry. The memory to hold the
+ * group entry is talloced under ctx, and must be freed when no
+ * longer required.
+ *
+ * @param ctx to allocate passwd entry in.
+ * @param out Where to write pointer to entry.
+ * @param gid to resolve.
+ * @return 0 on success, -1 on error.
+ */
+int rad_getgrgid(TALLOC_CTX *ctx, struct group **out, gid_t gid)
+{
+       static size_t len;
+       uint8_t *buff;
+       int ret;
 
-               if (err) errno = err; /* so the caller knows what went wrong */
+       *out = NULL;
 
-               break;
+       /*
+        *      We assume this won't change between calls,
+        *      and that the value is the same, so races don't
+        *      matter.
+        */
+       if (len == 0) {
+               long int sc_len;
+
+#ifdef _SC_GETGR_R_SIZE_MAX
+               sc_len = sysconf(_SC_GETGR_R_SIZE_MAX);
+#endif
+               if (sc_len <= 0) sc_len = 1024;
+               len = (size_t)sc_len;
+       }
+
+       buff = talloc_array(ctx, uint8_t, sizeof(struct group) + len);
+       if (!buff) return -1;
+
+       /*
+        *      In some cases we may need to dynamically
+        *      grow the string buffer.
+        */
+       while ((ret = getgrgid_r(gid, (struct group *)buff, (char *)(buff + sizeof(struct group)),
+                                talloc_array_length(buff) - sizeof(struct group), out)) == ERANGE) {
+               buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2);
+               if (!buff) {
+                       talloc_free(buff);
+                       return -1;
+               }
+       }
+
+       if (ret != 0) {
+               fr_strerror_printf("Failed resolving GID: %s", fr_syserror(ret));
+               talloc_free(buff);
+               errno = ret;
+               return -1;
+       }
+
+       talloc_set_type(buff, struct group);
+
+       return 0;
+}
+
+/** Resolve a group name to a group database entry
+ *
+ * Resolves a group name to a group database entry.
+ * The memory to hold the group entry is talloced under ctx,
+ * and must be freed when no longer required.
+ *
+ * @param ctx to allocate passwd entry in.
+ * @param out Where to write pointer to entry.
+ * @param name to resolve.
+ * @return 0 on success, -1 on error.
+ */
+int rad_getgrnam(TALLOC_CTX *ctx, struct group **out, char const *name)
+{
+       static size_t len;
+       uint8_t *buff;
+       int ret;
+
+       *out = NULL;
+
+       /*
+        *      We assume this won't change between calls,
+        *      and that the value is the same, so races don't
+        *      matter.
+        */
+       if (len == 0) {
+               long int sc_len;
+
+#ifdef _SC_GETGR_R_SIZE_MAX
+               sc_len = sysconf(_SC_GETGR_R_SIZE_MAX);
+#endif
+               if (sc_len <= 0) sc_len = 1024;
+               len = (size_t)sc_len;
+       }
+
+       buff = talloc_array(ctx, uint8_t, sizeof(struct group) + len);
+       if (!buff) return -1;
+
+       /*
+        *      In some cases we may need to dynamically
+        *      grow the string buffer.
+        */
+       while ((ret = getgrnam_r(name, (struct group *)buff, (char *)(buff + sizeof(struct group)),
+                                talloc_array_length(buff) - sizeof(struct group), out)) == ERANGE) {
+               buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2);
+               if (!buff) {
+                       talloc_free(buff);
+                       return -1;
+               }
+       }
+
+       if (ret != 0) {
+               fr_strerror_printf("Failed resolving GID: %s", fr_syserror(ret));
+               talloc_free(buff);
+               errno = ret;
+               return -1;
        }
 
-       talloc_free(group_buffer);
+       talloc_set_type(buff, struct group);
+
+       return 0;
+}
+
+/** Resolve a group name to a GID
+ *
+ * @param ctx to allocate temporary buffers in. Useful if using talloc pools.
+ * @param name of group.
+ * @param out where to write gid.
+ * @return 0 on success, -1 on error;
+ */
+int rad_getgid(TALLOC_CTX *ctx, gid_t *out, char const *name)
+{
+       int ret;
+       struct group *result;
 
-       if (!grp) return false;
+       ret = rad_getgrnam(ctx, &result, name);
+       if (ret < 0) return -1;
 
-       *gid = grp->gr_gid;
-       return true;
+       *out = result->gr_gid;
+       talloc_free(result);
+       return 0;
 }
-#endif /* HAVE_GETGRNAM_R */
-#endif /* HAVE_GRP_H */
index fec5df5..cd7079d 100644 (file)
@@ -464,11 +464,10 @@ static rlm_rcode_t CC_HINT(nonnull) detail_do(void *instance, REQUEST *request,
                return RLM_MODULE_FAIL;
        }
 
-#ifdef HAVE_GRP_H
        if (inst->group != NULL) {
                gid = strtol(inst->group, &endptr, 10);
                if (*endptr != '\0') {
-                       if (!fr_getgid(inst->group, &gid)) {
+                       if (rad_getgid(request, &gid, inst->group) < 0) {
                                RDEBUG2("Unable to find system group '%s'", inst->group);
                                goto skip_group;
                        }
@@ -480,8 +479,6 @@ static rlm_rcode_t CC_HINT(nonnull) detail_do(void *instance, REQUEST *request,
        }
 
 skip_group:
-#endif
-
        /*
         *      Open the output fp for buffering.
         */
index 1030b74..c9e9bb2 100644 (file)
@@ -278,11 +278,10 @@ static rlm_rcode_t CC_HINT(nonnull) mod_do_linelog(void *instance, REQUEST *requ
                        return RLM_MODULE_FAIL;
                }
 
-#ifdef HAVE_GRP_H
                if (inst->group != NULL) {
                        gid = strtol(inst->group, &endptr, 10);
                        if (*endptr != '\0') {
-                               if (!fr_getgid(inst->group, &gid)) {
+                               if (rad_getgid(request, &gid, inst->group) < 0) {
                                        RDEBUG2("Unable to find system group \"%s\"", inst->group);
                                        goto skip_group;
                                }
@@ -292,7 +291,6 @@ static rlm_rcode_t CC_HINT(nonnull) mod_do_linelog(void *instance, REQUEST *requ
                                RDEBUG2("Unable to change system group of \"%s\"", path);
                        }
                }
-#endif
        }
 
  skip_group:
index 228d6d3..192a1d8 100644 (file)
@@ -350,13 +350,7 @@ static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, REQUEST
        uuid_t guid_nasgroup;
        int err;
        char host_ipaddr[128] = {0};
-#ifdef HAVE_GRP_H
        gid_t gid;
-#endif
-#ifdef HAVE_GETPWNAM_R
-       struct passwd my_pwd;
-       char pwd_buffer[1024];
-#endif
 
        if (!request->username) {
                RDEBUG("OpenDirectory requires a User-Name attribute");
@@ -366,8 +360,7 @@ static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, REQUEST
        /* resolve SACL */
        uuid_clear(guid_sacl);
 
-#ifdef HAVE_GRP_H
-       if (fr_getgid(kRadiusSACLName, &gid)) {
+       if (rad_getgid(request, &gid, kRadiusSACLName) < 0) {
                err = mbr_gid_to_uuid(gid, guid_sacl);
                if (err != 0) {
                        ERROR("rlm_opendirectory: The group \"%s\" does not have a GUID.", kRadiusSACLName);
@@ -377,7 +370,6 @@ static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, REQUEST
        else {
                RDEBUG("The SACL group \"%s\" does not exist on this system.", kRadiusSACLName);
        }
-#endif /* HAVE_GRP_H */
 
        /* resolve client access list */
        uuid_clear(guid_nasgroup);
@@ -431,18 +423,13 @@ static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, REQUEST
        /* resolve user */
        uuid_clear(uuid);
 
-#ifdef HAVE_GETPWNAM_R
-       if (getpwnam_r(request->username->vp_strvalue, &my_pwd, pwd_buffer, sizeof(pwd_buffer), &userdata) != 0) {
-               userdata = NULL;
-       }
-#else
-       userdata = getpwnam(request->username->vp_strvalue);
-#endif
+       rad_getpwnam(request, &userdata, request->username->vp_strvalue);
        if (userdata != NULL) {
                err = mbr_uid_to_uuid(userdata->pw_uid, uuid);
                if (err != 0)
                        uuid_clear(uuid);
        }
+       talloc_free(userdata);
 
        if (uuid_is_null(uuid)) {
                REDEBUG("Could not get the user's uuid");
index 4ab7609..3a79287 100644 (file)
@@ -70,41 +70,10 @@ static const CONF_PARSER module_config[] = {
        { NULL, -1, 0, NULL, NULL }             /* end the list */
 };
 
-
-#ifndef HAVE_GETGRNAM_R
-#define fr_getgrnam(_a, _b) getgrnam(_b)
-#else
-static struct group *fr_getgrnam(TALLOC_CTX *ctx, char const *name)
-{
-       struct group    *grp, *result;
-       char            *group_buffer;
-       size_t          group_size = 1024;
-
-       grp = talloc(ctx, struct group);
-       group_buffer = talloc_array(grp, char, group_size);
-       while (group_buffer) {
-               int err;
-
-               err = getgrnam_r(name, grp, group_buffer, group_size, &result);
-               if (err == ERANGE) {
-                       group_size *= 2;
-                       talloc_free(group_buffer);
-                       group_buffer = talloc_array(grp, char, group_size);
-                       continue;
-               }
-
-               if (err) errno = err; /* so the caller knows what went wrong */
-               break;
-       }
-
-       return grp;
-}
-#endif /* HAVE_GETGRNAM_R */
-
 /*
  *     The Group = handler.
  */
-static int groupcmp(UNUSED void *instance, REQUEST *req, UNUSED VALUE_PAIR *request,
+static int groupcmp(UNUSED void *instance, REQUEST *request, UNUSED VALUE_PAIR *req_vp,
                    VALUE_PAIR *check, UNUSED VALUE_PAIR *check_pairs,
                    UNUSED VALUE_PAIR **reply_pairs)
 {
@@ -112,43 +81,32 @@ static int groupcmp(UNUSED void *instance, REQUEST *req, UNUSED VALUE_PAIR *requ
        struct group    *grp;
        char            **member;
        int             retval;
-#ifdef HAVE_GETPWNAM_R
-       struct passwd   my_pwd;
-       char            pwd_buffer[1024];
-#endif
 
        /*
-        *      No user name, doesn't compare.
+        *      No user name, can't compare.
         */
-       if (!req->username) {
-               return -1;
-       }
+       if (!request->username) return -1;
 
-#ifdef HAVE_GETPWNAM_R
-       if (getpwnam_r(req->username->vp_strvalue, &my_pwd, pwd_buffer, sizeof(pwd_buffer), &pwd) != 0) {
-               pwd = NULL;
-       }
-#else
-       pwd = getpwnam(req->username->vp_strvalue);
-#endif
-       if (!pwd)
+       if (rad_getpwnam(request, &pwd, request->username->vp_strvalue) < 0) {
+               RERROR("%s", fr_strerror());
                return -1;
-
-       grp = fr_getgrnam(req, check->vp_strvalue);
-       if (!grp)
+       }
+       if (rad_getgrnam(request, &grp, check->vp_strvalue) < 0) {
+               RERROR("%s", fr_strerror());
+               talloc_free(pwd);
                return -1;
+       }
 
        retval = (pwd->pw_gid == grp->gr_gid) ? 0 : -1;
        if (retval < 0) {
                for (member = grp->gr_mem; *member && retval; member++) {
-                       if (strcmp(*member, pwd->pw_name) == 0)
-                               retval = 0;
+                       if (strcmp(*member, pwd->pw_name) == 0) retval = 0;
                }
        }
 
-#ifdef HAVE_GETGRNAM_R
+       /* lifo */
        talloc_free(grp);
-#endif
+       talloc_free(pwd);
 
        return retval;
 }