Пример #1
0
static void
test_ap(krb5_context context,
        krb5_principal sprincipal,
        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,
                            sprincipal,
                            NULL,
                            ccache,
                            &data);
    if (ret)
        krb5_err(context, 1, ret, "krb5_mk_req_exact");

    ret = krb5_rd_req(context,
                      &server_ac,
                      &data,
                      sprincipal,
                      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_getremoteseqnumber(context, server_ac, &server_seq);
    krb5_auth_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);
}
Пример #2
0
static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context,
					   const krb5_principal client_principal,
					   const krb5_principal delegated_proxy_principal,
					   struct hdb_entry_ex *client,
					   struct hdb_entry_ex *server,
					   struct hdb_entry_ex *krbtgt,
					   krb5_pac *pac)
{
	struct samba_kdc_entry *p = talloc_get_type(server->ctx, struct samba_kdc_entry);
	TALLOC_CTX *mem_ctx = talloc_named(p, 0, "samba_kdc_reget_pac context");
	DATA_BLOB *pac_blob;
	DATA_BLOB *deleg_blob = NULL;
	krb5_error_code ret;
	NTSTATUS nt_status;
	struct PAC_SIGNATURE_DATA *pac_srv_sig;
	struct PAC_SIGNATURE_DATA *pac_kdc_sig;
	bool is_in_db, is_untrusted;

	if (!mem_ctx) {
		return ENOMEM;
	}

	/* The user account may be set not to want the PAC */
	if (!samba_princ_needs_pac(server)) {
		talloc_free(mem_ctx);
		return EINVAL;
	}

	/* If the krbtgt was generated by an RODC, and we are not that
	 * RODC, then we need to regenerate the PAC - we can't trust
	 * it */
	ret = samba_krbtgt_is_in_db(krbtgt, &is_in_db, &is_untrusted);
	if (ret != 0) {
		talloc_free(mem_ctx);
		return ret;
	}

	if (is_untrusted) {
		if (client == NULL) {
			return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
		}
		nt_status = samba_kdc_get_pac_blob(mem_ctx, client, &pac_blob);
		if (!NT_STATUS_IS_OK(nt_status)) {
			talloc_free(mem_ctx);
			return EINVAL;
		}
	} else {
		pac_blob = talloc_zero(mem_ctx, DATA_BLOB);
		if (!pac_blob) {
			talloc_free(mem_ctx);
			return ENOMEM;
		}

		pac_srv_sig = talloc_zero(mem_ctx, struct PAC_SIGNATURE_DATA);
		if (!pac_srv_sig) {
			talloc_free(mem_ctx);
			return ENOMEM;
		}

		pac_kdc_sig = talloc_zero(mem_ctx, struct PAC_SIGNATURE_DATA);
		if (!pac_kdc_sig) {
			talloc_free(mem_ctx);
			return ENOMEM;
		}

		nt_status = samba_kdc_update_pac_blob(mem_ctx, context,
						      *pac, pac_blob,
						      pac_srv_sig, pac_kdc_sig);
		if (!NT_STATUS_IS_OK(nt_status)) {
			DEBUG(0, ("Building PAC failed: %s\n",
				  nt_errstr(nt_status)));
			talloc_free(mem_ctx);
			return EINVAL;
		}
		
		if (is_in_db) {
			/* Now check the KDC signature, fetching the correct key based on the enc type */
			ret = kdc_check_pac(context, pac_srv_sig->signature, pac_kdc_sig, krbtgt);
			if (ret != 0) {
				DEBUG(1, ("PAC KDC signature failed to verify\n"));
				talloc_free(mem_ctx);
				return ret;
			}
		}
	}

	if (delegated_proxy_principal) {
		deleg_blob = talloc_zero(mem_ctx, DATA_BLOB);
		if (!deleg_blob) {
			talloc_free(mem_ctx);
			return ENOMEM;
		}

		nt_status = samba_kdc_update_delegation_info_blob(mem_ctx,
					context, *pac,
					server->entry.principal,
					delegated_proxy_principal,
					deleg_blob);
		if (!NT_STATUS_IS_OK(nt_status)) {
			DEBUG(0, ("Building PAC failed: %s\n",
				  nt_errstr(nt_status)));
			talloc_free(mem_ctx);
			return EINVAL;
		}
	}

	/* We now completely regenerate this pac */
	krb5_pac_free(context, *pac);

	ret = samba_make_krb5_pac(context, pac_blob, deleg_blob, pac);

	talloc_free(mem_ctx);
	return ret;
}
Пример #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)
	return krb5_enomem(context);

    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 the 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);
		break;
	    }

	    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);
		break;
	    }

	    ret = krb5_copy_principal(context, entry.principal, &p);
	    if (ret) {
		krb5_kt_free_entry (context, &entry);
		break;
	    }
	    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 (ret)
            goto out;
    }

    /* 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)
		goto out;
	} 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;
}