jborean93 / pykrb5

Python krb5 API interface
MIT License
17 stars 8 forks source link

set_password extended server response processing #53

Closed zarganum closed 2 months ago

zarganum commented 2 months ago

The result_string returned from kpasswd service by krb5_set_password() family is a non-documented binary sequence that may or may not be a human readable string. However it is mandatory to clearly inform of the end user what requirements does the system provide to conduct a successful password change operation. For example, system may remember last 24 used passwords and thus decline operation. Or the minimum password age may be 1 day. Etc, etc.

The only way to obtain such information by client is to analyze the mentioned result_string. Based on MIT library source code it appears that at least two cases deserve special attention:

  1. UTF8-compatible string returned by MIT and other non-MS implementations, human readable.
  2. 30-byte binary structure starting with 0x0000 (to avoid confusing with UTF8), returned by Active Directory that contains machine-encoded rules for password validity, referred as ADPolicyInfo.
  3. All other responses are returned as raw bytes.

MIT library contains a dedicated function krb5_chpw_message() to decode the ADPolicyInfo, in a locale-sensitive fashion. With Heimdal, it is required to analyze the ADPolicyInfo and generate the response in the client code.

This PR addresses above mentioned cases providing "best efforts" decoding of the result_string and chpw_message() interface to MIT library decoder. Additional enums where introduced as nested classes for status codes and ADPolicyInfo binary flags. Also, theresult_code_string pure library response is decoded as string when possible.

The implementation and unit test protocols are based on MIT decode_ad_policy_info() internal function and according tests from test_chpw_message.c.

zarganum commented 2 months ago

PS @jborean93 Jordan sorry I failed to comply with D.R.Y in set_password() and set_password_using_ccache() because I did not find a way how to pass *krb5_data C-type pointers between Python functions returning a variable tuple. Compiler complained or even crashed but rejected my attempts anyway. So I copy-pasted.

zarganum commented 2 months ago

@jborean93 Jordan, anything else I can improve?

jborean93 commented 2 months ago

Thanks for working on this. Just an FYI I'm planning on pushing out a new release soon so there will be a package with 3.13 wheels on macOS before the final version is out.