std::pair fetch_gmsa_password_and_create_krb_ticket()

in auth/kerberos/src/krb.cpp [108:244]


std::pair<int, std::string> fetch_gmsa_password_and_create_krb_ticket(
    std::string domain_name, krb_ticket_info_t* krb_ticket, const std::string& krb_cc_name,
    CF_logger& cf_logger )
{
    std::vector<std::string> results;
    std::string gmsa_account_name = "";
    std::string distinguished_name = "";

    if ( krb_ticket != NULL )
    {
        gmsa_account_name = krb_ticket->service_account_name;
        distinguished_name = krb_ticket->distinguished_name;
    }

    if ( domain_name.empty() || gmsa_account_name.empty() )
    {
        std::string log_message =
            "ERROR: " + std::string( __func__ ) + ": " + std::to_string( __LINE__ ) + " null args";
        cf_logger.logger( LOG_ERR, log_message.c_str() );
        std::string err_msg = std::string( "domain_name " + domain_name + " or gmsa_account_name " +
                                           gmsa_account_name + " is empty" );
        return std::make_pair( -1, err_msg );
    }

    std::pair<int, std::string> ldap_search_result;
    std::string base_dn = "";

    std::pair<int, std::string> base_dn_result = Util::get_base_dn( domain_name );
    if ( base_dn_result.first == 0 && !base_dn_result.second.empty() )
    {
        base_dn = base_dn_result.second;
    }

    if ( distinguished_name.empty() && getenv( ENV_CF_GMSA_OU ) != NULL )
    {
        distinguished_name = std::string( getenv( ENV_CF_GMSA_OU ) );
    }

    std::vector<std::string> fqdn_list_result = Util::get_FQDN_list( domain_name );
    for ( auto fqdn : fqdn_list_result )
    {
        if ( distinguished_name.empty() )
        {
            std::pair<int, std::string> distinguished_name_result =
                Util::find_dn( gmsa_account_name, base_dn, fqdn );
            if ( distinguished_name_result.first == 0 && !distinguished_name_result.second.empty() )
            {
                distinguished_name = distinguished_name_result.second;
            }
            std::string log_str = "Found dn = " + distinguished_name;
            cf_logger.logger( LOG_INFO, log_str.c_str() );
        }

        krb_ticket->distinguished_name = distinguished_name;
        // Then find the password
        std::string search_string = std::string(
            " -s sub  '(objectClass=msDs-GroupManagedServiceAccount)' msDS-ManagedPassword" );
        ldap_search_result =
            Util::execute_ldapsearch( gmsa_account_name, distinguished_name, fqdn, search_string );
        if ( ldap_search_result.first == 0 )
        {
            std::size_t pos = ldap_search_result.second.find( "msDS-ManagedPassword:" );
            if ( pos != std::string::npos )
            {
                std::string log_str = ldap_search_result.second.substr( 0, pos );
                log_str = "ldapsearch successful with FQDN = " + fqdn + ", cmd = " + log_str + "," +
                          "search_string = " + search_string;
                std::cerr << log_str << std::endl;
                cf_logger.logger( LOG_INFO, log_str.c_str() );
            }
            break;
        }
        else
        {
            std::string log_str = "ldapsearch failed with FQDN = " + fqdn + " " +
                                  ldap_search_result.second.c_str() + " " + search_string;
            std::cerr << log_str << std::endl;
            cf_logger.logger( LOG_INFO, log_str.c_str() );
        }
    }
    fqdn_list_result.clear();

    if ( ldap_search_result.first != 0 ) // ldapsearch did not work in any FQDN
    {
        return std::make_pair( -1, std::string( "" ) );
    }

    std::pair<size_t, void*> password_found_result =
        Util::find_password( ldap_search_result.second );
    OPENSSL_cleanse( (void*)ldap_search_result.second.c_str(),
                     strlen( ldap_search_result.second.c_str() ) );

    if ( password_found_result.first == 0 || password_found_result.second == nullptr )
    {
        std::string log_str = Util::getCurrentTime() + '\t' + "ERROR: Password not found";
        std::cerr << log_str << std::endl;
        cf_logger.logger( LOG_ERR, log_str.c_str() );
        return std::make_pair( -1, log_str );
    }

    blob_t* blob = ( (blob_t*)password_found_result.second );
    auto* blob_password = (uint8_t*)blob->current_password;

    std::transform( domain_name.begin(), domain_name.end(), domain_name.begin(),
                    []( unsigned char c ) { return std::toupper( c ); } );
    std::string default_principal = "'" + gmsa_account_name + "$'" + "@" + domain_name;

    /* Pipe password to the utf16 decoder and kinit */
    std::string kinit_cmd = std::string("dotnet ") + std::string( install_path_for_decode_exe ) +
                            std::string( " | kinit " ) + std::string( " -c " ) + krb_cc_name +
                            " -V " + default_principal;
    std::cerr << Util::getCurrentTime() << '\t' << "INFO:" << kinit_cmd << std::endl;
    FILE* fp = popen( kinit_cmd.c_str(), "w" );
    if ( fp == nullptr )
    {
        perror( "kinit failed" );
        OPENSSL_cleanse( password_found_result.second, password_found_result.first );
        OPENSSL_free( password_found_result.second );
        std::string log_message = "ERROR: " + std::string( __func__ ) + " : " +
                                  std::to_string( __LINE__ ) + " kinit failed";
        cf_logger.logger( LOG_ERR, log_message.c_str() );
        std::cerr << Util::getCurrentTime() << '\t' << "ERROR: kinit failed" << std::endl;
        return std::make_pair( -1, std::string( "kinit failed" ) );
    }
    fwrite( blob_password, 1, GMSA_PASSWORD_SIZE, fp );
    int error_code = pclose( fp );

    // kinit output
    std::string log_str = Util::getCurrentTime() + '\t' +
                          "INFO: kinit return value = " + std::to_string( error_code );
    std::cerr << log_str << std::endl;
    cf_logger.logger( LOG_ERR, log_str.c_str() );

    OPENSSL_cleanse( password_found_result.second, password_found_result.first );

    return std::make_pair( error_code, krb_cc_name );
}