Пример #1
0
static OM_uint32 inquire_sec_context_authz_data
           (OM_uint32 *minor_status,
            const gsskrb5_ctx context_handle,
	    krb5_context context,
            unsigned ad_type,
            gss_buffer_set_t *data_set)
{
    krb5_data data;
    gss_buffer_desc ad_data;
    OM_uint32 ret;

    *minor_status = 0;
    *data_set = GSS_C_NO_BUFFER_SET;

    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
    if (context_handle->ticket == NULL) {
	HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
	*minor_status = EINVAL;
	_gsskrb5_set_status(EINVAL, "No ticket to obtain authz data from");
	return GSS_S_NO_CONTEXT;
    }

    ret = krb5_ticket_get_authorization_data_type(context,
						  context_handle->ticket,
						  ad_type,
						  &data);
    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
    if (ret) {
	*minor_status = ret;
	return GSS_S_FAILURE;
    }

    ad_data.value = data.data;
    ad_data.length = data.length;

    ret = gss_add_buffer_set_member(minor_status,
				    &ad_data,
				    data_set);

    krb5_data_free(&data);

    return ret;
}
Пример #2
0
static void
test_ap(krb5_context context,
	krb5_principal target,
	krb5_principal server,
	krb5_keytab keytab,
	krb5_ccache ccache,
	const krb5_flags client_flags)
{
    krb5_error_code ret;
    krb5_auth_context client_ac = NULL, server_ac = NULL;
    krb5_data data;
    krb5_flags server_flags;
    krb5_ticket *ticket = NULL;
    int32_t server_seq, client_seq;

    ret = krb5_mk_req_exact(context,
			    &client_ac,
			    client_flags,
			    target,
			    NULL,
			    ccache,
			    &data);
    if (ret)
	krb5_err(context, 1, ret, "krb5_mk_req_exact");

    ret = krb5_rd_req(context,
		      &server_ac,
		      &data,
		      server,
		      keytab,
		      &server_flags,
		      &ticket);
    if (ret)
	krb5_err(context, 1, ret, "krb5_rd_req");


    if (server_flags & AP_OPTS_MUTUAL_REQUIRED) {
	krb5_ap_rep_enc_part *repl;

	krb5_data_free(&data);

	if ((client_flags & AP_OPTS_MUTUAL_REQUIRED) == 0)
	    krb5_errx(context, 1, "client flag missing mutual req");

	ret = krb5_mk_rep (context, server_ac, &data);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_mk_rep");

	ret = krb5_rd_rep (context,
			   client_ac,
			   &data,
			   &repl);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_rd_rep");

	krb5_free_ap_rep_enc_part (context, repl);
    } else {
	if (client_flags & AP_OPTS_MUTUAL_REQUIRED)
	    krb5_errx(context, 1, "server flag missing mutual req");
    }

    krb5_auth_con_getremoteseqnumber(context, server_ac, &server_seq);
    krb5_auth_con_getremoteseqnumber(context, client_ac, &client_seq);
    if (server_seq != client_seq)
	krb5_errx(context, 1, "seq num differ");

    krb5_auth_con_getlocalseqnumber(context, server_ac, &server_seq);
    krb5_auth_con_getlocalseqnumber(context, client_ac, &client_seq);
    if (server_seq != client_seq)
	krb5_errx(context, 1, "seq num differ");

    krb5_data_free(&data);
    krb5_auth_con_free(context, client_ac);
    krb5_auth_con_free(context, server_ac);

    if (verify_pac) {
	krb5_pac pac;

	ret = krb5_ticket_get_authorization_data_type(context,
						      ticket,
						      KRB5_AUTHDATA_WIN2K_PAC,
						      &data);
	if (ret)
	    krb5_err(context, 1, ret, "get pac");

	ret = krb5_pac_parse(context, data.data, data.length, &pac);
	if (ret)
	    krb5_err(context, 1, ret, "pac parse");

	krb5_pac_free(context, pac);
    }

    krb5_free_ticket(context, ticket);
}
Пример #3
0
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_rd_req_ctx(krb5_context context,
		krb5_auth_context *auth_context,
		const krb5_data *inbuf,
		krb5_const_principal server,
		krb5_rd_req_in_ctx inctx,
		krb5_rd_req_out_ctx *outctx)
{
    krb5_error_code ret;
    krb5_ap_req ap_req;
    krb5_rd_req_out_ctx o = NULL;
    krb5_keytab id = NULL, keytab = NULL;
    krb5_principal service = NULL;

    *outctx = NULL;

    o = calloc(1, sizeof(*o));
    if (o == NULL) {
	krb5_set_error_message(context, ENOMEM,
			       N_("malloc: out of memory", ""));
	return ENOMEM;
    }

    if (*auth_context == NULL) {
	ret = krb5_auth_con_init(context, auth_context);
	if (ret)
	    goto out;
    }

    ret = krb5_decode_ap_req(context, inbuf, &ap_req);
    if(ret)
	goto out;

    /* Save that principal that was in the request */
    ret = _krb5_principalname2krb5_principal(context,
					     &o->server,
					     ap_req.ticket.sname,
					     ap_req.ticket.realm);
    if (ret)
	goto out;

    if (ap_req.ap_options.use_session_key &&
	(*auth_context)->keyblock == NULL) {
	ret = KRB5KRB_AP_ERR_NOKEY;
	krb5_set_error_message(context, ret,
			       N_("krb5_rd_req: user to user auth "
				  "without session key given", ""));
	goto out;
    }

    if (inctx && inctx->keytab)
	id = inctx->keytab;

    if((*auth_context)->keyblock){
	ret = krb5_copy_keyblock(context,
				 (*auth_context)->keyblock,
				 &o->keyblock);
	if (ret)
	    goto out;
    } else if(inctx && inctx->keyblock){
	ret = krb5_copy_keyblock(context,
				 inctx->keyblock,
				 &o->keyblock);
	if (ret)
	    goto out;
    } else {

	if(id == NULL) {
	    krb5_kt_default(context, &keytab);
	    id = keytab;
	}
	if (id == NULL)
	    goto out;

	if (server == NULL) {
	    ret = _krb5_principalname2krb5_principal(context,
						     &service,
						     ap_req.ticket.sname,
						     ap_req.ticket.realm);
	    if (ret)
		goto out;
	    server = service;
	}

	ret = get_key_from_keytab(context,
				  &ap_req,
				  server,
				  id,
				  &o->keyblock);
	if (ret) {
	    /* If caller specified a server, fail. */
	    if (service == NULL && (context->flags & KRB5_CTX_F_RD_REQ_IGNORE) == 0)
		goto out;
	    /* Otherwise, fall back to iterating over the keytab. This
	     * have serious performace issues for larger keytab.
	     */
	    o->keyblock = NULL;
	}
    }

    if (o->keyblock) {
	/*
	 * We got an exact keymatch, use that.
	 */

	ret = krb5_verify_ap_req2(context,
				  auth_context,
				  &ap_req,
				  server,
				  o->keyblock,
				  0,
				  &o->ap_req_options,
				  &o->ticket,
				  KRB5_KU_AP_REQ_AUTH);

	if (ret)
	    goto out;

    } else {
	/*
	 * Interate over keytab to find a key that can decrypt the request.
	 */

	krb5_keytab_entry entry;
	krb5_kt_cursor cursor;
	int done = 0, kvno = 0;

	memset(&cursor, 0, sizeof(cursor));

	if (ap_req.ticket.enc_part.kvno)
	    kvno = *ap_req.ticket.enc_part.kvno;

	ret = krb5_kt_start_seq_get(context, id, &cursor);
	if (ret)
	    goto out;

	done = 0;
	while (!done) {
	    krb5_principal p;

	    ret = krb5_kt_next_entry(context, id, &entry, &cursor);
	    if (ret) {
		_krb5_kt_principal_not_found(context, ret, id, o->server,
					     ap_req.ticket.enc_part.etype,
					     kvno);
		krb5_kt_end_seq_get(context, id, &cursor);
		goto out;
	    }

	    if (entry.keyblock.keytype != ap_req.ticket.enc_part.etype) {
		krb5_kt_free_entry (context, &entry);
		continue;
	    }

	    ret = krb5_verify_ap_req2(context,
				      auth_context,
				      &ap_req,
				      server,
				      &entry.keyblock,
				      0,
				      &o->ap_req_options,
				      &o->ticket,
				      KRB5_KU_AP_REQ_AUTH);
	    if (ret) {
		krb5_kt_free_entry(context, &entry);
		continue;
	    }

	    /*
	     * Found a match, save the keyblock for PAC processing,
	     * and update the service principal in the ticket to match
	     * whatever is in the keytab.
	     */

	    ret = krb5_copy_keyblock(context,
				     &entry.keyblock,
				     &o->keyblock);
	    if (ret) {
		krb5_kt_free_entry(context, &entry);
		krb5_kt_end_seq_get(context, id, &cursor);
		goto out;
	    }

	    ret = krb5_copy_principal(context, entry.principal, &p);
	    if (ret) {
		krb5_kt_free_entry(context, &entry);
		krb5_kt_end_seq_get(context, id, &cursor);
		goto out;
	    }
	    krb5_free_principal(context, o->ticket->server);
	    o->ticket->server = p;
	    
	    krb5_kt_free_entry(context, &entry);

	    done = 1;
	}
	krb5_kt_end_seq_get(context, id, &cursor);
    }

    /* If there is a PAC, verify its server signature */
    if (inctx == NULL || inctx->check_pac) {
	krb5_pac pac;
	krb5_data data;

	ret = krb5_ticket_get_authorization_data_type(context,
						      o->ticket,
						      KRB5_AUTHDATA_WIN2K_PAC,
						      &data);
	if (ret == 0) {
	    ret = krb5_pac_parse(context, data.data, data.length, &pac);
	    krb5_data_free(&data);
	    if (ret)
		goto out;

	    ret = krb5_pac_verify(context,
				  pac,
				  o->ticket->ticket.authtime,
				  o->ticket->client,
				  o->keyblock,
				  NULL);
	    krb5_pac_free(context, pac);
	    if (ret == 0)
		o->flags |= KRB5_RD_REQ_OUT_PAC_VALID;
	    ret = 0;
	} else
	    ret = 0;
    }
 out:

    if (ret || outctx == NULL) {
	krb5_rd_req_out_ctx_free(context, o);
    } else
	*outctx = o;

    free_AP_REQ(&ap_req);

    if (service)
	krb5_free_principal(context, service);

    if (keytab)
	krb5_kt_close(context, keytab);

    return ret;
}
Пример #4
0
krb5_error_code KRB5_LIB_FUNCTION
krb5_rd_req_ctx(krb5_context context,
		krb5_auth_context *auth_context,
		const krb5_data *inbuf,
		krb5_const_principal server,
		krb5_rd_req_in_ctx inctx,
		krb5_rd_req_out_ctx *outctx)
{
    krb5_error_code ret;
    krb5_ap_req ap_req;
    krb5_principal service = NULL;
    krb5_rd_req_out_ctx o = NULL;

    ret = _krb5_rd_req_out_ctx_alloc(context, &o);
    if (ret)
	goto out;

    if (*auth_context == NULL) {
	ret = krb5_auth_con_init(context, auth_context);
	if (ret)
	    goto out;
    }

    ret = krb5_decode_ap_req(context, inbuf, &ap_req);
    if(ret)
	goto out;

    if(server == NULL){
	ret = _krb5_principalname2krb5_principal(context,
						 &service,
						 ap_req.ticket.sname,
						 ap_req.ticket.realm);
	if (ret)
	    goto out;
	server = service;
    }
    if (ap_req.ap_options.use_session_key &&
	(*auth_context)->keyblock == NULL) {
	krb5_set_error_string(context, "krb5_rd_req: user to user auth "
			      "without session key given");
	ret = KRB5KRB_AP_ERR_NOKEY;
	goto out;
    }

    if((*auth_context)->keyblock){
	ret = krb5_copy_keyblock(context,
				 (*auth_context)->keyblock,
				 &o->keyblock);
	if (ret)
	    goto out;
    } else if(inctx->keyblock){
	ret = krb5_copy_keyblock(context,
				 inctx->keyblock,
				 &o->keyblock);
	if (ret)
	    goto out;
    } else {
	krb5_keytab keytab = NULL;

	if (inctx && inctx->keytab)
	    keytab = inctx->keytab;

	ret = get_key_from_keytab(context, 
				  auth_context, 
				  &ap_req,
				  server,
				  keytab,
				  &o->keyblock);
	if(ret)
	    goto out;
    }

    ret = krb5_verify_ap_req2(context,
			      auth_context,
			      &ap_req,
			      server,
			      o->keyblock,
			      0,
			      &o->ap_req_options,
			      &o->ticket,
			      KRB5_KU_AP_REQ_AUTH);

    if (ret)
	goto out;

    /* If there is a PAC, verify its server signature */
    if (inctx->check_pac) {
	krb5_pac pac;
	krb5_data data;

	ret = krb5_ticket_get_authorization_data_type(context,
						      o->ticket,
						      KRB5_AUTHDATA_WIN2K_PAC,
						      &data);
	if (ret == 0) {
	    ret = krb5_pac_parse(context, data.data, data.length, &pac);
	    krb5_data_free(&data);
	    if (ret)
		goto out;
	
	    ret = krb5_pac_verify(context,
				  pac, 
				  o->ticket->ticket.authtime,
				  o->ticket->client, 
				  o->keyblock, 
				  NULL);
	    krb5_pac_free(context, pac);
	    if (ret)
		goto out;
	}
	ret = 0;
    }
out:
    if (ret || outctx == NULL) {
	krb5_rd_req_out_ctx_free(context, o);
    } else 
	*outctx = o;

    free_AP_REQ(&ap_req);
    if(service)
	krb5_free_principal(context, service);
    return ret;
}
Пример #5
0
static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security,
					 TALLOC_CTX *mem_ctx_out,
					 struct auth_session_info **_session_info) 
{
	NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
	struct gensec_krb5_state *gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data;
	krb5_context context = gensec_krb5_state->smb_krb5_context->krb5_context;
	struct auth_user_info_dc *user_info_dc = NULL;
	struct auth_session_info *session_info = NULL;
	struct PAC_LOGON_INFO *logon_info;

