Query: “krb5_get_init_creds_keytab” failing with message "Key table entry not found"

nitin dangwal nitindangwal at gmail.com
Fri Jul 9 16:58:09 EDT 2010


Kerberos version:  krb5-1.5.3
OS: Windows


I am trying to login a principal using Kerberos. However during the process
of initializing Kerberos, API  “krb5_get_init_creds_keytab” is returning a
failure. It seems that there are two alternative APIs available (VIZ
krb5_get_init_creds_password API and krb5_get_init_creds API) which can be
used instead of krb5_get_init_creds_keytab. If I modify my sample program to
use krb5_get_init_creds_password API, things seems to be working fine.
However in the actual application I don't have handle to password. So using
krb5_get_init_creds_password API is really not an option for
me.krb5_get_init_creds API doesn't seem to be available in the version of
Kerberos that I am using. So the only option that I am left with is to use
krb5_get_init_creds_keytab only. Can anyone please take a look at the sample
program and let me know if I am doing anything incorrectly.Sample Code:


/*
* Kerberos.h
*/



#ifndef __KERBEROS_H__
#define __KERBEROS_H__

#include <stdio.h>
#include <gssapi/gssapi.h>
#include <krb5/krb5.h>

#include "Status.h"

#define KERBEROS_STATUS_CODE_BASE 100

#define KERBEROS_STATUS_MESSAGE_DEFAULT                        "No text
available"
#define KERBEROS_STATUS_MESSAGE_SUCCESS                        "Success"
#define KERBEROS_STATUS_MESSAGE_CCACHE_NOT_INITIALIZED         "Credentials
Cache not initialized"
#define KERBEROS_STATUS_MESSAGE_ALREADY_LOGGED_IN              "Already
logged in"
#define KERBEROS_STATUS_MESSAGE_ALLOC_FAILURE                  "Memory
allocation failure"

enum eCSmKerberosStatusCode
{
    KERBEROS_STATUS_CODE_DEFAULT                             =
KERBEROS_STATUS_CODE_BASE,
    KERBEROS_STATUS_CODE_SUCCESS,
    KERBEROS_STATUS_CODE_CCACHE_NOT_INITIALIZED,
    KERBEROS_STATUS_CODE_ALREADY_LOGGED_IN,
    KERBEROS_STATUS_CODE_ALLOC_FAILURE
};

class CredCache
{
      private:

        krb5_context          m_hContext;
        krb5_principal        m_pnPrincipal;
        krb5_principal        m_pnTGS;
        krb5_ccache           m_hCache;

        char *                m_pszTGS;
        char *                m_sPrincipal;

        CredCache () :
            m_hContext          (NULL),
            m_hCache            (NULL),
            m_pnPrincipal       (NULL),
            m_pnTGS             (NULL),
            m_pszTGS            (NULL),
            m_sPrincipal        (NULL)
        {
        }
        ~CredCache();
      public:
        static CredCache * GetInstance();
        Status Login (char * sService, FILE* fp);
        char* &Principal ()
        {
            return m_sPrincipal;
        }
      friend class Status;
      private:
        bool Init ();
        void UnInit ();

};

#endif // __KERBEROS_H__

//EOF

//------------------------------------------------------------------------

/*
* Kerberos.cpp
*/

#include "Kerberos.h"
#include "Status.h"

/**
* CredCache Functions
**/
CredCache::~CredCache ()
{
   UnInit();
}

CredCache * CredCache::GetInstance()
{
    static CredCache theCredCache;
    return (theCredCache.Init()) ? &theCredCache : NULL;
}

bool CredCache::Init ()
{
    if (NULL == m_hContext)
    {
        // Initialize Kerberos context
        if (krb5_init_context (&m_hContext)) return false;
    }

    if (NULL == m_hCache)
    {
        // Create default credentials cache
        if (krb5_cc_default (m_hContext, &m_hCache))
        {
            UnInit();
            return false;
        }
    }

    return true;
}

void CredCache::UnInit()
{
    if (m_hContext)
    {
        if (m_pnPrincipal)
        {
            krb5_free_principal (m_hContext, m_pnPrincipal);
            m_pnPrincipal = NULL;
        }

        if (m_pnTGS)
        {
            krb5_free_principal (m_hContext, m_pnTGS);
            m_pnTGS = NULL;
        }

        if (m_pszTGS)
        {
            krb5_free_unparsed_name (m_hContext, m_pszTGS);
            m_pszTGS = NULL;
        }

        if (m_hCache)
        {
            krb5_cc_close (m_hContext, m_hCache);
            m_hCache = NULL;
        }

        krb5_free_context (m_hContext);
        m_hContext = NULL;
    }
}

