mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-26 08:51:50 -06:00
f996c21edb
On Fedora 33 GCC defaults to -Wmissing-prototypes and emits warnings about function prototypes missing. If -Werror is specified, this breaks compilation. We also default to -Werror=implicit-function-declaration Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com> Reviewed-By: Robbie Harwood <rharwood@redhat.com> Reviewed-By: Rob Crittenden <rcritten@redhat.com>
202 lines
6.7 KiB
C
202 lines
6.7 KiB
C
/*
|
|
* Copyright (C) 2018,2020 FreeIPA Contributors see COPYING for license
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <syslog.h>
|
|
#include <sys/random.h>
|
|
|
|
#include <krb5/kdcpolicy_plugin.h>
|
|
|
|
#include "ipa_krb5.h"
|
|
#include "ipa_kdb.h"
|
|
|
|
#define ONE_DAY_SECONDS (24 * 60 * 60)
|
|
#define JITTER_WINDOW_SECONDS (1 * 60 * 60)
|
|
|
|
krb5_error_code kdcpolicy_ipakdb_initvt(krb5_context context,
|
|
int maj_ver, int min_ver,
|
|
krb5_plugin_vtable vtable);
|
|
|
|
static void
|
|
jitter(krb5_deltat baseline, krb5_deltat *lifetime_out)
|
|
{
|
|
krb5_deltat offset;
|
|
ssize_t ret;
|
|
|
|
if (baseline < JITTER_WINDOW_SECONDS) {
|
|
/* A negative value here would correspond to a never-valid ticket,
|
|
* which isn't the goal. */
|
|
*lifetime_out = baseline;
|
|
return;
|
|
}
|
|
|
|
do {
|
|
ret = getrandom(&offset, sizeof(offset), 0);
|
|
} while (ret == -1 && errno == EINTR);
|
|
if (ret < 0) {
|
|
krb5_klog_syslog(LOG_INFO, "IPA kdcpolicy: getrandom failed (errno %d); skipping jitter...",
|
|
errno);
|
|
return;
|
|
}
|
|
|
|
*lifetime_out = baseline - offset % JITTER_WINDOW_SECONDS;
|
|
}
|
|
|
|
static krb5_error_code
|
|
ipa_kdcpolicy_check_as(krb5_context context, krb5_kdcpolicy_moddata moddata,
|
|
const krb5_kdc_req *request,
|
|
const krb5_db_entry *client,
|
|
const krb5_db_entry *server,
|
|
const char *const *auth_indicators,
|
|
const char **status, krb5_deltat *lifetime_out,
|
|
krb5_deltat *renew_lifetime_out)
|
|
{
|
|
krb5_error_code kerr = 0;
|
|
enum ipadb_user_auth ua;
|
|
struct ipadb_e_data *ied;
|
|
struct ipadb_e_pol_limits *pol_limits = NULL;
|
|
int valid_auth_indicators = 0, flags = 0;
|
|
krb5_db_entry *client_actual = NULL;
|
|
|
|
#ifdef KRB5_KDB_FLAG_ALIAS_OK
|
|
flags = KRB5_KDB_FLAG_ALIAS_OK;
|
|
#endif
|
|
|
|
|
|
*status = NULL;
|
|
*lifetime_out = 0;
|
|
*renew_lifetime_out = 0;
|
|
|
|
ied = (struct ipadb_e_data *)client->e_data;
|
|
if (ied == NULL || ied->magic != IPA_E_DATA_MAGIC) {
|
|
/* e-data is not availble, getting user auth from LDAP */
|
|
krb5_klog_syslog(LOG_INFO, "IPA kdcpolicy: client e_data not availble. Try fetching...");
|
|
kerr = ipadb_get_principal(context, request->client, flags,
|
|
&client_actual);
|
|
if (kerr != 0) {
|
|
krb5_klog_syslog(LOG_ERR, "IPA kdcpolicy: ipadb_find_principal failed.");
|
|
goto done;
|
|
}
|
|
|
|
ied = (struct ipadb_e_data *)client_actual->e_data;
|
|
if (ied == NULL || ied->magic != IPA_E_DATA_MAGIC) {
|
|
krb5_klog_syslog(LOG_ERR, "IPA kdcpolicy: client e_data fetching failed.");
|
|
kerr = EINVAL;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
ua = ied->user_auth;
|
|
|
|
/* If no mechanisms are set, allow every auth method */
|
|
if (ua == IPADB_USER_AUTH_NONE) {
|
|
jitter(ONE_DAY_SECONDS, lifetime_out);
|
|
kerr = 0;
|
|
goto done;
|
|
}
|
|
|
|
/* For each auth indicator, see if it is allowed for that user */
|
|
for (int i = 0; auth_indicators[i] != NULL; i++) {
|
|
const char *auth_indicator = auth_indicators[i];
|
|
|
|
if (strcmp(auth_indicator, "otp") == 0) {
|
|
valid_auth_indicators++;
|
|
if (!(ua & IPADB_USER_AUTH_OTP)) {
|
|
*status = "OTP pre-authentication not allowed for this user.";
|
|
kerr = KRB5KDC_ERR_POLICY;
|
|
goto done;
|
|
}
|
|
pol_limits = &(ied->pol_limits[IPADB_USER_AUTH_IDX_OTP]);
|
|
} else if (strcmp(auth_indicator, "radius") == 0) {
|
|
valid_auth_indicators++;
|
|
if (!(ua & IPADB_USER_AUTH_RADIUS)) {
|
|
*status = "OTP pre-authentication not allowed for this user.";
|
|
kerr = KRB5KDC_ERR_POLICY;
|
|
goto done;
|
|
}
|
|
pol_limits = &(ied->pol_limits[IPADB_USER_AUTH_IDX_RADIUS]);
|
|
} else if (strcmp(auth_indicator, "pkinit") == 0) {
|
|
valid_auth_indicators++;
|
|
if (!(ua & IPADB_USER_AUTH_PKINIT)) {
|
|
*status = "PKINIT pre-authentication not allowed for this user.";
|
|
kerr = KRB5KDC_ERR_POLICY;
|
|
goto done;
|
|
}
|
|
pol_limits = &(ied->pol_limits[IPADB_USER_AUTH_IDX_PKINIT]);
|
|
} else if (strcmp(auth_indicator, "hardened") == 0) {
|
|
valid_auth_indicators++;
|
|
/* Allow hardened even if only password pre-auth is allowed */
|
|
if (!(ua & (IPADB_USER_AUTH_HARDENED | IPADB_USER_AUTH_PASSWORD))) {
|
|
*status = "Password pre-authentication not not allowed for this user.";
|
|
kerr = KRB5KDC_ERR_POLICY;
|
|
goto done;
|
|
}
|
|
pol_limits = &(ied->pol_limits[IPADB_USER_AUTH_IDX_HARDENED]);
|
|
}
|
|
}
|
|
|
|
/* There is no auth indicator assigned for non-hardened password authentication
|
|
* so we assume password is used when no supported indicator exists */
|
|
if (!valid_auth_indicators) {
|
|
if (!(ua & IPADB_USER_AUTH_PASSWORD)) {
|
|
*status = "Non-hardened password authentication not allowed for this user.";
|
|
kerr = KRB5KDC_ERR_POLICY;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
/* If there were policy limits associated with the authentication indicators,
|
|
* apply them */
|
|
if (pol_limits != NULL) {
|
|
if (pol_limits->max_life != 0) {
|
|
jitter(pol_limits->max_life, lifetime_out);
|
|
} else {
|
|
jitter(ONE_DAY_SECONDS, lifetime_out);
|
|
}
|
|
|
|
if (pol_limits->max_renewable_life != 0) {
|
|
*renew_lifetime_out = pol_limits->max_renewable_life;
|
|
}
|
|
}
|
|
|
|
done:
|
|
ipadb_free_principal(context, client_actual);
|
|
|
|
return kerr;
|
|
}
|
|
|
|
static krb5_error_code
|
|
ipa_kdcpolicy_check_tgs(krb5_context context, krb5_kdcpolicy_moddata moddata,
|
|
const krb5_kdc_req *request,
|
|
const krb5_db_entry *server,
|
|
const krb5_ticket *ticket,
|
|
const char *const *auth_indicators,
|
|
const char **status, krb5_deltat *lifetime_out,
|
|
krb5_deltat *renew_lifetime_out)
|
|
{
|
|
*status = NULL;
|
|
*lifetime_out = 0;
|
|
*renew_lifetime_out = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
krb5_error_code kdcpolicy_ipakdb_initvt(krb5_context context,
|
|
int maj_ver, int min_ver,
|
|
krb5_plugin_vtable vtable)
|
|
{
|
|
krb5_kdcpolicy_vtable vt;
|
|
|
|
if (maj_ver != 1)
|
|
return KRB5_PLUGIN_VER_NOTSUPP;
|
|
|
|
vt = (krb5_kdcpolicy_vtable)vtable;
|
|
vt->name = "ipakdb";
|
|
vt->init = NULL;
|
|
vt->fini = NULL;
|
|
vt->check_as = ipa_kdcpolicy_check_as;
|
|
vt->check_tgs = ipa_kdcpolicy_check_tgs;
|
|
return 0;
|
|
}
|