	krb5_principal client_principal;
	char *principal_string;
	
	DATA_BLOB pac;
	krb5_data pac_data;

	krb5_error_code ret;

	TALLOC_CTX *mem_ctx = talloc_new(mem_ctx_out);
	if (!mem_ctx) {
		return NT_STATUS_NO_MEMORY;
	}
	
	ret = krb5_ticket_get_client(context, gensec_krb5_state->ticket, &client_principal);
	if (ret) {
		DEBUG(5, ("krb5_ticket_get_client failed to get cleint principal: %s\n", 
			  smb_get_krb5_error_message(context, 
						     ret, mem_ctx)));
		talloc_free(mem_ctx);
		return NT_STATUS_NO_MEMORY;
	}
	
	ret = krb5_unparse_name(gensec_krb5_state->smb_krb5_context->krb5_context, 
				client_principal, &principal_string);
	if (ret) {
		DEBUG(1, ("Unable to parse client principal: %s\n",
			  smb_get_krb5_error_message(context, 
						     ret, mem_ctx)));
		krb5_free_principal(context, client_principal);
		talloc_free(mem_ctx);
		return NT_STATUS_NO_MEMORY;
	}

	ret = krb5_ticket_get_authorization_data_type(context, gensec_krb5_state->ticket, 
						      KRB5_AUTHDATA_WIN2K_PAC, 
						      &pac_data);
	
