我安装了带有 kdc 服务器和客户端的 kerberos。它们都可以工作,我可以通过kinit毫无问题地生成票证。但是,我无法通过MIT Kerberos API做到这一点。我有以下代码,它应该使用 kdc 生成一个票证:
#include <stdio.h>
#include <krb5.h>
#include <com_err.h>
#include <string.h>
#include <unistd.h>
#define TKT_LIFETIME 30
#define NO_REPLAYCACHE
static void syslog_err(const char* tag, long code, const char*format, va_list args){
printf("%s: %s in %sn", tag, error_message(code), format);
}
#define check_code(err, tag)
if(err){
void (*proc)(const char*, long, const char*, va_list);
proc=set_com_err_hook(syslog_err);
com_err("Error: ",(err),(tag));
(void)set_com_err_hook(proc);
goto cleanup;
}
int main() {
const char *username="foo@DOMAIN.COM";
const char *password="pass";
//const char *host="";
const char kt_pathname[256] = "/etc/krb5.keytab";
const char service[256]="krbtgt/DOMAIN.COM";
const char host[256]="DOMAIN.COM";
krb5_error_code err;
krb5_context context;
krb5_auth_context auth_context = NULL;
krb5_creds credentials;
krb5_principal user_principal,
service_principal;
krb5_keytab keytab=NULL;
krb5_ccache ccache;
char ccache_name[L_tmpnam + 8];
krb5_get_init_creds_opt * gic_options;
#ifndef NO_REPLAYCACHE
krb5_verify_init_creds_opt vic_options;
#endif
krb5_data apreq_pkt;
char myhostname[256],sprinc[256];
int have_user_principal =0,
have_service_principal=0,
have_keytab=0,
have_credentials=0,
success=-1;
apreq_pkt.data=NULL;
/* --------------------------------------------------------------------------------- */
err = krb5_init_context(&context);
check_code(err, "init context");
(void) memset(ccache_name,0,sizeof(ccache_name));
(void) strcpy(ccache_name, "MEMORY:");
(void) mkstemp(&ccache_name[7]);
err = krb5_cc_resolve(context,ccache_name,&ccache);
/* else:
* err = krb5_cc_default(context,&ccache);
*/
if(err != 0) printf("[*] Error resolving credential cache name. Code: %dn", err);
err = krb5_parse_name(context, username, &user_principal);
if(err != 0) printf("[*] Error parsing kerberos name. Code: %dn", err);
else have_user_principal=1;
err = krb5_cc_initialize(context,ccache,user_principal);
if(err != 0) printf("[*] Error initializing credential cache. Code: %dn", err);
(void) memset( (char*)&credentials, 0, sizeof(credentials));
// TODO: swtich later to: (void) gethostname(myhostname, sizeof(myhostname));
// TODO: not sure if double pointer.
krb5_get_init_creds_opt_alloc(context, &gic_options); // Allocate a new initial credential options structure
krb5_get_init_creds_opt_set_tkt_life(gic_options, TKT_LIFETIME); // Set the ticket lifetime in initial credential options
err = krb5_get_init_creds_password(context, &credentials, user_principal,password,0,0,0,NULL,gic_options); //Get initial credentials using a password
switch(err){
case 0:
have_credentials=1;
printf("[*] Successfully received credentialsn");
break;
case KRB5KDC_ERR_PREAUTH_FAILED:
printf("[*] Generic Pre-athentication failure. Unable to login. Access denied.n");
case KRB5KRB_AP_ERR_BAD_INTEGRITY:
printf("[*] Decrypt integrity check failed - no domain controllern");
case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
printf("[*] Bad username or passwordn");
case KRB5_KDC_UNREACH:
printf("[*] Cannot contact any KDC for requested realmn");
case KRB5_LIBOS_PWDINTR:
printf("[*] Password read interruptedn");
case KRB5_REALM_CANT_RESOLVE:
printf("[*] Cannot resolve network address for KDC in requested realmn");
case KRB5KDC_ERR_KEY_EXP:
printf("[*] Password has expiredn");
case KRB5_LIBOS_BADPWDMATCH:
printf("[*] Password mismatchn");
case KRB5_CHPW_PWDNULL:
printf("[*] New password cannot be zero lengthn");
case KRB5_CHPW_FAIL:
printf("[*] Password change failedn");
default:
success=0;
break;
}
err = krb5_cc_store_cred(context, ccache, &credentials); // Store credentials in a credential cache
if (err != 0)
printf("[*] Failed storing credentials in credential cachen");
char ***realmsp=malloc(sizeof(***realmsp));
err = krb5_get_host_realm(context, NULL,realmsp);
check_code(err, "krb5_get_host_realm");
free(realmsp);
err = krb5_sname_to_principal(context,host,service,KRB5_NT_SRV_HST,&service_principal); //Generate a full principal name from a service name KRB5_NT_UNKNOWN
check_code(err, "sname_to_principal");
have_service_principal=1;
err = krb5_kt_resolve(context,kt_pathname,&keytab); //Get a handle for a key table
check_code(err, "kt_resolve");
have_keytab=1;
/*
* A replay cache keeps track of all authenticators recenntly presented to a service. If a duplicate authneitcation request is detected in the replay cache,
* an error message is sent to application program
*/
#ifndef NO_REPLAYCACHE
krb5_verify_init_creds_opt_init(&vic_options); //Initialize a credential verification options structure
krb5_verify_init_creds_opt_set_ap_req_nofail(&vic_options,1); //Set whether credential verification is required
err = krb5_verify_init_creds(context, &credentials, service_principal, keytab,0,&vic_options); //Verify initial credentials against a keytab
check_code(err,"verify init credentials");
#else
//**********************************************CODE FAILES IN THE FOLLOWING FUNCTION **********************
err = krb5_mk_req(context,&auth_context,0,service,host,NULL,ccache,&apreq_pkt);
if(auth_context){
krb5_auth_con_free(context,auth_context); //Free a krb5_auth_context structure.
auth_context=NULL;
}
err = krb5_auth_con_init(context,&auth_context); //Create and initialize an authentication context
if (err!=0)
printf("[*] Failed to initialize an authentication contextn");
err = krb5_auth_con_setflags(context,auth_context,~KRB5_AUTH_CONTEXT_DO_TIME); //Set a flags field in a krb5_auth_context structure
if (err!=0)
printf("[*] Failed to set flags in context structuren");
err = krb5_rd_req(context,&auth_context,&apreq_pkt,service_principal,keytab,NULL,NULL); // This function parses, decrypts and verifies a AP-REQ message
if (err!=0)
printf("[*] Failed to decrypt/parse AP-REQ message n");
if(auth_context){
krb5_auth_con_free(context,auth_context); //Free a krb5_auth_context structure.
auth_context=NULL;
}
#endif
err = krb5_cc_destroy(context,ccache);
if (err!=0)
printf("[*] Failed to destroy kerberos context n");
else
success=1;
cleanup:
if(apreq_pkt.data)
krb5_free_data_contents(context,&apreq_pkt); // Free the contents of a krb5_data structure and zero the data field
if(have_keytab){
krb5_kt_close(context,keytab);
if (err!=0)
printf("[*] Failed to destroy the keytab n"); //Close a key table handle
}
if(have_user_principal)
krb5_free_principal(context,user_principal);
if(have_service_principal)
krb5_free_principal(context,service_principal);
if(have_credentials)
krb5_free_cred_contents(context,&credentials);
if(context)
krb5_free_context(context);
return 0;
}
当代码到达"krb5_mk_req"函数时,它会失败并显示错误:"在 Kerberos 数据库中找不到服务器"。我尝试了许多与服务+主机的组合,但没有一个有效。在 kinit 中,我可以使用"kinit -S krbtgt@DOMAIN.COM"生成有效的票证。我错过了什么?(DOMAIN.COM 不是我真正的领域(
谢谢!
似乎如果数据库尚不可用,则必须创建数据库,否则必须在 kerberos 配置文件中对其进行配置。请查看以下链接,其中解释了如何创建或配置 kdc 数据库。 https://www.thetechnojournals.com/2019/12/setting-up-kerberos-in-mac-os-x.html