PAM authentication and RADIUS attributes

While directly using RADIUS authentication is preferable to using RADIUS
through PAM, it seems OK to read and use the RADIUS attributes that PAM
is able to let through (currently Framed-IP-Address only).

Signed-off-by: Dimitri Papadopoulos <3350651-DimitriPapadopoulos@users.noreply.gitlab.com>
This commit is contained in:
Dimitri Papadopoulos
2024-04-06 23:07:50 +02:00
parent 5e39f4c7f0
commit e7a7a5f67b
3 changed files with 58 additions and 2 deletions

2
NEWS
View File

@@ -1,6 +1,8 @@
* Version 1.3.1 (unreleased)
- The bundled llhtp was updated to 9.3.0.
- The bundled protobuf-c was updated to 1.5.1.
- When using RADIUS authentication through the PAM module, take into
account RADIUS attributes that PAM passes as environment variables.
- Fixed issues with PAM authentication when combined with pam_sssd (#618)
- Enhanced the seccomp filters to address issue in testing (#627)
- Fixed "unexpected URL" errors for Cisco AnyConnect clients

View File

@@ -41,12 +41,13 @@
* no session management.
*/
#include "auth/pam.h"
#include "auth-unix.h"
#include <security/pam_appl.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include "auth/pam.h"
#include "auth-unix.h"
#include <arpa/inet.h>
#define PAM_STACK_SIZE (1024 * 1024)
@@ -148,9 +149,14 @@ static void co_auth_user(void *data)
{
struct pam_ctx_st *pctx = data;
int pret;
static const char envname[] = "Framed-IP-Address";
const char *envval;
pctx->state = PAM_S_INIT;
/* Unset environment variables that may be set by pam_authenticate() */
unsetenv(envname);
pret = pam_authenticate(pctx->ph, 0);
if (pret != PAM_SUCCESS) {
oc_syslog(LOG_INFO, "PAM authenticate error for '%s': %s",
@@ -159,6 +165,51 @@ static void co_auth_user(void *data)
goto wait;
}
/*
* As of release 2.0.0, the pam_radius module supports passing RADIUS
* attributes as environment variables. Only the Framed-IP-Address attribute
* is currently supported:
* https://github.com/FreeRADIUS/pam_radius/pull/47
* This is just a hack. We recommend explicitly using authentication RADIUS
* authentication in ocserv, instead of misusing PAM authentication against
* a RADIUS server.
*/
envval = getenv(envname);
if (envval) {
struct in_addr addr;
oc_syslog(LOG_DEBUG, "Get PAM environment variable: %s=%s\n",
envname, envval);
switch (inet_pton(AF_INET, envval, &addr)) {
case 1:
if (addr.s_addr != 0xffffffff &&
addr.s_addr != 0xfffffffe) {
/* According to RFC2865 the values above instruct the server
* (fe) to assign an address from the pool of the server, and
* (ff) to assign address as negotiated with the client.
* We don't negotiate with clients.
*/
strncpy(pctx->ipv4, envval, MAX_IP_STR - 1);
oc_syslog(
LOG_DEBUG,
"Interpret PAM environment variable as a RADIUS attribute: %s=%s\n",
envname, envval);
}
break;
case 0:
oc_syslog(
LOG_NOTICE,
"PAM environment variable is not an IPv4 address: %s=%s\n",
envname, envval);
break;
default:
oc_syslog(LOG_NOTICE,
"Cannot convert to an IPv4 address: %s\n",
strerror(errno));
break;
}
}
pret = pam_acct_mgmt(pctx->ph, 0);
if (pret == PAM_NEW_AUTHTOK_REQD) {
/* change password */

View File

@@ -26,6 +26,8 @@
#ifdef HAVE_PAM
#include "common/common.h"
#include <security/pam_appl.h>
#include <str.h>
#include <pcl.h>
@@ -43,6 +45,7 @@ struct pam_ctx_st {
str_st msg;
str_st prompt;
unsigned int sent_msg;
char ipv4[MAX_IP_STR];
struct pam_response *replies; /* for safety */
unsigned int state; /* PAM_S_ */
unsigned int passwd_counter;