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 d6b18598cd
commit de95ff8046
No known key found for this signature in database
GPG Key ID: C39F225C34319CDA
4 changed files with 51 additions and 5 deletions

2
NEWS
View File

@ -1,4 +1,6 @@
* Version 1.3.1 (unreleased)
- 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)

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)
@ -138,9 +139,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", pctx->username, pam_strerror(pctx->ph, pret));
@ -148,6 +154,41 @@ int pret;
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 sent_msg;
char ipv4[MAX_IP_STR];
struct pam_response *replies; /* for safety */
unsigned state; /* PAM_S_ */
unsigned passwd_counter;

View File

@ -432,9 +432,9 @@ static int radius_auth_pass(void *ctx, const char *pass, unsigned pass_len)
} else if (vp->attribute == PW_FRAMED_IP_ADDRESS && vp->type == PW_TYPE_IPADDR) {
/* Framed-IP-Address */
if (vp->lvalue != 0xffffffff && vp->lvalue != 0xfffffffe) {
/* According to RFC2865 the values above (fe) instruct the
* server to assign an address from the pool of the server,
* and (ff) to assign address as negotiated with the client.
/* 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.
*/
ipv4 = htonl(vp->lvalue);