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