Esempio n. 1
0
static krb5_error_code
kcm_op_do_ntlm(krb5_context context,
	       kcm_client *client,
	       kcm_operation opcode,
	       krb5_storage *request,
	       krb5_storage *response)
{
    struct kcm_ntlm_cred *c;
    struct ntlm_type2 type2;
    struct ntlm_type3 type3;
    char *user = NULL, *domain = NULL;
    struct ntlm_buf ndata, sessionkey;
    krb5_data data;
    krb5_error_code ret;
    uint32_t flags = 0;

    memset(&type2, 0, sizeof(type2));
    memset(&type3, 0, sizeof(type3));
    sessionkey.data = NULL;
    sessionkey.length = 0;
    
    ret = krb5_ret_stringz(request, &user);
    if (ret)
	goto error;

    ret = krb5_ret_stringz(request, &domain);
    if (ret)
	goto error;

    if (domain[0] == '\0') {
	free(domain);
	domain = NULL;
    }

    c = find_ntlm_cred(user, domain, client);
    if (c == NULL) {
	ret = EINVAL;
	goto error;
    }

    ret = krb5_ret_data(request, &data);
    if (ret)
	goto error;

    ndata.data = data.data;
    ndata.length = data.length;

    ret = heim_ntlm_decode_type2(&ndata, &type2);
    krb5_data_free(&data);
    if (ret)
	goto error;

    if (domain && strcmp(domain, type2.targetname) == 0) {
	ret = EINVAL;
	goto error;
    }

    type3.username = c->user;
    type3.flags = type2.flags;
    type3.targetname = type2.targetname;
    type3.ws = rk_UNCONST("workstation");
    
    /*
     * NTLM Version 1 if no targetinfo buffer.
     */
    
    if (1 || type2.targetinfo.length == 0) {
	struct ntlm_buf sessionkey;
	
	if (type2.flags & NTLM_NEG_NTLM2_SESSION) {
	    unsigned char nonce[8];
	    
	    if (RAND_bytes(nonce, sizeof(nonce)) != 1) {
		ret = EINVAL;
		goto error;
	    }
	    
	    ret = heim_ntlm_calculate_ntlm2_sess(nonce,
						 type2.challenge,
						 c->nthash.data,
						 &type3.lm,
						 &type3.ntlm);
	} else {
	    ret = heim_ntlm_calculate_ntlm1(c->nthash.data,
					    c->nthash.length,
					    type2.challenge,
					    &type3.ntlm);
	    
	}
	if (ret)
	    goto error;
	
	ret = heim_ntlm_build_ntlm1_master(c->nthash.data,
					   c->nthash.length,
					   &sessionkey,
					   &type3.sessionkey);
	if (ret) {
	    if (type3.lm.data)
		free(type3.lm.data);
	    if (type3.ntlm.data)
		free(type3.ntlm.data);
	    goto error;
	}

	free(sessionkey.data);
	if (ret) {
	    if (type3.lm.data)
		free(type3.lm.data);
	    if (type3.ntlm.data)
		free(type3.ntlm.data);
	    goto error;
	}
	flags |= NTLM_FLAG_SESSIONKEY;
#if 0	
    } else {
	struct ntlm_buf sessionkey;
	unsigned char ntlmv2[16];
	struct ntlm_targetinfo ti;
	
	/* verify infotarget */
	
	ret = heim_ntlm_decode_targetinfo(&type2.targetinfo, 1, &ti);
	if(ret) {
	    _gss_ntlm_delete_sec_context(minor_status,
					 context_handle, NULL);
	    *minor_status = ret;
	    return GSS_S_FAILURE;
	}
	
	if (ti.domainname && strcmp(ti.domainname, name->domain) != 0) {
	    _gss_ntlm_delete_sec_context(minor_status,
					 context_handle, NULL);
	    *minor_status = EINVAL;
	    return GSS_S_FAILURE;
	}
	
	ret = heim_ntlm_calculate_ntlm2(ctx->client->key.data,
					ctx->client->key.length,
					type3.username,
					name->domain,
					type2.challenge,
					&type2.targetinfo,
					ntlmv2,
					&type3.ntlm);
	if (ret) {
	    _gss_ntlm_delete_sec_context(minor_status,
					 context_handle, NULL);
	    *minor_status = ret;
	    return GSS_S_FAILURE;
	}
	
	ret = heim_ntlm_build_ntlm1_master(ntlmv2, sizeof(ntlmv2),
					   &sessionkey,
					   &type3.sessionkey);
	memset(ntlmv2, 0, sizeof(ntlmv2));
	if (ret) {
	    _gss_ntlm_delete_sec_context(minor_status,
					 context_handle, NULL);
	    *minor_status = ret;
	    return GSS_S_FAILURE;
	}
	
	flags |= NTLM_FLAG_NTLM2_SESSION |
	         NTLM_FLAG_SESSION;
	
	if (type3.flags & NTLM_NEG_KEYEX)
	    flags |= NTLM_FLAG_KEYEX;

	ret = krb5_data_copy(&ctx->sessionkey,
			     sessionkey.data, sessionkey.length);
	free(sessionkey.data);
	if (ret) {
	    _gss_ntlm_delete_sec_context(minor_status,
					 context_handle, NULL);
	    *minor_status = ret;
	    return GSS_S_FAILURE;
	}
#endif
    }
    
#if 0
    if (flags & NTLM_FLAG_NTLM2_SESSION) {
	_gss_ntlm_set_key(&ctx->u.v2.send, 0, (ctx->flags & NTLM_NEG_KEYEX),
			  ctx->sessionkey.data,
			  ctx->sessionkey.length);
	_gss_ntlm_set_key(&ctx->u.v2.recv, 1, (ctx->flags & NTLM_NEG_KEYEX),
			  ctx->sessionkey.data,
			  ctx->sessionkey.length);
    } else {
	flags |= NTLM_FLAG_SESSION;
	RC4_set_key(&ctx->u.v1.crypto_recv.key,
		    ctx->sessionkey.length,
		    ctx->sessionkey.data);
	RC4_set_key(&ctx->u.v1.crypto_send.key,
		    ctx->sessionkey.length,
		    ctx->sessionkey.data);
    }
#endif

    ret = heim_ntlm_encode_type3(&type3, &ndata);
    if (ret)
	goto error;
	
    data.data = ndata.data;
    data.length = ndata.length;
    ret = krb5_store_data(response, data);
    heim_ntlm_free_buf(&ndata);
    if (ret) goto error;

    ret = krb5_store_int32(response, flags);
    if (ret) goto error;

    data.data = sessionkey.data;
    data.length = sessionkey.length;

    ret = krb5_store_data(response, data);
    if (ret) goto error;

 error:
    free(type3.username);
    heim_ntlm_free_type2(&type2);
    free(user);
    if (domain)
	free(domain);

    return ret;
}
OM_uint32
_gss_ntlm_acquire_cred_ext(OM_uint32 * minor_status,
			   const gss_name_t desired_name,
			   gss_const_OID credential_type,
			   const void *credential_data,
			   OM_uint32 time_req,
			   gss_const_OID desired_mech,
			   gss_cred_usage_t cred_usage,
			   gss_cred_id_t * output_cred_handle)
{
    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 (credential_data == NULL)
	return GSS_S_FAILURE;

    if (!gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD))
	return GSS_S_FAILURE;

    if (name == NULL)
	return GSS_S_FAILURE;
	
    ret = krb5_init_context(&context);
    if (ret)
	return GSS_S_FAILURE;

    {
	gss_buffer_t buffer;
	char *password;
	
	buffer = (gss_buffer_t)credential_data;
	password = malloc(buffer->length + 1);
	if (password == NULL) {
	    ret = ENOMEM;
	    goto out;
	}
	memcpy(password, buffer->value, buffer->length);
	password[buffer->length] = '\0';
	
	heim_ntlm_nt_key(password, &buf);
	memset(password, 0, strlen(password));
	free(password);
    }

    data.data = buf.data;
    data.length = buf.length;
	
    krb5_kcm_storage_request(context, KCM_OP_ADD_NTLM_CRED, &request);
	
    krb5_store_stringz(request, name->user);
    krb5_store_stringz(request, name->domain);
    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;
    }

    dn->user = strdup(name->user);
    dn->domain = strdup(name->domain);
    dn->flags = NTLM_UUID;
    memcpy(dn->uuid, uuid, sizeof(dn->uuid));

    *output_cred_handle = (gss_cred_id_t)dn;
    
    major = GSS_S_COMPLETE;
 out:

    krb5_free_context(context);
    if (ret)
	major = GSS_S_FAILURE;

    return major;
}