	if (ret && gensec_setting_bool(gensec_security->settings, "gensec", "require_pac", false)) {
		DEBUG(1, ("Unable to find PAC in ticket from %s, failing to allow access: %s \n",
			  principal_string,
			  smb_get_krb5_error_message(context, 
						     ret, mem_ctx)));
		free(principal_string);
		krb5_free_principal(context, client_principal);
		talloc_free(mem_ctx);
		return NT_STATUS_ACCESS_DENIED;
	} else if (ret) {
		/* NO pac */
		DEBUG(5, ("krb5_ticket_get_authorization_data_type failed to find PAC: %s\n", 
			  smb_get_krb5_error_message(context, 
						     ret, mem_ctx)));
		if (gensec_security->auth_context && 
		    !gensec_setting_bool(gensec_security->settings, "gensec", "require_pac", false)) {
			DEBUG(1, ("Unable to find PAC for %s, resorting to local user lookup: %s",
				  principal_string, smb_get_krb5_error_message(context, 
						     ret, mem_ctx)));
			nt_status = gensec_security->auth_context->get_user_info_dc_principal(mem_ctx,
											     gensec_security->auth_context, 
											     principal_string,
											     NULL, &user_info_dc);
			if (!NT_STATUS_IS_OK(nt_status)) {
				free(principal_string);
				krb5_free_principal(context, client_principal);
				talloc_free(mem_ctx);
				return nt_status;
			}
		} else {
			DEBUG(1, ("Unable to find PAC in ticket from %s, failing to allow access\n",
				  principal_string));
			free(principal_string);
			krb5_free_principal(context, client_principal);
			talloc_free(mem_ctx);
			return NT_STATUS_ACCESS_DENIED;
		}
	} else {
		/* Found pac */
		union netr_Validation validation;

		pac = data_blob_talloc(mem_ctx, pac_data.data, pac_data.length);
		if (!pac.data) {
			free(principal_string);
			krb5_free_principal(context, client_principal);
			talloc_free(mem_ctx);
			return NT_STATUS_NO_MEMORY;
		}

		/* decode and verify the pac */
		nt_status = kerberos_pac_logon_info(gensec_krb5_state, 
						    pac,
						    gensec_krb5_state->smb_krb5_context->krb5_context,
						    NULL, gensec_krb5_state->keyblock,
						    client_principal,
						    gensec_krb5_state->ticket->ticket.authtime, &logon_info);

		if (!NT_STATUS_IS_OK(nt_status)) {
			free(principal_string);
			krb5_free_principal(context, client_principal);
			talloc_free(mem_ctx);
			return nt_status;
		}

		validation.sam3 = &logon_info->info3;
		nt_status = make_user_info_dc_netlogon_validation(mem_ctx,
								 NULL,
								 3, &validation,
								  true, /* This user was authenticated */
								 &user_info_dc);
		if (!NT_STATUS_IS_OK(nt_status)) {
			free(principal_string);
			krb5_free_principal(context, client_principal);
			talloc_free(mem_ctx);
			return nt_status;
		}
	}

