Skip to content

Commit

Permalink
[ 7274] Use grid configs for auth configs
Browse files Browse the repository at this point in the history
  • Loading branch information
alanking committed Sep 14, 2023
1 parent e5141bf commit 9d34ffd
Showing 1 changed file with 143 additions and 77 deletions.
220 changes: 143 additions & 77 deletions plugins/database/src/db_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,6 @@ static rodsLong_t MAX_PASSWORDS = 40;

#define MAX_HOST_STR 2700

// =-=-=-=-=-=-=-
// local variables externed for config file setting in
bool irods_pam_auth_no_extend = false;
char irods_pam_password_min_time[ NAME_LEN ] = { "121" };
char irods_pam_password_max_time[ NAME_LEN ] = { "1209600" };
char irods_pam_password_default_time[ NAME_LEN ] = { "1209600" };

size_t log_sql_flg = 0;
icatSessionStruct icss; // JMC :: only for testing!!!
extern int logSQL;
Expand All @@ -123,6 +116,90 @@ const std::string ZONE_PROP( "irods_zone_property" );

static const auto intermediate_replica_status_str = std::to_string(INTERMEDIATE_REPLICA);

irods::error db_get_grid_configuration_value_op(irods::plugin_context& _ctx,
const char* _namespace,
const char* _option_name,
char* _option_value,
std::size_t _option_value_buffer_size);

namespace
{
constexpr std::size_t grid_configuration_size = 2700;
constexpr rodsLong_t default_password_max_time = 1209600;
constexpr rodsLong_t default_password_min_time = 121;
struct auth_config
{
bool password_extend_lifetime = true;

rodsLong_t password_max_time = default_password_max_time;
std::array<char, grid_configuration_size + 1> password_max_time_str{};

rodsLong_t password_min_time = default_password_min_time;
std::array<char, grid_configuration_size + 1> password_min_time_str{};
};

auto get_auth_config(irods::plugin_context& _ctx, const char* _namespace, auth_config& _out) -> irods::error
{
try {
auto err = db_get_grid_configuration_value_op(_ctx,
_namespace,
irods::KW_CFG_PAM_PASSWORD_MIN_TIME,
_out.password_min_time_str.data(),
_out.password_min_time_str.size());
if (err.ok()) {
try {
_out.password_min_time = std::stoll(_out.password_min_time_str.data());
}
catch (...) {
log_db::error("Grid configuration value in namespace [{}] is invalid. Using default.", _namespace);
}
}

err = db_get_grid_configuration_value_op(_ctx,
_namespace,
irods::KW_CFG_PAM_PASSWORD_MAX_TIME,
_out.password_max_time_str.data(),
_out.password_max_time_str.size());
if (err.ok()) {
try {
_out.password_max_time = std::stoll(_out.password_max_time_str.data());
}
catch (...) {
log_db::error("Grid configuration value in namespace [{}] is invalid. Using default.", _namespace);
}
}

std::array<char, grid_configuration_size + 1> extend_lifetime_buf{};
err = db_get_grid_configuration_value_op(_ctx,
_namespace,
irods::KW_CFG_PAM_PASSWORD_EXTEND_LIFETIME,
extend_lifetime_buf.data(),
extend_lifetime_buf.size());
if (err.ok()) {
if (0 == std::strcmp(extend_lifetime_buf.data(), "1")) {
_out.password_extend_lifetime = true;
}
else if (0 == std::strcmp(extend_lifetime_buf.data(), "0")) {
_out.password_extend_lifetime = false;
}
else {
// Use default if it's neither, and print an annoying error message.
log_db::error("Grid configuration [{}] in namespace [{}] is invalid.",
irods::KW_CFG_PAM_PASSWORD_EXTEND_LIFETIME,
_namespace);
}
}
}
catch (const std::out_of_range& e) {
const auto msg =
fmt::format("Grid configuration value in namespace [{}] is out of range: [{}]", _namespace, e.what());
log_db::error(msg);
}

return SUCCESS();
} // get_auth_config
} // anonymous namespace

