Enabled to load shared library for Credential and Token (#1927)

This commit is contained in:
Takeshi Nakatani
2022-10-22 10:42:07 +09:00
committed by GitHub
parent 9a4282208e
commit 6e89e69bba
8 changed files with 592 additions and 20 deletions

View File

@ -23,6 +23,7 @@
#include <pwd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dlfcn.h>
#include <fstream>
#include <sstream>
@ -36,13 +37,85 @@
//-------------------------------------------------------------------
// Symbols
//-------------------------------------------------------------------
#define DEFAULT_AWS_PROFILE_NAME "default"
#define DEFAULT_AWS_PROFILE_NAME "default"
//-------------------------------------------------------------------
// External Credential dummy function
//-------------------------------------------------------------------
// [NOTE]
// This function expects the following values:
//
// detail=false ex. "Custom AWS Credential Library - v1.0.0"
// detail=true ex. "Custom AWS Credential Library - v1.0.0
// s3fs-fuse credential I/F library for S3 compatible strage X.
// Copyright(C) 2022 Foo"
//
const char* VersionS3fsCredential(bool detail)
{
static const char version[] = "built-in";
static const char detail_version[] =
"s3fs-fuse built-in Credential I/F Function\n"
"Copyright(C) 2007 s3fs-fuse\n";
S3FS_PRN_CRIT("Check why built-in function was called, the external credential library must have VersionS3fsCredential function.");
if(detail){
return detail_version;
}else{
return version;
}
}
bool InitS3fsCredential(const char* popts, char** pperrstr)
{
if(popts && 0 < strlen(popts)){
S3FS_PRN_WARN("The external credential library does not have InitS3fsCredential function, but credlib_opts value is not empty(%s)", popts);
}
if(pperrstr){
*pperrstr = strdup("The external credential library does not have InitS3fsCredential function, so built-in function was called.");
}else{
S3FS_PRN_INFO("The external credential library does not have InitS3fsCredential function, so built-in function was called.");
}
return true;
}
bool FreeS3fsCredential(char** pperrstr)
{
if(pperrstr){
*pperrstr = strdup("The external credential library does not have FreeS3fsCredential function, so built-in function was called.");
}else{
S3FS_PRN_INFO("The external credential library does not have FreeS3fsCredential function, so built-in function was called.");
}
return true;
}
bool UpdateS3fsCredential(char** ppaccess_key_id, char** ppserect_access_key, char** ppaccess_token, long long* ptoken_expire, char** pperrstr)
{
S3FS_PRN_INFO("Parameters : ppaccess_key_id=%p, ppserect_access_key=%p, ppaccess_token=%p, ptoken_expire=%p", ppaccess_key_id, ppserect_access_key, ppaccess_token, ptoken_expire);
if(pperrstr){
*pperrstr = strdup("Check why built-in function was called, the external credential library must have UpdateS3fsCredential function.");
}else{
S3FS_PRN_CRIT("Check why built-in function was called, the external credential library must have UpdateS3fsCredential function.");
}
if(ppaccess_key_id){
*ppaccess_key_id = NULL;
}
if(ppserect_access_key){
*ppserect_access_key = NULL;
}
if(ppaccess_token){
*ppaccess_token = NULL;
}
return false; // always false
}
//-------------------------------------------------------------------
// Class Variables
//-------------------------------------------------------------------
const char* S3fsCred::ALLBUCKET_FIELDS_TYPE = "";
const char* S3fsCred::KEYVAL_FIELDS_TYPE = "\t";
const char* S3fsCred::KEYVAL_FIELDS_TYPE = "\t";
const char* S3fsCred::AWS_ACCESSKEYID = "AWSAccessKeyId";
const char* S3fsCred::AWS_SECRETKEY = "AWSSecretKey";
@ -73,7 +146,7 @@ bool S3fsCred::SetBucket(const char* bucket)
const std::string& S3fsCred::GetBucket()
{
return S3fsCred::bucket_name;
return S3fsCred::bucket_name;
}
bool S3fsCred::ParseIAMRoleFromMetaDataResponse(const char* response, std::string& rolename)
@ -110,7 +183,13 @@ S3fsCred::S3fsCred() :
IAM_api_version(2),
IAM_field_count(4),
IAM_token_field("Token"),
IAM_expiry_field("Expiration")
IAM_expiry_field("Expiration"),
set_builtin_cred_opts(false),
hExtCredLib(NULL),
pFuncCredVersion(VersionS3fsCredential),
pFuncCredInit(InitS3fsCredential),
pFuncCredFree(FreeS3fsCredential),
pFuncCredUpdate(UpdateS3fsCredential)
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
@ -127,6 +206,8 @@ S3fsCred::S3fsCred() :
S3fsCred::~S3fsCred()
{
UnloadExtCredLib();
if(is_lock_init){
int result;
if(0 != (result = pthread_mutex_destroy(&token_lock))){
@ -150,7 +231,7 @@ bool S3fsCred::SetS3fsPasswdFile(const char* file)
return true;
}
bool S3fsCred::IsSetPasswdFile()
bool S3fsCred::IsSetPasswdFile() const
{
return !passwd_file.empty();
}
@ -424,7 +505,7 @@ bool S3fsCred::LoadIAMCredentials(AutoLock::Type type)
S3FS_PRN_ERR("Something error occurred, could not set IAM role name.");
return false;
}
return true;
return true;
}
//
@ -551,7 +632,7 @@ bool S3fsCred::CheckS3fsPasswdFilePerms()
return false;
}
// Check readable
// Check readable
if(!IsReadableS3fsPasswdFile()){
S3FS_PRN_EXIT("S3fs passwd file \"%s\" is not readable.", passwd_file.c_str());
return false;
@ -1066,14 +1147,21 @@ bool S3fsCred::CheckIAMCredentialUpdate(std::string* access_key_id, std::string*
{
AutoLock auto_lock(&token_lock);
if(IsSetIAMRole(AutoLock::ALREADY_LOCKED) || is_ecs || is_ibm_iam_auth){
if(hExtCredLib || IsSetIAMRole(AutoLock::ALREADY_LOCKED) || is_ecs || is_ibm_iam_auth){
if(AWSAccessTokenExpire < (time(NULL) + S3fsCred::IAM_EXPIRE_MERGIN)){
S3FS_PRN_INFO("IAM Access Token refreshing...");
// update
if(!LoadIAMCredentials(AutoLock::ALREADY_LOCKED)){
S3FS_PRN_ERR("IAM Access Token refresh failed");
return false;
if(!hExtCredLib){
if(!LoadIAMCredentials(AutoLock::ALREADY_LOCKED)){
S3FS_PRN_ERR("Access Token refresh by built-in failed");
return false;
}
}else{
if(!UpdateExtCredentials(AutoLock::ALREADY_LOCKED)){
S3FS_PRN_ERR("Access Token refresh by %s(external credential library) failed", credlib.c_str());
return false;
}
}
S3FS_PRN_INFO("IAM Access Token refreshed");
}
@ -1097,6 +1185,217 @@ bool S3fsCred::CheckIAMCredentialUpdate(std::string* access_key_id, std::string*
return true;
}
const char* S3fsCred::GetCredFuncVersion(bool detail) const
{
static const char errVersion[] = "unknown";
if(!pFuncCredVersion){
return errVersion;
}
return (*pFuncCredVersion)(detail);
}
//-------------------------------------------------------------------
// Methods : External Credential Library
//-------------------------------------------------------------------
bool S3fsCred::SetExtCredLib(const char* arg)
{
if(!arg || strlen(arg) == 0){
return false;
}
credlib = arg;
return true;
}
bool S3fsCred::IsSetExtCredLib() const
{
return !credlib.empty();
}
bool S3fsCred::SetExtCredLibOpts(const char* args)
{
if(!args || strlen(args) == 0){
return false;
}
credlib_opts = args;
return true;
}
bool S3fsCred::IsSetExtCredLibOpts() const
{
return !credlib_opts.empty();
}
bool S3fsCred::InitExtCredLib()
{
if(!LoadExtCredLib()){
return false;
}
// Initialize library
if(!pFuncCredInit){
S3FS_PRN_CRIT("\"InitS3fsCredential\" function pointer is NULL, why?");
UnloadExtCredLib();
return false;
}
const char* popts = credlib_opts.empty() ? NULL : credlib_opts.c_str();
char* perrstr = NULL;
if(!(*pFuncCredInit)(popts, &perrstr)){
S3FS_PRN_ERR("Could not initialize %s(external credential library) by \"InitS3fsCredential\" function : %s", credlib.c_str(), perrstr ? perrstr : "unknown");
// cppcheck-suppress unmatchedSuppression
// cppcheck-suppress knownConditionTrueFalse
if(perrstr){
free(perrstr);
}
UnloadExtCredLib();
return false;
}
// cppcheck-suppress unmatchedSuppression
// cppcheck-suppress knownConditionTrueFalse
if(perrstr){
free(perrstr);
}
return true;
}
bool S3fsCred::LoadExtCredLib()
{
if(credlib.empty()){
return false;
}
UnloadExtCredLib();
S3FS_PRN_INFO("Load External Credential Library : %s", credlib.c_str());
// Open Library
//
// Search Library: (RPATH ->) LD_LIBRARY_PATH -> (RUNPATH ->) /etc/ld.so.cache -> /lib -> /usr/lib
//
if(NULL == (hExtCredLib = dlopen(credlib.c_str(), RTLD_LAZY))){
const char* preason = dlerror();
S3FS_PRN_ERR("Could not load %s(external credential library) by error : %s", credlib.c_str(), preason ? preason : "unknown");
return false;
}
// Set function pointers
if(NULL == (pFuncCredVersion = reinterpret_cast<fp_VersionS3fsCredential>(dlsym(hExtCredLib, "VersionS3fsCredential")))){
S3FS_PRN_ERR("%s(external credential library) does not have \"VersionS3fsCredential\" function which is required.", credlib.c_str());
UnloadExtCredLib();
return false;
}
if(NULL == (pFuncCredUpdate = reinterpret_cast<fp_UpdateS3fsCredential>(dlsym(hExtCredLib, "UpdateS3fsCredential")))){
S3FS_PRN_ERR("%s(external credential library) does not have \"UpdateS3fsCredential\" function which is required.", credlib.c_str());
UnloadExtCredLib();
return false;
}
if(NULL == (pFuncCredInit = reinterpret_cast<fp_InitS3fsCredential>(dlsym(hExtCredLib, "InitS3fsCredential")))){
S3FS_PRN_INFO("%s(external credential library) does not have \"InitS3fsCredential\" function which is optional.", credlib.c_str());
pFuncCredInit = InitS3fsCredential; // set built-in function
}
if(NULL == (pFuncCredFree = reinterpret_cast<fp_FreeS3fsCredential>(dlsym(hExtCredLib, "FreeS3fsCredential")))){
S3FS_PRN_INFO("%s(external credential library) does not have \"FreeS3fsCredential\" function which is optional.", credlib.c_str());
pFuncCredFree = FreeS3fsCredential; // set built-in function
}
S3FS_PRN_INFO("Succeed loading External Credential Library : %s", credlib.c_str());
return true;
}
bool S3fsCred::UnloadExtCredLib()
{
if(hExtCredLib){
S3FS_PRN_INFO("Unload External Credential Library : %s", credlib.c_str());
// Uninitialize library
if(!pFuncCredFree){
S3FS_PRN_CRIT("\"FreeS3fsCredential\" function pointer is NULL, why?");
}else{
char* perrstr = NULL;
if(!(*pFuncCredFree)(&perrstr)){
S3FS_PRN_ERR("Could not uninitialize by \"FreeS3fsCredential\" function : %s", perrstr ? perrstr : "unknown");
}
// cppcheck-suppress unmatchedSuppression
// cppcheck-suppress knownConditionTrueFalse
if(perrstr){
free(perrstr);
}
}
// reset
pFuncCredVersion = VersionS3fsCredential;
pFuncCredInit = InitS3fsCredential;
pFuncCredFree = FreeS3fsCredential;
pFuncCredUpdate = UpdateS3fsCredential;
// close
dlclose(hExtCredLib);
hExtCredLib = NULL;
}
return true;
}
bool S3fsCred::UpdateExtCredentials(AutoLock::Type type)
{
if(!hExtCredLib){
S3FS_PRN_CRIT("External Credential Library is not loaded, why?");
return false;
}
AutoLock auto_lock(&token_lock, type);
char* paccess_key_id = NULL;
char* pserect_access_key = NULL;
char* paccess_token = NULL;
char* perrstr = NULL;
long long token_expire = 0;
bool result = (*pFuncCredUpdate)(&paccess_key_id, &pserect_access_key, &paccess_token, &token_expire, &perrstr);
if(!result){
// error occurred
S3FS_PRN_ERR("Could not update credential by \"UpdateS3fsCredential\" function : %s", perrstr ? perrstr : "unknown");
// cppcheck-suppress unmatchedSuppression
// cppcheck-suppress knownConditionTrueFalse
}else if(!paccess_key_id || !pserect_access_key || !paccess_token || token_expire <= 0){
// some variables are wrong
S3FS_PRN_ERR("After updating credential by \"UpdateS3fsCredential\" function, but some variables are wrong : paccess_key_id=%p, pserect_access_key=%p, paccess_token=%p, token_expire=%lld", paccess_key_id, pserect_access_key, paccess_token, token_expire);
result = false;
}else{
// succeed updating
AWSAccessKeyId = paccess_key_id;
AWSSecretAccessKey = pserect_access_key;
AWSAccessToken = paccess_token;
AWSAccessTokenExpire = token_expire;
}
// clean
// cppcheck-suppress unmatchedSuppression
// cppcheck-suppress knownConditionTrueFalse
if(paccess_key_id){
free(paccess_key_id);
}
// cppcheck-suppress unmatchedSuppression
// cppcheck-suppress knownConditionTrueFalse
if(pserect_access_key){
free(pserect_access_key);
}
// cppcheck-suppress unmatchedSuppression
// cppcheck-suppress knownConditionTrueFalse
if(paccess_token){
free(paccess_token);
}
// cppcheck-suppress unmatchedSuppression
// cppcheck-suppress knownConditionTrueFalse
if(perrstr){
free(perrstr);
}
return result;
}
//-------------------------------------------------------------------
// Methods: Option detection
//-------------------------------------------------------------------
@ -1113,6 +1412,7 @@ int S3fsCred::DetectParam(const char* arg)
if(is_prefix(arg, "passwd_file=")){
SetS3fsPasswdFile(strchr(arg, '=') + sizeof(char));
set_builtin_cred_opts = true;
return 0;
}
@ -1123,11 +1423,13 @@ int S3fsCred::DetectParam(const char* arg)
SetIAMExpiryField("\"expiration\"");
SetIAMFieldCount(2);
SetIMDSVersion(1, AutoLock::NONE);
set_builtin_cred_opts = true;
return 0;
}
if(0 == strcmp(arg, "use_session_token")){
SetIsUseSessionToken(true);
set_builtin_cred_opts = true;
return 0;
}
@ -1142,11 +1444,13 @@ int S3fsCred::DetectParam(const char* arg)
}
endpoint_url = std::string(iam_endpoint) + "/identity/token";
SetIAMCredentialsURL(endpoint_url.c_str());
set_builtin_cred_opts = true;
return 0;
}
if(0 == strcmp(arg, "imdsv1only")){
SetIMDSVersion(1, AutoLock::NONE);
set_builtin_cred_opts = true;
return 0;
}
@ -1159,6 +1463,7 @@ int S3fsCred::DetectParam(const char* arg)
SetIMDSVersion(1, AutoLock::NONE);
SetIAMCredentialsURL("http://169.254.170.2");
SetIAMFieldCount(5);
set_builtin_cred_opts = true;
return 0;
}
@ -1171,18 +1476,37 @@ int S3fsCred::DetectParam(const char* arg)
// loading IAM role name in s3fs_init(), because we need to wait initializing curl.
//
SetIAMRoleMetadataType(true);
set_builtin_cred_opts = true;
return 0;
}else if(is_prefix(arg, "iam_role=")){
const char* role = strchr(arg, '=') + sizeof(char);
SetIAMRole(role, AutoLock::NONE);
SetIAMRoleMetadataType(false);
set_builtin_cred_opts = true;
return 0;
}
}
if(is_prefix(arg, "profile=")){
SetAwsProfileName(strchr(arg, '=') + sizeof(char));
set_builtin_cred_opts = true;
return 0;
}
if(is_prefix(arg, "credlib=")){
if(!SetExtCredLib(strchr(arg, '=') + sizeof(char))){
S3FS_PRN_EXIT("failed to set credlib option : %s", (strchr(arg, '=') + sizeof(char)));
return -1;
}
return 0;
}
if(is_prefix(arg, "credlib_opts=")){
if(!SetExtCredLibOpts(strchr(arg, '=') + sizeof(char))){
S3FS_PRN_EXIT("failed to set credlib_opts option : %s", (strchr(arg, '=') + sizeof(char)));
return -1;
}
return 0;
}
@ -1267,6 +1591,32 @@ bool S3fsCred::CheckAllParams()
return false;
}
}
// check External Credential Library
//
// [NOTE]
// If credlib(_opts) option (for External Credential Library) is specified,
// no other Credential related options can be specified. It is exclusive.
//
if(set_builtin_cred_opts && (IsSetExtCredLib() || IsSetExtCredLibOpts())){
S3FS_PRN_EXIT("The \"credlib\" or \"credlib_opts\" option and other credential-related options(passwd_file, iam_role, profile, use_session_token, ecs, imdsv1only, ibm_iam_auth, ibm_iam_endpoint, etc) cannot be specified together.");
return false;
}
// Load and Initialize external credential library
if(IsSetExtCredLib() || IsSetExtCredLibOpts()){
if(!IsSetExtCredLib()){
S3FS_PRN_EXIT("The \"credlib_opts\"(%s) is specifyed but \"credlib\" option is not specified.", credlib_opts.c_str());
return false;
}
if(!InitExtCredLib()){
S3FS_PRN_EXIT("failed to load the library specified by the option credlib(%s, %s).", credlib.c_str(), credlib_opts.c_str());
return false;
}
S3FS_PRN_INFO("Loaded External Credential Library:\n%s", GetCredFuncVersion(true));
}
return true;
}