Status CredCache::Login (char* sPrincipal, FILE* fp)
{
    fprintf(fp, "sPrincipal: %s. \n",sPrincipal);

    // Do not proceed unless the credential cache has been initialized
    if (!m_hContext || !m_hCache)
    {
        fprintf(fp, "Error: Cache not Initialized. Exiting. \n");
        return Status (GSS_S_FAILURE,
KERBEROS_STATUS_CODE_CCACHE_NOT_INITIALIZED);
    }
    fprintf(fp, "Context and Cache initialization OK.\n");

    if (m_pnPrincipal && m_pnTGS && m_pszTGS)
    {
        fprintf(fp, "Service is already logged in.Exiting.\n");
        return Status (GSS_S_COMPLETE,
KERBEROS_STATUS_CODE_ALREADY_LOGGED_IN);
    }

    // Make principal ("service/host at realm")
    krb5_error_code nStatus;

    nStatus = krb5_parse_name (m_hContext, sPrincipal, &m_pnPrincipal);
    if (nStatus)
    {
        fprintf(fp, "Krb: Parse name failed.\n");
        return Status (GSS_S_FAILURE, nStatus);
    }
    fprintf(fp, "Krb: Parse name returned SUCCESS.\n");

    krb5_data dTGSName = { 0, KRB5_TGS_NAME_SIZE, (char *) KRB5_TGS_NAME };
    krb5_data * pdRealm = krb5_princ_realm (m_hContext, m_pnPrincipal);

    nStatus = krb5_build_principal_ext (m_hContext, &m_pnTGS,
                                       pdRealm->length, pdRealm->data,   //
'@' realm
                                       dTGSName.length, dTGSName.data,   //
krbtgt
                                       pdRealm->length, pdRealm->data,   //
'/' realm
                                       0);
    if (nStatus)
    {
        fprintf(fp, "krb5_build_principal_ext failed.\n");
        return Status (GSS_S_FAILURE, nStatus);
    }
    fprintf(fp, "krb5_build_principal_ext: returned SUCCESS.\n");

    nStatus = krb5_unparse_name (m_hContext, m_pnTGS, &m_pszTGS);
    if (nStatus)
    {
        fprintf(fp, "krb5_unparse_name failed.\n");
        return Status (GSS_S_FAILURE, nStatus);
    }
    fprintf(fp, "krb5_unparse_name: returned SUCCESS.\n");

    krb5_creds credTGT;

    credTGT.client = m_pnPrincipal;
    credTGT.server = m_pnTGS;

    krb5_get_init_creds_opt hOptions;
    krb5_get_init_creds_opt_init (&hOptions);

    krb5_keytab Keytab;

    nStatus = krb5_kt_default (m_hContext, &Keytab);
    if (nStatus)
    {
        fprintf(fp, "krb5_kt_default failed.\n");
        return Status (GSS_S_FAILURE, nStatus);
    }
    fprintf(fp, "krb5_kt_default: returned SUCCESS.\n");

    nStatus = krb5_get_init_creds_keytab (m_hContext, &credTGT,
m_pnPrincipal, Keytab,
        0, m_pszTGS, &hOptions);
    if (nStatus)
    {
        fprintf(fp, "krb5_get_init_creds_keytab failed.\n");
        return Status (GSS_S_FAILURE, nStatus);
    }
    fprintf(fp, "krb5_get_init_creds_keytab: returned: SUCCESS.\n");

    nStatus = krb5_cc_initialize (m_hContext, m_hCache, m_pnPrincipal);
    if (nStatus)
    {
        fprintf(fp, "krb5_cc_initialize failed.\n");
        return Status (GSS_S_FAILURE, nStatus);
    }
    fprintf(fp, "krb5_cc_initialize: returned: SUCCESS.\n");

    nStatus = krb5_cc_store_cred (m_hContext, m_hCache, &credTGT);
    if (nStatus)
    {
        fprintf(fp, "krb5_cc_store_cred failed.\n");
        return Status (GSS_S_FAILURE, nStatus);
    }
    fprintf(fp, "krb5_cc_store_cred: returned SUCCESS.\n");

    return Status (GSS_S_COMPLETE, KERBEROS_STATUS_CODE_SUCCESS);
}

//EOF

//------------------------------------------------------------------------

/*
* Status.h
*/

#ifndef __STATUS_H__
#define __STATUS_H__

#include "gssapi/gssapi.h"
#include "krb5/krb5.h"

class Status
{
      private:

        static const char * c_arMessages [];
        const char * m_pszMessage;

        OM_uint32 m_nMajor;
        OM_uint32 m_nMinor;

      public:

        Status ();
        Status (OM_uint32 nMajor, OM_uint32 nMinor);
        //~Status ();
        Status &operator= (const Status &cStatus);

        const char * Message ();
        bool Fail () const;
        bool Complete () const;
        bool Continue () const;
        OM_uint32 Major () const;
        OM_uint32 Minor () const;
};