// =-=-=-=-=-=-=-
// virtual path management
#define PATH_SEPARATOR irods::get_virtual_path_separator().c_str()
Expand Down Expand Up @@ -2002,41 +2079,6 @@ irods::error db_open_op(
irods::catalog_properties::instance().capture_if_needed( &icss );
#endif

// =-=-=-=-=-=-=-
// set pam properties
try {
// clang-format off
namespace auth_scheme = irods::experimental::auth::scheme;

irods_pam_auth_no_extend = irods::get_server_property<const bool>(
std::vector<std::string>{irods::KW_CFG_PLUGIN_TYPE_AUTHENTICATION,
auth_scheme::pam_password,
irods::KW_CFG_PAM_NO_EXTEND});

snprintf(irods_pam_password_min_time, NAME_LEN, "%s",
irods::get_server_property<const std::string>(
std::vector<std::string>{irods::KW_CFG_PLUGIN_TYPE_AUTHENTICATION,
auth_scheme::pam_password,
irods::KW_CFG_PAM_PASSWORD_MIN_TIME}).c_str());

snprintf(irods_pam_password_max_time, NAME_LEN, "%s",
irods::get_server_property<const std::string>(
std::vector<std::string>{irods::KW_CFG_PLUGIN_TYPE_AUTHENTICATION,
auth_scheme::pam_password,
irods::KW_CFG_PAM_PASSWORD_MAX_TIME}).c_str());
// clang-format on
}
catch (const irods::exception& e) {
log_db::debug("[{}:{}] PAM property not found [{}]", __func__, __LINE__, e.client_display_what());
return CODE(status);
}

if ( irods_pam_auth_no_extend ) {
snprintf( irods_pam_password_default_time,
sizeof( irods_pam_password_default_time ),
"%s", "28800" );
}

return CODE( status );

} // db_open_op
Expand Down Expand Up @@ -6323,15 +6365,16 @@ irods::error db_check_auth_op(
char myUserZone[MAX_NAME_LEN];
char userName2[NAME_LEN + 2];
char userZone[NAME_LEN + 2];
rodsLong_t pamMinTime = 0;
rodsLong_t pamMaxTime = 0;
int hashType = 0;
char lastPwModTs[MAX_PASSWORD_LEN + 10];
snprintf( lastPwModTs, sizeof( lastPwModTs ), "0" );
char *cPwTs = NULL;
int iTs1 = 0, iTs2 = 0;
std::vector<char> pwInfoArray( MAX_PASSWORD_LEN * MAX_PASSWORDS * 4 );

// This function uses goto statements. You cannot initialize variables after a goto statement.
auth_config ac{};

if ( logSQL != 0 ) {
log_sql::debug("chlCheckAuth");
}
Expand Down Expand Up @@ -6520,12 +6563,14 @@ irods::error db_check_auth_op(
getNowStr( myTime );

/* Check for PAM_AUTH type passwords */
pamMaxTime = atoll( irods_pam_password_max_time );
pamMinTime = atoll( irods_pam_password_min_time );

if ( ( strncmp( goodPwExpiry, "9999", 4 ) != 0 ) &&
expireTime >= pamMinTime &&
expireTime <= pamMaxTime ) {
if (const auto err = get_auth_config(_ctx, "authentication::pam_password", ac); !err.ok()) {
irods::log(err);
log_db::warn("Failed to get password configuration - using defaults.");
}

if ((strncmp(goodPwExpiry, "9999", 4) != 0) && expireTime >= ac.password_min_time &&
expireTime <= ac.password_max_time) {
time_t modTime;
/* The used pw is an iRODS-PAM type, so now check if it's expired */
getNowStr( myTime );
Expand Down Expand Up @@ -6951,9 +6996,6 @@ irods::error db_make_limited_pw_op(
int j = 0;
char tSQL[MAX_SQL_SIZE];
char expTime[50];
int timeToLive;
rodsLong_t pamMinTime;
rodsLong_t pamMaxTime;

if ( logSQL != 0 ) {
log_sql::debug("chlMakeLimitedPw");
Expand Down Expand Up @@ -7016,20 +7058,30 @@ irods::error db_make_limited_pw_op(

getNowStr( myTime );

timeToLive = _ttl * 3600; /* convert input hours to seconds */
pamMaxTime = atoll( irods_pam_password_max_time );
pamMinTime = atoll( irods_pam_password_min_time );
if ( timeToLive < pamMinTime ||
timeToLive > pamMaxTime ) {
auth_config ac{};
if (const auto err = get_auth_config(_ctx, "authentication::native", ac); !err.ok()) {
irods::log(err);
log_db::warn("Failed to get password configuration - using defaults.");
}

if (_ttl < ac.password_min_time || _ttl > ac.password_max_time) {
log_db::error(
"Invalid TTL - min time: [{}] max time:[{}] ttl: [{}]", ac.password_min_time, ac.password_max_time, _ttl);
return ERROR( PAM_AUTH_PASSWORD_INVALID_TTL, "invalid ttl" );
}

/* Insert the limited password */
// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
int timeToLive = _ttl * 3600; /* convert input hours to seconds */
snprintf( expTime, sizeof expTime, "%d", timeToLive );
cllBindVars[cllBindVarCount++] = _ctx.comm()->clientUser.userName;
cllBindVars[cllBindVarCount++] = _ctx.comm()->clientUser.rodsZone,
cllBindVars[cllBindVarCount++] = newPw;
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
cllBindVars[cllBindVarCount++] = _ctx.comm()->clientUser.rodsZone;
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
cllBindVars[cllBindVarCount++] = newPw;
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
cllBindVars[cllBindVarCount++] = expTime;
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
cllBindVars[cllBindVarCount++] = myTime;
cllBindVars[cllBindVarCount++] = myTime;
if ( logSQL != 0 ) {
Expand All @@ -7048,8 +7100,10 @@ irods::error db_make_limited_pw_op(
if ( logSQL != 0 ) {
log_sql::debug("chlMakeLimitedPw SQL 3");
}
cllBindVars[cllBindVarCount++] = irods_pam_password_min_time;
cllBindVars[cllBindVarCount++] = irods_pam_password_max_time;
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
cllBindVars[cllBindVarCount++] = ac.password_min_time_str.data();
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
cllBindVars[cllBindVarCount++] = ac.password_max_time_str.data();
cllBindVars[cllBindVarCount++] = myTime;
#if MY_ICAT
status = cmlExecuteNoAnswerSql( "delete from R_USER_PASSWORD where pass_expiry_ts not like '9999%' and cast(pass_expiry_ts as signed integer)>=? and cast(pass_expiry_ts as signed integer)<=? and (cast(pass_expiry_ts as signed integer) + cast(modify_ts as signed integer) < ?)",
Expand Down Expand Up @@ -7138,18 +7192,20 @@ auto db_update_pam_password_op(irods::plugin_context& _ctx,

getNowStr( myTime );

/* if ttl is unset, use the default */
auth_config ac{};
if (const auto err = get_auth_config(_ctx, "authentication::pam_password", ac); !err.ok()) {
irods::log(err);
log_db::warn("Failed to get password configuration - using defaults.");
}

/* if ttl is unset, use the default (minimum password lifetime) */
if ( _ttl == 0 ) {
rstrcpy( expTime, irods_pam_password_default_time, sizeof expTime );
rstrcpy(expTime, std::to_string(ac.password_min_time).c_str(), sizeof expTime);
}
else {
/* convert ttl to seconds and make sure ttl is within the limits */
rodsLong_t pamMinTime, pamMaxTime;
pamMinTime = atoll( irods_pam_password_min_time );
pamMaxTime = atoll( irods_pam_password_max_time );
_ttl = _ttl * 3600;
if ( _ttl < pamMinTime ||
_ttl > pamMaxTime ) {
if (_ttl < ac.password_min_time || _ttl > ac.password_max_time) {
return ERROR( PAM_AUTH_PASSWORD_INVALID_TTL, "pam ttl invalid" );
}
snprintf( expTime, sizeof expTime, "%d", _ttl );
Expand Down Expand Up @@ -7178,8 +7234,10 @@ auto db_update_pam_password_op(irods::plugin_context& _ctx,
if ( logSQL != 0 ) {
log_sql::debug("chlUpdateIrodsPamPassword SQL 2");
}
cllBindVars[cllBindVarCount++] = irods_pam_password_min_time;
cllBindVars[cllBindVarCount++] = irods_pam_password_max_time;
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
cllBindVars[cllBindVarCount++] = ac.password_min_time_str.data();
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
cllBindVars[cllBindVarCount++] = ac.password_max_time_str.data();
cllBindVars[cllBindVarCount++] = myTime;
#if MY_ICAT
status = cmlExecuteNoAnswerSql( "delete from R_USER_PASSWORD where pass_expiry_ts not like '9999%' and cast(pass_expiry_ts as signed integer)>=? and cast(pass_expiry_ts as signed integer)<=? and (cast(pass_expiry_ts as signed integer) + cast(modify_ts as signed integer) < ?)",
Expand All @@ -7204,9 +7262,9 @@ auto db_update_pam_password_op(irods::plugin_context& _ctx,
iVal[1] = sizeof( passwordModifyTime );
{
std::vector<std::string> bindVars;
bindVars.push_back( selUserId );
bindVars.push_back( irods_pam_password_min_time );
bindVars.push_back( irods_pam_password_max_time );
bindVars.emplace_back(selUserId);
bindVars.emplace_back(ac.password_min_time_str.data());
bindVars.emplace_back(ac.password_max_time_str.data());
status = cmlGetStringValuesFromSql(
#if MY_ICAT
"select rcat_password, modify_ts from R_USER_PASSWORD where user_id=? and pass_expiry_ts not like '9999%' and cast(pass_expiry_ts as signed integer) >= ? and cast (pass_expiry_ts as signed integer) <= ?",
Expand All @@ -7217,7 +7275,7 @@ auto db_update_pam_password_op(irods::plugin_context& _ctx,
}

if ( status == 0 ) {
if ( !irods_pam_auth_no_extend ) {
if (ac.password_extend_lifetime) {
if ( logSQL != 0 ) {
log_sql::debug("chlUpdateIrodsPamPassword SQL 4");
}
Expand All @@ -7237,7 +7295,7 @@ auto db_update_pam_password_op(irods::plugin_context& _ctx,
log_db::info("chlUpdateIrodsPamPassword cmlExecuteNoAnswerSql commit failure {}", status);
return ERROR( status, "commit failure" );
}
} // if !irods_pam_auth_no_extend
}

// random_password is the randomly generated password (see while loop below) in a scrambled form.
icatDescramble(random_password.data());
Expand Down Expand Up @@ -7463,9 +7521,17 @@ irods::error db_mod_user_op(
}

if ( strncmp( _option, "rmPamPw", 9 ) == 0 ) {
auth_config ac{};
if (const auto err = get_auth_config(_ctx, "authentication::pam_password", ac); !err.ok()) {
irods::log(err);
log_db::warn("Failed to get password configuration - using defaults.");
}

rstrcpy( tSQL, form7, MAX_SQL_SIZE );
cllBindVars[cllBindVarCount++] = irods_pam_password_min_time;
cllBindVars[cllBindVarCount++] = irods_pam_password_max_time;
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
cllBindVars[cllBindVarCount++] = ac.password_min_time_str.data();
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
cllBindVars[cllBindVarCount++] = ac.password_max_time_str.data();
cllBindVars[cllBindVarCount++] = userName2;
cllBindVars[cllBindVarCount++] = zoneName;
if ( logSQL != 0 ) {
Expand Down

0 comments on commit 9d34ffd

Please sign in to comment.