	free(principal_string);
	krb5_free_principal(context, client_principal);

	/* references the user_info_dc into the session_info */
	nt_status = gensec_generate_session_info(mem_ctx, gensec_security, user_info_dc, &session_info);

	if (!NT_STATUS_IS_OK(nt_status)) {
		talloc_free(mem_ctx);
		return nt_status;
	}

	nt_status = gensec_krb5_session_key(gensec_security, session_info, &session_info->session_key);

	if (!NT_STATUS_IS_OK(nt_status)) {
		talloc_free(mem_ctx);
		return nt_status;
	}

	*_session_info = talloc_steal(mem_ctx_out, session_info);

	talloc_free(mem_ctx);
	return NT_STATUS_OK;
}
Пример #6
0
static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security,
        TALLOC_CTX *mem_ctx,
        struct auth_session_info **_session_info)
{
    NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
    struct gensec_krb5_state *gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data;
    krb5_context context = gensec_krb5_state->smb_krb5_context->krb5_context;
    struct auth_session_info *session_info = NULL;

    krb5_principal client_principal;
    char *principal_string;

    DATA_BLOB pac_blob, *pac_blob_ptr = NULL;
    krb5_data pac_data;

    krb5_error_code ret;

    TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    if (!tmp_ctx) {
        return NT_STATUS_NO_MEMORY;
    }