#endif

//EOF

//------------------------------------------------------------------------

/*
* Status.cpp
*/


#include "Kerberos.h"
#include "Status.h"

#define IS_KERBEROS_STATUS_CODE(x) ((KERBEROS_STATUS_CODE_BASE <= x) && (x
<= KERBEROS_STATUS_CODE_BASE + sizeof (Status::c_arMessages)/sizeof
(Status::c_arMessages[0]) ))

const char *Status::c_arMessages [] =
{
    KERBEROS_STATUS_MESSAGE_DEFAULT,
    KERBEROS_STATUS_MESSAGE_SUCCESS,
    KERBEROS_STATUS_MESSAGE_CCACHE_NOT_INITIALIZED,
    KERBEROS_STATUS_MESSAGE_ALREADY_LOGGED_IN,
    KERBEROS_STATUS_MESSAGE_ALLOC_FAILURE
};

Status::Status () :
    m_nMajor (GSS_S_FAILURE),
    m_nMinor (KERBEROS_STATUS_CODE_DEFAULT),
    m_pszMessage (c_arMessages[KERBEROS_STATUS_CODE_DEFAULT -
KERBEROS_STATUS_CODE_BASE])
{
}

Status::Status (OM_uint32 nMajor, OM_uint32 nMinor) :
    m_nMajor (nMajor),
    m_nMinor (nMinor),
    m_pszMessage (c_arMessages[KERBEROS_STATUS_CODE_DEFAULT -
KERBEROS_STATUS_CODE_BASE])
{
}


Status& Status::operator= (const Status &cStatus)
{
    m_nMajor = cStatus.m_nMajor;
    m_nMinor = cStatus.m_nMinor;
    m_pszMessage = cStatus.m_pszMessage;

    return *this;
}


const char * Status::Message ()
{
    if (IS_KERBEROS_STATUS_CODE(m_nMinor))
    {
        m_pszMessage = c_arMessages [m_nMinor - KERBEROS_STATUS_CODE_BASE];
    }
    else // If the error code is not a native error code, try to fetch the
error text from kerberos
    {
        CredCache * pCC = CredCache::GetInstance();
        if (pCC)
        {
            char * pszMessage = krb5_get_error_message (pCC->m_hContext,
(krb5_error_code) m_nMinor);
            if (pszMessage && *pszMessage)
            {
                m_pszMessage = pszMessage;
            }
            else
            {
                m_pszMessage = c_arMessages[KERBEROS_STATUS_CODE_DEFAULT -
KERBEROS_STATUS_CODE_BASE];
            }
        }
    }

    return m_pszMessage;
}

bool Status::Fail () const
{
    return (GSS_ERROR(m_nMajor) != 0);
}

bool Status::Complete () const
{
    return (m_nMajor == GSS_S_COMPLETE);
}

bool Status::Continue () const
{
    return (m_nMajor == GSS_S_CONTINUE_NEEDED);
}

OM_uint32 Status::Major () const
{
    return m_nMajor;
}

OM_uint32 Status::Minor () const
{
    return m_nMinor;
}


//EOF

//------------------------------------------------------------------------

/*
* sample.cpp
*/

// sample.cpp : Defines the entry point for the console application.
//

#include <stdio.h>

#include "Kerberos.h"
#include "Status.h"

void main()
{
    FILE* fp;
    fp = fopen("Trace.log","a+");

    CredCache * pCredCache = CredCache::GetInstance();
    if (!pCredCache)
    {
        fprintf(fp, "CredCache::GetInstance failed.\n");
    }

    char* sHttpServicePrincipal = "HTTP/cookie.sample.lab at SAMPLE.LAB";

    fprintf(fp, "CredCache::Login called.\n");
    Status kStatus = pCredCache->Login (sHttpServicePrincipal, fp);

    if (kStatus.Fail())
    {
        fprintf(fp, "Kerberos Credential Cache login failed with service
principal %s: %s", sHttpServicePrincipal, kStatus.Message());
    }
    else
    {
        fprintf(fp, "Request Completed Successfully.");
    }
    fflush(fp);
    fclose(fp);
}


On execution, I am getting following log entries:
CredCache::Login called.
sPrincipal: HTTP/cookie.sample.lab at SAMPLE.LAB.
Context and Cache initialization OK.
Krb: Parse name returned SUCCESS.
krb5_build_principal_ext: returned SUCCESS.
krb5_unparse_name: returned SUCCESS.
krb5_kt_default: returned SUCCESS.
krb5_get_init_creds_keytab failed.
Kerberos Credential Cache login failed with service principal
HTTP/cookie.sample.lab at SAMPLE.LAB: Key table entry not found



More information about the Kerberos mailing list