aboutsummaryrefslogtreecommitdiffstats
path: root/main/freeradius
diff options
context:
space:
mode:
authorNatanael Copa <ncopa@alpinelinux.org>2014-09-04 14:40:59 +0000
committerNatanael Copa <ncopa@alpinelinux.org>2014-09-04 14:43:34 +0000
commitcd34a7d66f7efb60335bca5e0e87c0571a4d7a48 (patch)
treed373842465efbb2a0cf801cc8f0955884aa04d60 /main/freeradius
parent3ef2e14c40e74821e39e2d6049976da5b7516f49 (diff)
main/freeradius: fix segfault in rlm_unix
rlm_unix can segfault if you require group name lookup (eg user needs to be in a given system group) and 2 users are authenticating at the same time. Upstream has choosed to fix it differently and has added backport for v3.0.x, but has not cherry-picked it for v2.x.x branch. We use my proposed fix for v2.x. upstream bug is https://github.com/FreeRADIUS/freeradius-server/issues/767
Diffstat (limited to 'main/freeradius')
-rw-r--r--main/freeradius/0001-Use-threadsafe-wrapper-for-getpwnam-getgrnam.patch288
-rw-r--r--main/freeradius/APKBUILD6
2 files changed, 293 insertions, 1 deletions
diff --git a/main/freeradius/0001-Use-threadsafe-wrapper-for-getpwnam-getgrnam.patch b/main/freeradius/0001-Use-threadsafe-wrapper-for-getpwnam-getgrnam.patch
new file mode 100644
index 00000000000..8c6ba176c8e
--- /dev/null
+++ b/main/freeradius/0001-Use-threadsafe-wrapper-for-getpwnam-getgrnam.patch
@@ -0,0 +1,288 @@
+From aa269e0e41e4c4c3213149069d8083b27967a192 Mon Sep 17 00:00:00 2001
+From: Natanael Copa <ncopa@alpinelinux.org>
+Date: Mon, 1 Sep 2014 16:38:59 +0200
+Subject: [PATCH] Use threadsafe wrapper for getpwnam/getgrnam
+
+Even if rlm_unix is marked as RLM_TYPE_THREAD_UNSAFE, it runs in a
+separate thread than the main thread. Both main thread and rlm_unix
+uses thread unsafe getpwnam/getgrnam which causes segfault when under
+stress.
+
+We create a thread safe wrapper for those that uses TLS.
+
+ref #767
+---
+ src/include/radiusd.h | 5 +
+ src/main/command.c | 6 +-
+ src/main/util.c | 144 ++++++++++++++++++++++
+ src/modules/rlm_opendirectory/rlm_opendirectory.c | 6 +-
+ src/modules/rlm_unix/rlm_unix.c | 6 +-
+ 5 files changed, 158 insertions(+), 9 deletions(-)
+
+diff --git a/src/include/radiusd.h b/src/include/radiusd.h
+index 2bf5173..6936305 100644
+--- a/src/include/radiusd.h
++++ b/src/include/radiusd.h
+@@ -39,6 +39,9 @@ typedef struct auth_req REQUEST;
+ #include <pthread.h>
+ #endif
+
++#include <pwd.h>
++#include <grp.h>
++
+ #ifndef NDEBUG
+ #define REQUEST_MAGIC (0xdeadbeef)
+ #endif
+@@ -506,6 +509,8 @@ int rad_copy_variable(char *dst, const char *from);
+ int rad_expand_xlat(REQUEST *request, const char *cmd,
+ int max_argc, const char *argv[], int can_fail,
+ size_t argv_buflen, char *argv_buf);
++struct passwd *rad_getpwnam(const char *name);
++struct group *rad_getgrnam(const char *name);
+
+ /* client.c */
+ RADCLIENT_LIST *clients_init(void);
+diff --git a/src/main/command.c b/src/main/command.c
+index bce7e9a..4debd2b 100644
+--- a/src/main/command.c
++++ b/src/main/command.c
+@@ -1975,8 +1975,8 @@ static int command_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
+ #if defined(HAVE_GETPEEREID) || defined (SO_PEERCRED)
+ if (sock->uid_name) {
+ struct passwd *pw;
+-
+- pw = getpwnam(sock->uid_name);
++
++ pw = rad_getpwnam(sock->uid_name);
+ if (!pw) {
+ radlog(L_ERR, "Failed getting uid for %s: %s",
+ sock->uid_name, strerror(errno));
+@@ -1991,7 +1991,7 @@ static int command_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
+ if (sock->gid_name) {
+ struct group *gr;
+
+- gr = getgrnam(sock->gid_name);
++ gr = rad_getgrnam(sock->gid_name);
+ if (!gr) {
+ radlog(L_ERR, "Failed getting gid for %s: %s",
+ sock->gid_name, strerror(errno));
+diff --git a/src/main/util.c b/src/main/util.c
+index aebaff0..9ec96bb 100644
+--- a/src/main/util.c
++++ b/src/main/util.c
+@@ -31,6 +31,21 @@ RCSID("$Id$")
+
+ #include <sys/stat.h>
+ #include <fcntl.h>
++#include <unistd.h>
++#include <pwd.h>
++#include <grp.h>
++
++struct pwgrnam_buffer {
++ struct passwd pwd;
++ char *pwbuffer;
++ int pwsize;
++
++ struct group grp;
++ char *grbuffer;
++ int grsize;
++};
++
++fr_thread_local_setup(struct pwgrnam_buffer *, fr_pwgrnam_buffer); /* macro */
+
+ /*
+ * The signal() function in Solaris 2.5.1 sets SA_NODEFER in
+@@ -778,3 +793,132 @@ int rad_expand_xlat(REQUEST *request, const char *cmd,
+ return argc;
+ }
+
++/*
++ * Explicitly cleanup the memory allocated to the pwgrnam
++ * buffer.
++ */
++static void _fr_pwgrnam_free(void *arg)
++{
++ struct pwgrnam_buffer *p = (struct pwgrnam_buffer *)arg;
++ free(p->pwbuffer);
++ free(p->grbuffer);
++ free(p);
++}
++
++/*
++ * Allocate buffers for our getpwnam/getgrnam wrappers.
++ */
++static struct pwgrnam_buffer *init_pwgrnam_buffer(void) {
++ struct pwgrnam_buffer *p;
++ int ret;
++
++ p = fr_thread_local_init(fr_pwgrnam_buffer, _fr_pwgrnam_free);
++ if (p)
++ return p;
++
++ p = malloc(sizeof(struct pwgrnam_buffer));
++ if (!p) {
++ fr_perror("Failed allocating pwnam/grnam buffer");
++ return NULL;
++ }
++
++#ifdef _SC_GETPW_R_SIZE_MAX
++ p->pwsize = sysconf(_SC_GETPW_R_SIZE_MAX);
++ if (p->pwsize <= 0)
++#endif
++ p->pwsize = 16384;
++
++#ifdef _SC_GETGR_R_SIZE_MAX
++ p->grsize = sysconf(_SC_GETGR_R_SIZE_MAX);
++ if (p->grsize <= 0)
++#endif
++ p->grsize = 16384;
++
++ p->pwbuffer = malloc(p->pwsize);
++ if (!p->pwbuffer) {
++ fr_perror("Failed allocating pwnam buffer");
++ free(p);
++ return NULL;
++ }
++
++ p->grbuffer = malloc(p->grsize);
++ if (!p->grbuffer) {
++ fr_perror("Failed allocating grnam buffer");
++ free(p->pwbuffer);
++ free(p);
++ return NULL;
++ }
++
++ ret = fr_thread_local_set(fr_pwgrnam_buffer, p);
++ if (ret != 0) {
++ fr_perror("Failed setting up TLS for pwnam buffer: %s", fr_syserror(ret));
++ _fr_pwgrnam_free(p);
++ return NULL;
++ }
++
++ return p;
++}
++
++/** Wrapper around getpwnam, search user database for a name
++ *
++ * getpwnam is not threadsafe so provide a thread-safe variant that
++ * uses TLS.
++ *
++ * @param name then username to search for
++ * @return NULL on error or not found, else pointer to thread local struct passwd buffer
++ */
++struct passwd *rad_getpwnam(const char *name)
++{
++ struct pwgrnam_buffer *p;
++ struct passwd *result;
++ int ret;
++
++ p = init_pwgrnam_buffer();
++ if (!p)
++ return NULL;
++
++ while ((ret = getpwnam_r(name, &p->pwd, p->pwbuffer, p->pwsize, &result)) == ERANGE) {
++ char *tmp = realloc(p->pwbuffer, p->pwsize * 2);
++ if (!tmp) {
++ fr_perror("Failed reallocating pwnam buffer");
++ return NULL;
++ }
++ p->pwsize *= 2;
++ p->pwbuffer = tmp;
++ }
++ if (ret < 0 || result == NULL)
++ return NULL;
++ return result;
++}
++
++/** Wrapper around getgrnam, search group database for a name
++ *
++ * getgrnam is not threadsafe so provide a thread-safe variant that
++ * uses TLS.
++ *
++ * @param name the name to search for
++ * @return NULL on error or not found, else pointer to thread local struct group buffer
++ */
++struct group *rad_getgrnam(const char *name)
++{
++ struct pwgrnam_buffer *p;
++ struct group *result;
++ int ret;
++
++ p = init_pwgrnam_buffer();
++ if (!p)
++ return NULL;
++
++ while ((ret = getgrnam_r(name, &p->grp, p->grbuffer, p->grsize, &result)) == ERANGE) {
++ char *tmp = realloc(p->grbuffer, p->grsize * 2);
++ if (!tmp) {
++ fr_perror("Failed reallocating pwnam buffer");
++ return NULL;
++ }
++ p->grsize *= 2;
++ p->grbuffer = tmp;
++ }
++ if (ret < 0 || result == NULL)
++ return NULL;
++ return result;
++}
+diff --git a/src/modules/rlm_opendirectory/rlm_opendirectory.c b/src/modules/rlm_opendirectory/rlm_opendirectory.c
+index a160b81..0cacadf 100644
+--- a/src/modules/rlm_opendirectory/rlm_opendirectory.c
++++ b/src/modules/rlm_opendirectory/rlm_opendirectory.c
+@@ -352,7 +352,7 @@ static int od_authorize(UNUSED void *instance, REQUEST *request)
+
+ /* resolve SACL */
+ uuid_clear(guid_sacl);
+- groupdata = getgrnam(kRadiusSACLName);
++ groupdata = rad_getgrnam(kRadiusSACLName);
+ if (groupdata != NULL) {
+ err = mbr_gid_to_uuid(groupdata->gr_gid, guid_sacl);
+ if (err != 0) {
+@@ -377,7 +377,7 @@ static int od_authorize(UNUSED void *instance, REQUEST *request)
+ */
+ if (uuid_parse(rad_client->community, guid_nasgroup) != 0) {
+ /* attempt to resolve the name */
+- groupdata = getgrnam(rad_client->community);
++ groupdata = rad_getgrnam(rad_client->community);
+ if (groupdata == NULL) {
+ radlog(L_AUTH, "rlm_opendirectory: The group \"%s\" does not exist on this system.", rad_client->community);
+ return RLM_MODULE_FAIL;
+@@ -418,7 +418,7 @@ static int od_authorize(UNUSED void *instance, REQUEST *request)
+ name = (char *)request->username->vp_strvalue;
+ rad_assert(name != NULL);
+
+- userdata = getpwnam(name);
++ userdata = rad_getpwnam(name);
+ if (userdata != NULL) {
+ err = mbr_uid_to_uuid(userdata->pw_uid, uuid);
+ if (err != 0)
+diff --git a/src/modules/rlm_unix/rlm_unix.c b/src/modules/rlm_unix/rlm_unix.c
+index 9caab7a..661e3d7 100644
+--- a/src/modules/rlm_unix/rlm_unix.c
++++ b/src/modules/rlm_unix/rlm_unix.c
+@@ -93,11 +93,11 @@ static int groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request,
+ return -1;
+ }
+
+- pwd = getpwnam(req->username->vp_strvalue);
++ pwd = rad_getpwnam(req->username->vp_strvalue);
+ if (pwd == NULL)
+ return -1;
+
+- grp = getgrnam(check->vp_strvalue);
++ grp = rad_getgrnam(check->vp_strvalue);
+ if (grp == NULL)
+ return -1;
+
+@@ -211,7 +211,7 @@ static int unix_getpw(UNUSED void *instance, REQUEST *request,
+ return RLM_MODULE_USERLOCK;
+ }
+ #else /* OSFC2 */
+- if ((pwd = getpwnam(name)) == NULL) {
++ if ((pwd = rad_getpwnam(name)) == NULL) {
+ return RLM_MODULE_NOTFOUND;
+ }
+ encrypted_pass = pwd->pw_passwd;
+--
+2.1.0
+
diff --git a/main/freeradius/APKBUILD b/main/freeradius/APKBUILD
index ad0c65a30ce..dcb1c75713b 100644
--- a/main/freeradius/APKBUILD
+++ b/main/freeradius/APKBUILD
@@ -2,7 +2,7 @@
# Maintainer: Leonardo Arena <rnalrd@alpinelinux.org>
pkgname=freeradius
pkgver=2.2.5
-pkgrel=1
+pkgrel=2
pkgdesc="RADIUS (Remote Authentication Dial-In User Service) server"
url="http://freeradius.org/"
arch="all"
@@ -20,6 +20,7 @@ subpackages="$pkgname-doc $pkgname-dev $pkgname-dbg $pkgname-ldap $pkgname-lib
$pkgname-unixodbc $pkgname-pam $pkgname-webif $pkgname-webif-doc"
source="ftp://ftp.freeradius.org/pub/freeradius/$pkgname-server-$pkgver.tar.gz
freeradius-fix-openssl-version-check.patch
+ 0001-Use-threadsafe-wrapper-for-getpwnam-getgrnam.patch
freeradius.confd
freeradius.initd
"
@@ -244,13 +245,16 @@ webif() {
md5sums="da77eb23b4c5e2f9fc55119025a91b61 freeradius-server-2.2.5.tar.gz
fde9be89b76ed262db1198dfbeb237c6 freeradius-fix-openssl-version-check.patch
+f28735060b63d88875783817bcd95586 0001-Use-threadsafe-wrapper-for-getpwnam-getgrnam.patch
fc6693f3df5a0694610110287a28568a freeradius.confd
b3eefdfc466d80c241cd1bb11face405 freeradius.initd"
sha256sums="8c4c2a0b600a8d85d2235589a5e80d4fefd1f52317e9daf8193731566fa9d012 freeradius-server-2.2.5.tar.gz
c0f15867924ae73511cd009cb3c53cbd7eda298ff708a54f02d1900da5ebfc06 freeradius-fix-openssl-version-check.patch
+115ae559fc5c8a638c5ebb510cb58478df66ceeb61a6768584e592e4a1fbc9d4 0001-Use-threadsafe-wrapper-for-getpwnam-getgrnam.patch
2d5b3e1af1299373182f2c8021bdf45c29db5d82b0a077b965a16ded32cb6292 freeradius.confd
719bbe4a44df60e76f68d327f7ee70d4dfd6a95e51f9cb01f850cd4ed153f9de freeradius.initd"
sha512sums="511599b4f4f5906441d0cda61946341f2226b9aae69b6f68b03a19898b6385499a8221933c191232d50f736cab93f0f6f271e4defe4552e7738cb21e2415f053 freeradius-server-2.2.5.tar.gz
77ec50125b38e05ee784b4cf724a31074844ea9c935c0d28aa51bd71e3e8a5399ba5194958f65f8c7f6c501b67ea6560da3869917f661178afbe602062a6fdc6 freeradius-fix-openssl-version-check.patch
+4fb99b6a0f22cb844382139d448e24cc1b698452e30c1b0f06674a6fbd21463bcece2f2f4121618f9c7c57c8eb882eee35511b4dcea6e2a0904e27e5f2a6a679 0001-Use-threadsafe-wrapper-for-getpwnam-getgrnam.patch
e248159c0a44f722e405c51c8015d9ad672e42ad0d38ca28f8a051ff911aa4d3e630b9bd4543e9d610940bc4ae50c022594e219ce341b36abe85c572acad418b freeradius.confd
57f12f06ef9112817204dec4ab2591bcd4baf3c8a033afadb2376e115911f76045c70b7a2c80b294a83dac4e05b1ff22335a3bcc9af1c0760682622ab2cdbd31 freeradius.initd"