    ret = krb5_ticket_get_client(context, gensec_krb5_state->ticket, &client_principal);
    if (ret) {
        DEBUG(5, ("krb5_ticket_get_client failed to get cleint principal: %s\n",
                  smb_get_krb5_error_message(context,
                                             ret, tmp_ctx)));
        talloc_free(tmp_ctx);
        return NT_STATUS_NO_MEMORY;
    }

    ret = krb5_unparse_name(gensec_krb5_state->smb_krb5_context->krb5_context,
                            client_principal, &principal_string);
    if (ret) {
        DEBUG(1, ("Unable to parse client principal: %s\n",
                  smb_get_krb5_error_message(context,
                                             ret, tmp_ctx)));
        krb5_free_principal(context, client_principal);
        talloc_free(tmp_ctx);
        return NT_STATUS_NO_MEMORY;
    }

    ret = krb5_ticket_get_authorization_data_type(context, gensec_krb5_state->ticket,
            KRB5_AUTHDATA_WIN2K_PAC,
            &pac_data);

    if (ret) {
        /* NO pac */
        DEBUG(5, ("krb5_ticket_get_authorization_data_type failed to find PAC: %s\n",
                  smb_get_krb5_error_message(context,
                                             ret, tmp_ctx)));
    } else {
        /* Found pac */
        pac_blob = data_blob_talloc(tmp_ctx, pac_data.data, pac_data.length);
        if (!pac_blob.data) {
            free(principal_string);
            krb5_free_principal(context, client_principal);
            talloc_free(tmp_ctx);
            return NT_STATUS_NO_MEMORY;
        }

        /* decode and verify the pac */
        nt_status = kerberos_decode_pac(gensec_krb5_state,
                                        pac_blob,
                                        gensec_krb5_state->smb_krb5_context->krb5_context,
                                        NULL, gensec_krb5_state->keyblock,
                                        client_principal,
                                        gensec_krb5_state->ticket->ticket.authtime, NULL);

        if (!NT_STATUS_IS_OK(nt_status)) {
            free(principal_string);
            krb5_free_principal(context, client_principal);
            talloc_free(tmp_ctx);
            return nt_status;
        }

        pac_blob_ptr = &pac_blob;
    }

    nt_status = gensec_generate_session_info_pac(tmp_ctx,
                gensec_security,
                gensec_krb5_state->smb_krb5_context,
                pac_blob_ptr, principal_string,
                gensec_get_remote_address(gensec_security),
                &session_info);

    free(principal_string);
    krb5_free_principal(context, client_principal);

    if (!NT_STATUS_IS_OK(nt_status)) {
        talloc_free(tmp_ctx);
        return nt_status;
    }

    nt_status = gensec_krb5_session_key(gensec_security, session_info, &session_info->session_key);

    if (!NT_STATUS_IS_OK(nt_status)) {
        talloc_free(tmp_ctx);
        return nt_status;
    }

    *_session_info = talloc_steal(mem_ctx, session_info);

    talloc_free(tmp_ctx);
    return NT_STATUS_OK;
}