Projects/Policy refcount elimination
This project corresponds to [krbdev.mit.edu #7385], which proposes to elminate the use of the policy reference count field.
Policy objects in the Kerberos database contain a policy_refcnt field, which is intended to reflect the number of principals associated with that policy. libkadm5srv maintains the policy_refcnt field in its principal operations (so modifying a principal can also result in modifying its old or new policy reference), and refuses to delete a policy with a non-zero policy_refcnt value.
The policy reference count field creates a number of problems:
- If the database is modified by any agent other than kadmin (e.g. through LDAP operations for an LDAP KDB, or through an application using libkdb5 for any type of KDB), the policy field may not be maintained.
- The LDAP KDB schema does not contain a field for the policy reference count, presumably out of concern that it might become out of date. Instead, prior to [krbdev.mit.edu #6799], every policy fetch operation performed a search for all principals referencing the policy. This created a terrible performance problem--especially since fetching a principal currently requires fetching its associated policy object. After [krbdev.mit.edu #6799], LDAP populates the refcnt_policy field with 0 and checks for references from principals when deleting a policy, but this creates a layering inconsistency between the LDAP KDB and other KDB types.
- Historically, there have been bugs such as [krbdev.mit.edu #7384] allowing policy reference counts to become out of sync on slaves, and there are probably still bugs of that nature. If a slave is promoted to a master with inconsistent reference counts, the new master could incorrectly forbid or allow a policy deletion operation.
- Policy deletion is a rare operation. Fundamentally, it does not make sense to impose an extra burden on principal modifications for the sake of such a rare operation.
Alternatives for policy deletion
Here are four options for handling policy deletion without using the reference count:
1. Disallow policy deletion altogether. A typical KDB does not have many policy objects, so the total space occupied by policies is quite small, and there is no efficiency reason to delete them. However, administrators might find it annoying not to be able to delete a policy name which contains a typo.
2. At deletion time, iterate over all principals. If any principals reference the policy, disallow the deletion.
3. At deletion time, iterate over all principals. If any principals reference the policy, null out their policy references.
4. Delete the policy even though it might be referenced by principals. If a principals references a nonexistent policy, treat it as if the principal had no policy reference. If a policy with the same name is recreated, principals referencing that policy name will become associated with the new policy. Put another way, principals could be thought of as referencing policy names (which might or might not exist as policy objects), rather than directly referencing policy objects.
This project proposes to implement option #4.
The following units of code would be affected by this project:
- kadm5_policy_ent_rec, osa_policy_ent_rec: add comments indicating that policy_refcnt is no longer maintained or used.
- kadm5_create_principal_3, kadm5_modify_principal, kadm5_delete_principal: stop maintaining policy_refcnt fields of policies referenced by the old or new principal entries.
[TBD: should we also allow new principal entries to reference nonexistent policies?]
- kadm5_create_policy_internal, kadm5_modify_policy_internal: stop checking mask & KADM5_REF_COUNT and setting pent.policy_refcnt. These functions can be folded into their callers (kadm5_create_policy and kadm5_modify_policy).
- kadm5_delete_policy: stop checking policy_refcnt.
- kadm5_get_policy: set entry->policy_refcnt to 0 instead of propagating it from the KDB entry.
- [TBD: kdb5_util dump/load functions should dump 0 and ignore on load]
- kadmin_getpol: Don't output policy_refcnt in long-form output. In terse output, always output 0.
[TBD: check all call sites where we look up policies and make sure they don't error out if the policy doesn't exist. At least the LDAP back end errors out when populating a principal entry with a nonexistent policy.]