#include "ntlm.h"
#include <gssapi_spi.h>
static OM_uint32
_gss_ntlm_have_cred(OM_uint32 *minor,
const ntlm_name target_name,
ntlm_cred *rcred)
{
krb5_context context;
krb5_error_code ret;
krb5_storage *request, *response;
krb5_data response_data;
OM_uint32 major;
ntlm_name cred;
kcmuuid_t uuid;
ssize_t sret;
ret = krb5_init_context(&context);
if (ret) {
*minor = ret;
return GSS_S_FAILURE;
}
ret = krb5_kcm_storage_request(context, KCM_OP_HAVE_NTLM_CRED, &request);
if (ret)
goto out;
ret = krb5_store_stringz(request, target_name->user);
if (ret)
goto out;
ret = krb5_store_stringz(request, target_name->domain);
if (ret)
goto out;
ret = krb5_kcm_call(context, request, &response, &response_data);
krb5_storage_free(request);
if (ret)
goto out;
sret = krb5_storage_read(response, uuid, sizeof(uuid));
krb5_storage_free(response);
krb5_data_free(&response_data);
if (sret != sizeof(uuid)) {
krb5_clear_error_message(context);
return KRB5_CC_IO;
}
major = _gss_ntlm_duplicate_name(minor, (gss_name_t)target_name,
(gss_name_t *)&cred);
if (major)
return major;
cred->flags |= NTLM_UUID;
memcpy(cred->uuid, uuid, sizeof(cred->uuid));
*rcred = (ntlm_cred)cred;
out:
krb5_free_context(context);
if (ret) {
*minor = ret;
major = GSS_S_FAILURE;
}
return major;
}
OM_uint32
_gss_ntlm_acquire_cred(OM_uint32 * min_stat,
const gss_name_t desired_name,
OM_uint32 time_req,
const gss_OID_set desired_mechs,
gss_cred_usage_t cred_usage,
gss_cred_id_t * output_cred_handle,
gss_OID_set * actual_mechs,
OM_uint32 * time_rec)
{
ntlm_name name = (ntlm_name) desired_name;
OM_uint32 maj_stat, junk;
ntlm_ctx ctx;
*min_stat = 0;
*output_cred_handle = GSS_C_NO_CREDENTIAL;
if (actual_mechs)
*actual_mechs = GSS_C_NO_OID_SET;
if (time_rec)
*time_rec = GSS_C_INDEFINITE;
if (desired_name == NULL)
return GSS_S_NO_CRED;
if (cred_usage == GSS_C_BOTH || cred_usage == GSS_C_ACCEPT) {
gss_ctx_id_t gctx;
maj_stat = _gss_ntlm_allocate_ctx(min_stat, name->domain, &ctx);
if (maj_stat != GSS_S_COMPLETE)
return maj_stat;
gctx = (gss_ctx_id_t)ctx;
_gss_ntlm_delete_sec_context(&junk, &gctx, NULL);
}
if (cred_usage == GSS_C_BOTH || cred_usage == GSS_C_INITIATE) {
ntlm_cred cred;
if ((name->flags & NTLM_ANON_NAME) != 0) {
maj_stat = _gss_ntlm_duplicate_name(min_stat,
(gss_name_t)name,
(gss_name_t *)&cred);
if (maj_stat)
return maj_stat;
} else {
maj_stat = _gss_ntlm_have_cred(min_stat, name, &cred);
if (maj_stat)
return maj_stat;
}
*output_cred_handle = (gss_cred_id_t)cred;
}
return (GSS_S_COMPLETE);
}
OM_uint32
_gss_ntlm_acquire_cred_ex(gss_status_id_t status,
const gss_name_t desired_name,
OM_uint32 flags,
OM_uint32 time_req,
gss_cred_usage_t cred_usage,
gss_auth_identity_t identity,
void *ctx,
void (*complete)(void *, OM_uint32, gss_status_id_t, gss_cred_id_t, OM_uint32))
{
ntlm_name name = (ntlm_name) desired_name;
OM_uint32 major;
krb5_storage *request, *response;
krb5_data response_data;
krb5_context context;
krb5_error_code ret;
struct ntlm_buf buf;
krb5_data data;
ntlm_cred dn;
kcmuuid_t uuid;
ssize_t sret;
if (identity == NULL)
return GSS_S_FAILURE;
if (identity == NULL)
return GSS_S_FAILURE;
if (name == NULL && identity->username == NULL)
return GSS_S_FAILURE;
ret = krb5_init_context(&context);
if (ret)
return GSS_S_FAILURE;
heim_ntlm_nt_key(identity->password, &buf);
data.data = buf.data;
data.length = buf.length;
krb5_kcm_storage_request(context, KCM_OP_ADD_NTLM_CRED, &request);
if (name) {
krb5_store_stringz(request, name->user);
krb5_store_stringz(request, name->domain);
} else {
krb5_store_stringz(request, identity->username);
krb5_store_stringz(request, identity->realm ? identity->realm : "");
}
krb5_store_data(request, data);
ret = krb5_kcm_call(context, request, &response, &response_data);
krb5_storage_free(request);
if (ret)
goto out;
sret = krb5_storage_read(response, &uuid, sizeof(uuid));
krb5_storage_free(response);
krb5_data_free(&response_data);
if (sret != sizeof(uuid)) {
ret = KRB5_CC_IO;
goto out;
}
heim_ntlm_free_buf(&buf);
dn = calloc(1, sizeof(*dn));
if (dn == NULL) {
major = GSS_S_FAILURE;
goto out;
}
if (name) {
dn->user = strdup(name->user);
dn->domain = strdup(name->domain);
} else {
dn->user = strdup(identity->username);
dn->domain = strdup(identity->realm ? identity->realm : "");
}
dn->flags = NTLM_UUID;
memcpy(dn->uuid, uuid, sizeof(dn->uuid));
complete(ctx, GSS_S_COMPLETE, status, (gss_cred_id_t)dn, GSS_C_INDEFINITE);
major = GSS_S_COMPLETE;
out:
krb5_free_context(context);
if (ret)
major = GSS_S_FAILURE;
return major;
}