diff options
author | Barry Jaspan <bjaspan@mit.edu> | 1993-10-08 22:07:20 +0000 |
---|---|---|
committer | Barry Jaspan <bjaspan@mit.edu> | 1993-10-08 22:07:20 +0000 |
commit | dcaee6fde713ee9389b1fe82b8a75365a5b6a739 (patch) | |
tree | 94b6f343e48d4f30bb4f4aa33a12df24c4a01fed /doc | |
parent | ba5c693c1fb575e6e35fd159659e0c5873af1cf2 (diff) | |
download | krb5-dcaee6fde713ee9389b1fe82b8a75365a5b6a739.tar.gz krb5-dcaee6fde713ee9389b1fe82b8a75365a5b6a739.tar.xz krb5-dcaee6fde713ee9389b1fe82b8a75365a5b6a739.zip |
*** empty log message ***
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@2651 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'doc')
-rw-r--r-- | doc/kadm5/api-funcspec.tex | 360 | ||||
-rw-r--r-- | doc/kadm5/api-server-design.tex | 262 |
2 files changed, 305 insertions, 317 deletions
diff --git a/doc/kadm5/api-funcspec.tex b/doc/kadm5/api-funcspec.tex index 56602541b..f3605e5b7 100644 --- a/doc/kadm5/api-funcspec.tex +++ b/doc/kadm5/api-funcspec.tex @@ -10,7 +10,7 @@ \title{OV*Secure Admin \\ Functional Specifications} \author{} -\date{\today} +\date{DRAFT --- \today} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Make _ actually generate an _, and allow line-breaking after it. @@ -68,34 +68,26 @@ in the dictionary will not be accepted. component and the realm of the principal's name will not be accepted. \end{itemize} -\subsection{Principals, ovsec_kadm_principal_ent_t} +\subsection{Data Structures} + +This section describes the data structures used by the Admin API that +are unique to \secure{}. + +\subsubsection{Principals, ovsec_kadm_principal_ent_t} \label{sec:principal-structure} A Kerberos principal entry is represented by a ovsec_kadm_principal_ent_t. It contains a subset of the information stored in the master Kerberos database as well as the additional -information maintained by \secure{}. The new principal information -consists of a named password policy (\v{policy}) and optional -overrides for each field of the password policy (\v{pw_*}). - -The policy name and override fields may or may not be enabled -depending on the value of the aux_attributes bitmask (see section -\ref{sec:masks}). Specfically: - -\begin{itemize} -\item For each PW_* bit set in aux_attributes, the corresponding pw_* -field is enforced on the principal. - -\item If the POLICY bit is set in aux_attributes, then for each PW_* -bit that is {\it not} set in aux_attributes, the corresponding pw_* -field from the named policy is enforced on the principal. +information maintained by \secure{}. In the current version, the only +additional information is the principal's policy and the +aux_attributes flags. -\item If the POLICY bit is not set, then for each PW_* bit that is -{\it not} set in aux_attributes, no corresponding policy is enforced. -\end{itemize} - -For a retrieved principal, the value of the policy or pw_* fields when -the corresponding bits in aux_attributes are not set is undefined. +The principal may or may not have a policy enforced on it. If the +POLICY bit (see section \ref{sec:masks}) is set in aux_attributes, the +policy field names the principal's policy. If the POLICY bit is not +set in aux_attributes, no policy is enforced on the principal and the +value of the policy field is undefined. \begin{figure}[htbp] \begin{verbatim} @@ -113,11 +105,6 @@ typedef struct _ovsec_kadm_principal_ent_t { krb5_mkvno mkvno; char * policy; - u_int32 pw_min_life; - u_int32 pw_max_life; - u_int32 pw_min_length; - u_int32 pw_min_classes; - u_int32 pw_history_num; u_int32 aux_attributes; } ovsec_kadm_principal_ent_rec, *ovsec_kadm_principal_ent_t; \end{verbatim} @@ -126,8 +113,7 @@ typedef struct _ovsec_kadm_principal_ent_t { \end{figure} The fields of an ovsec_kadm_principal_ent_t are interpreted as -follows. For the semantics of the policy overriding fields, see -\ref{sec:policy-fields}. +follows. \begin{description} \item[principal] The name of the principal; must conform to Kerberos @@ -148,24 +134,25 @@ user can still obtain ticket-granting tickets. \item[max_life] The maximum lifetime of any Kerberos ticket issued to this principal. -\item[attributes] A bitfield of attributes for use by the KDC. The -bits are as follows. Note that only DISALLOW_ALL_TIX and -REQUIRES_PWCHANGE are explicitly supported by \secure{}. - -\begin{verbatim} -KRB5_KDB_DISALLOW_POSTDATED 0x00000001 -KRB5_KDB_DISALLOW_FORWARDABLE 0x00000002 -KRB5_KDB_DISALLOW_TGT_BASED 0x00000004 -KRB5_KDB_DISALLOW_RENEWABLE 0x00000008 -KRB5_KDB_DISALLOW_PROXIABLE 0x00000010 -KRB5_KDB_DISALLOW_DUP_SKEY 0x00000020 -KRB5_KDB_DISALLOW_ALL_TIX 0x00000040 -KRB5_KDB_REQUIRES_PRE_AUTH 0x00000080 -KRB5_KDB_REQUIRES_HW_AUTH 0x00000100 -KRB5_KDB_REQUIRES_PWCHANGE 0x00000200 -KRB5_KDB_DISALLOW_SVR 0x00001000 -KRB5_KDB_PWCHANGE_SERVICE 0x00002000 -\end{verbatim} +\item[attributes] A bitfield of attributes for use by the KDC. +Note that only some are explicitly supported by \secure{}. XXX Note: +We really should check what all of these mean. + +\begin{tabular}{clr} +{\bf Supported} & {\bf Name} & {\bf Value} \\ + & KRB5_KDB_DISALLOW_POSTDATED & 0x00000001 \\ + & KRB5_KDB_DISALLOW_FORWARDABLE & 0x00000002 \\ +X & KRB5_KDB_DISALLOW_TGT_BASED & 0x00000004 \\ + & KRB5_KDB_DISALLOW_RENEWABLE & 0x00000008 \\ + & KRB5_KDB_DISALLOW_PROXIABLE & 0x00000010 \\ + & KRB5_KDB_DISALLOW_DUP_SKEY & 0x00000020 \\ +X & KRB5_KDB_DISALLOW_ALL_TIX & 0x00000040 \\ + & KRB5_KDB_REQUIRES_PRE_AUTH & 0x00000080 \\ + & KRB5_KDB_REQUIRES_HW_AUTH & 0x00000100 \\ +X & KRB5_KDB_REQUIRES_PWCHANGE & 0x00000200 \\ + & KRB5_KDB_DISALLOW_SVR & 0x00001000 \\ + & KRB5_KDB_PWCHANGE_SERVICE & 0x00002000 +\end{tabular} \item[mod_name] The name of the Kerberos principal that most recently modified this principal. @@ -181,28 +168,12 @@ this principal's key was last changed. \item[policy] If the POLICY bit is set in aux_attributes, the name of the policy controlling this principal. -\item[pw_min_life] If the PW_MIN_LIFE bit is set in aux_attributes, -the pw_min_life for this principal. - -\item[pw_max_life] If the PW_MAX_LIFE bit is set in aux_attributes, -the pw_max_life for this principal. - -\item[pw_min_length] If the PW_MIN_LENGTH bit is set in -aux_attributes, the pw_min_length for this principal. - -\item[pw_min_classes] If the PW_MIN_CLASSES bit is set in the -aux_attributes, the pw_min_classes for this principal. - -\item[pw_history_num] If the PW_HISTORY_NUM bit is set in -aux_attributes, the pw_history_num for this principal. - \item[aux_attributes] A bitfield of flags for use by the -administration system. Currently, the only valid flags specify which -policy fields are overridden for this principal. See section -\ref{sec:masks}. +administration system. Currently, the only valid flag is POLICY, and +it indicates whether or not the principal has a policy enforced on it. \end{description} -\subsection{Policies, ovsec_kadm_policy_ent_t} +\subsubsection{Policies, ovsec_kadm_policy_ent_t} \label{sec:policy-fields} If the POLICY bit is set in aux_attributes, the \v{policy} name field @@ -224,11 +195,10 @@ typedef struct _ovsec_kadm_policy_ent_t { The fields of an ovsec_kadm_policy_ent_t are interpreted as follows. Note that a policy's values only apply to a principal using that -policy, and only when the corresponding override bit is not set in the -principal's aux_attributes field. +policy. \begin{description} -\item[name] The name of this policy, as a NULL-terminated string. +\item[policy] The name of this policy, as a NULL-terminated string. The ASCII characters between 32 (space) and 126 (tilde), inclusive, are legal. @@ -256,19 +226,21 @@ set its password to any of its previous pw_history_num passwords. A policy cannot be deleted unless this number is zero. \end{description} -\subsection{Create/Modify Masks} +\subsubsection{Create/Modify Masks} \label{sec:masks} The API functions for creating and modifying principals and policies -allow for a relevant subset of the fields to be specified or changed. -The chosen fields are determined by a bitmask that is passed to the -relevant function. Each API function has different rules for which -mask values can be specified, and can specify whether a given mask -value is mandatory, optional, or forbidden. Mandatory fields must be -present and forbidden fields must not be present or an error is -generated. When creating a principal or policy, optional fields have -a default value if they are not specified; when modifying a principal -or policy, optional fields are unchanged if they are not specified. +allow for a relevant subset of the fields of the +ovsec_kadm_principal_ent_t and ovsec_kadm_policy_ent_t to be specified +or changed. The chosen fields are determined by a bitmask that is +passed to the relevant function. Each API function has different +rules for which mask values can be specified, and can specify whether +a given mask value is mandatory, optional, or forbidden. Mandatory +fields must be present and forbidden fields must not be present or an +error is generated. When creating a principal or policy, optional +fields have a default value if they are not specified; when modifying +a principal or policy, optional fields are unchanged if they are not +specified. The masks for principals are in table \ref{tab:princ-bits} and the masks for policies are in table \ref{tab:policy-bits}. The @@ -277,19 +249,13 @@ Create and Modify fields, M means mandatory, F means forbidden, and O means optional. Create fields that are optional specify the default value. -Note that the POLICY, POLICY_CLR, PW_*, and PW_*_CLR masks are -special. When POLICY is set, the policy is assigned to the principal. -When POLICY_CLR is specified, the policy is unassigned to the -principal and as a result no policy controls the principal. When a -PW_* bit is set, the new value is stored and registered as a policy -override. When a PW_*_CLR bit is set, the policy override value is -removed, thus putting that field back under the principal's policy's -control. It is an error to specify both a PW_* bit and its PW_*_CLR -bit or both the POLICY and POLICY_CLR bits. +Note that the POLICY and POLICY_CLR bits are special. When POLICY is +set, the policy is assigned to the principal. When POLICY_CLR is +specified, the policy is unassigned to the principal and as a result +no policy controls the principal. If the principal has a policy assigned, the POLICY bit is set in -aux_attributes. Each enabled override is indicated by having the -corresponding PW_* bit set in aux_attributes. +aux_attributes. \begin{table}[htbp] \begin{tabular}{@{}lclll} @@ -305,19 +271,9 @@ MOD_TIME & 0x000040 & mod_date & F & F \\ MOD_NAME & 0x000080 & mod_name & F & F \\ KVNO & 0x000100 & kvno & O, 1 & O \\ MKVNO & 0x000200 & mkvno & F & F \\ -POLICY & 0x000400 & policy & O, none & O \\ -POLICY_CLR & 0x000800 & policy & F & O \\ -PW_MAX_LIFE & 0x001000 & pw_max_life & O, policy & O \\ -PW_MAX_LIFE_CLR & 0x002000 & pw_max_life & F & O \\ -PW_MIN_LIFE & 0x004000 & pw_min_life & O, policy & O \\ -PW_MIN_LIFE_CLR & 0x008000 & pw_min_life & F & O \\ -PW_MIN_LENGTH & 0x010000 & pw_min_length & O, policy & O \\ -PW_MIN_LENGTH_CLR & 0x020000 & pw_min_length & F & O \\ -PW_MIN_CLASSES & 0x040000 & pw_min_classes & O, policy & O \\ -PW_MIN_CLASSES_CLR & 0x080000 & pw_min_classes & F & O \\ -PW_HISTORY_NUM & 0x100000 & pw_history_num & O, policy & O \\ -PW_HISTORY_NUM_CLR & 0x200000 & pw_history_num & F & O \\ -AUX_ATTRIBUTES & 0x400000 & aux_attributes & O, 0 & O \\ +AUX_ATTRIBUTES & 0x000400 & aux_attributes & O, 0 & O \\ +POLICY & 0x000800 & policy & O, none & O \\ +POLICY_CLR & 0x001000 & policy & F & O \end{tabular} \caption{Mask bits for creating/modifying principals.} \label{tab:princ-bits} @@ -326,13 +282,13 @@ AUX_ATTRIBUTES & 0x400000 & aux_attributes & O, 0 & O \\ \begin{table}[htbp] \begin{tabular}{@{}lclll} Name & Value & Field Affected & Create & Modify \\ -POLICY & same & policy & M & F \\ -PW_MAX_LIFE & same & pw_max_life & O, infinite & O \\ -PW_MIN_LIFE & same & pw_min_life & O, 0 & O \\ -PW_MIN_LENGTH & same & pw_min_length & O, 0 & O \\ -PW_MIN_CLASSES & same & pw_min_classes & O, 1 & O \\ -PW_HISTORY_NUM & same & pw_history_num & O, 0 & O \\ -REF_COUNT & 0x01 & pw_refcnt & O, 0 & O +POLICY & 0x002000 & policy & M & F \\ +PW_MAX_LIFE & 0x004000 & pw_max_life & O, infinite & O \\ +PW_MIN_LIFE & 0x008000 & pw_min_life & O, 0 & O \\ +PW_MIN_LENGTH & 0x010000 & pw_min_length & O, 0 & O \\ +PW_MIN_CLASSES & 0x020000 & pw_min_classes & O, 1 & O \\ +PW_HISTORY_NUM & 0x040000 & pw_history_num & O, 0 & O \\ +REF_COUNT & 0x080000 & pw_refcnt & O, 0 & O \end{tabular} \caption{Mask bits for creating/modifying policies.} \label{tab:policy-bits} @@ -373,6 +329,8 @@ policy. \item[OVSEC_KADM_UNK_POLICY] The named policy does not exist. \item[OVSEC_KADM_BAD_MASK] The principal or policy field mask is invalid for the current operation. +\item[OVSEC_KADM_BAD_CLASS] The number of character classes specified +is invalid. \item[OVSEC_KADM_PASS_Q_TOOSHORT] The password does not contain enough characters. \item[OVSEC_KADM_PASS_Q_CLASS] The password must contain characters @@ -426,12 +384,10 @@ ever returned to an unauthorized user. obviously invalid values, and returns OVSEC_KADM_BAD_ARG if any are detected. -\item Any function that uses a policy value uses the principal's -policy override value if the appropriate aux_attributes bit is set; -otherwise, if the POLICY bit is set in aux_attributes, it uses the -value from the principal's policy. If a function attempts to check a -policy value and neither the principal's corresponding PW_* nor POLICY -bits are set in aux_attributes, the policy check is not performed. +\item Any function that performs a policy check uses the policy named +in the principal's policy field. If the POLICY bit is not set in the +principal's aux_attributes field, however, the principal has no +policy, so the policy check is not performed. \item Unless otherwise specified, all functions return OVSEC_KADM_OK. \end{itemize} @@ -447,7 +403,8 @@ rename_principal & add and delete & Rename a principal. \\ get_principal & get\footnotemark & Retrieve a principal. \\ chpass_principal & modify\footnotemark[\thefootnote] & Change a principal's password. \\ -randkey_principal & modify & Randomize a principal's key. \\ +randkey_principal & modify\footnotemark[\thefootnote] & + Randomize a principal's key. \\ create_policy & add & Create a new policy. \\ delete_policy & delete & Delete a policy. \\ modify_policy & modify & Modify the attributes of a policy. \\ @@ -466,8 +423,7 @@ details.} \begin{verbatim} ovsec_kadm_ret_t -ovsec_kadm_create_principal(ovsec_kadm_princ_ent_t, - ovsec_kadm_princ_mask_t, char *); +ovsec_kadm_create_principal(ovsec_kadm_princ_ent_t, u_int32, char *); \end{verbatim} AUTHORIZATION REQUIRED: add @@ -485,10 +441,15 @@ count by one. \item Set the pw_expiration field. \begin{enumerate} -\item If the POLICY bit is not set, set pw_expiration to never. -\item Otherwise, if the PW_EXPIRATION bit is set, set -pw_expiration to the given value. -\item Otherwise, set pw_expiration time to now + pw_max_life. +\item If the POLICY bit is not set, then +\begin{enumerate} +\item if the PW_EXPIRATION bit is set, set pw_expiration to the given +value, else +\item set pw_expiration to never. +\end{enumerate} +\item Otherwise, if the PW_EXPIRATION bit is set, set pw_expiration to +the maximum of the given value and now + pw_max_life. +\item Otherwise, set pw_expiration to now + pw_max_life. \end{enumerate} \item Set last_pwd_change and mod_date to now and set mod_name to caller. @@ -529,8 +490,7 @@ RETURN CODES: \begin{verbatim} ovsec_kadm_ret_t -ovsec_kadm_modify_principal(ovsec_kadm_prin_ent_t, - ovsec_kadm_princ_mask); +ovsec_kadm_modify_principal(ovsec_kadm_prin_ent_t, u_int32); \end{verbatim} Modify the attributes of the principal named in @@ -544,8 +504,8 @@ AUTHORIZATION REQUIRED: modify \item Return OVSEC_KADM_BAD_MASK if the mask is invalid. \item If POLICY bit is set but the new policy does not exist, return OVSEC_KADM_UNK_POLICY. -\item If any of the POLICY, POLICY_CLR, PW_*, or PW_*_CLR bits are -set, update the corresponding bits in aux_attributes. +\item If either the POLICY or POLICY_CLR bits are set, update the +corresponding bits in aux_attributes. \item Update policy reference counts. \begin{enumerate} @@ -557,14 +517,15 @@ aux_attributes is set, decrement policy count on old policy. \item Set pw_expiration according to the new policy. \begin{enumerate} -\item If the POLICY bit is not set in aux_attributes, set -pw_expiration to never. -\item Otherwise, if PW_EXPIRATION is specified, then set -pw_expiration to the new value. -\item Otherwise, if PW_MAX_LIFE changes (either because it or POLICY -is specified in the mask), set pw_expiration to last_pwd_change + -pw_max_life. Note that this means an explicit PW_EXPIRATION overrides -pw_max_life. +\item If the POLICY bit is not set in aux_attributes, then +\begin{enumerate} +\item if the PW_EXPIRATION bit is set, set pw_expiration to the given +value, else +\item set pw_expiration to never. +\end{enumerate} +\item Otherwise, if the PW_EXPIRATION bit is set, set pw_expiration to +the maximum of the given value and last_pwd_change + pw_max_life. +\item Otherwise, set pw_expiration to last_pwd_change + pw_max_life. \end{enumerate} \item Update the fields specified in the mask. @@ -585,8 +546,7 @@ policy does not exist. \begin{verbatim} ovsec_kadm_ret_t -ovsec_kadm_rename_principal(krb5_principal source, - krb5_principal target); +ovsec_kadm_rename_principal(krb5_principal source, krb5_principal target); \end{verbatim} AUTHORIZATION REQUIRED: add and delete @@ -598,6 +558,19 @@ OVSEC_KADM_UNK_PRINC error. \item Rename principal. \end{enumerate} +Note that since the principal name may have been used as the salt for +the principal's key, renaming the principal may render the principal's +current password useless; with the new salt, the key generated by +string-to-key on the password will suddenly be different. Therefore, +an application that renames a principal must also require the user to +specify a new password for the principal (and administrators should +notify the affected party). + +Note also that, by the same argument, renaming a principal will +invalidate that principal's password history information; since the +salt will be different, a user will be able to select a previous +password without error. + RETURN CODES: \begin{description} @@ -609,37 +582,51 @@ RETURN CODES: \begin{verbatim} ovsec_kadm_ret_t -ovsec_kadm_chpass_principal(krb5_principal princ, char *pw); +ovsec_kadm_chpass_principal(krb5_principal princ, char *pw, + int override_qual); \end{verbatim} AUTHORIZATION REQUIRED: modify, or the calling principal being the same as the princ argument. -Change a principal's password. In the description below, all the -checks that can result in password-related errors do not apply to -callers that have the modify privilege but are {\it not} the same as -the principal being affected. Thus, an administrator can change a -principal's password to one that violates the principal's policy, but -cannot change its own password to one that violates its own policy. +Change a principal's password. -Also note that the password quality or history steps should only be -performed if the POLICY bit is set in the principal's aux_attributes -field. +In the description below, all the checks that can result in +policy-related errors do not apply to callers that have the modify +privilege but are {\it not} the same as the principal being affected. +Thus, an administrator can change a principal's password in violation +of that principal's policy, but cannot change its own password in +violation of its own policy. +Note that the policy checks are only be performed if the POLICY bit is +set in the principal's aux_attributes field. + +\begin{enumerate} +\item Determine whether password quality checks should be overridden. \begin{enumerate} +\item If the POLICY bit is not set in aux_attributes, set +override_qual to true. +\item Otherwise, if the caller does not have the modify priviledge, +set override_qual to false. +\item Otherwise, if the caller has the modify privilege, but princ is the +same as the caller, set override_qual to false. +\item Otherwise, if the caller has the modify privilege and princ is +not the same as the caller, leave override_qual as it is. +\end{enumerate} \item Make sure principal exists, if not return OVSEC_KADM_UNK_PRINC error. -\item See if current password is older than password minimum life, -if not return OVSEC_KADM_PASS_TOOSOON error. -\item If the password does not meet quality standards, return the -appropriate OVSEC_KADM_PASS_Q_* error code. -\item Convert password to key. -\item Check to see if new key is in history, if so return -OVSEC_KADM_PASS_REUSE error. +\item If override_qual is false and (now - last_pwd_change) $<$ +pw_min_life, return OVSEC_KADM_PASS_TOOSOON. +\item If override_qual is false and the password does not meet the quality +standards, return the appropriate OVSEC_KADM_PASS_Q_* error code. +\item Convert password to key. The key is generated with +Kerberos' string-to-key function, using the salt method specified on +the admin server's command line; see section \ref{sec:commandline}. +\item If override_qual is false and the new key is in the principal's +password history, return OVSEC_KADM_PASS_REUSE. \item Store old key in history. \item Update principal to have new key. \item Increment principal's key version number by one. -\item If the POLICY bit in aux_attributes if set, set pw_expiration to -now + max_pw_life. +\item If the POLICY bit is set, set pw_expiration to now + max_pw_life. \item Update last_pwd_change and mod_date to now, update mod_name to caller. \end{enumerate} @@ -660,21 +647,46 @@ life. \begin{verbatim} ovsec_kadm_ret_t -ovsec_kadm_randkey_principal(krb5_principal, krb5_keyblock **); +ovsec_kadm_randkey_principal(krb5_principal, krb5_keyblock **, + int override_qual); \end{verbatim} -AUTHORIZATION REQUIRED: modify - Generate and assign a new random key to the named principal, and return the generated key in allocated storage. The caller must free the returned krb5_keyblock * with krb5_free_keyblock. +AUTHORIZATION REQUIRED: modify, or the calling principal being the +same as the princ argument. + +In the description below, all the checks that can result in +key-related errors do not apply to callers that have the modify +privilege but are {\it not} the same as the principal being affected. +Thus, an administrator can randomize a principal's password in +violation of the principal's policy, but cannot randomize its own +password in violation of its own policy. + +Note that the policy checks are only be performed if the POLICY bit is +set in the principal's aux_attributes field. + +\begin{enumerate} +\item Determine whether policy checks should be overriden. \begin{enumerate} +\item If the POLICY bit is not set in aux_attributes, set +override_qual to true. +\item Otherwise, if the caller does not have the modify priviledge, +set override_qual to false. +\item Otherwise, if the caller has the modify privilege, but princ is the +same as the caller, set override_qual to false. +\item Otherwise, if the caller has the modify privilege and princ is +not the same as the caller, leave override_qual as it is. +\end{enumerate} \item If the principal does not exist, return OVSEC_KADM_UNK_PRINC. +\item If override_qual is false and (now - last_pwd_change) $<$ +pw_min_life, return OVSEC_KADM_PASS_TOOSOON. \item Store old key in history. \item Update principal to have new key. \item Increment principal's key version number by one. -\item If the POLICY bit in aux_attributes if set, set pw_expiration to +\item If the POLICY bit in aux_attributes is set, set pw_expiration to now + max_pw_life. \item Update last_pwd_change and mod_date to now, update mod_name to caller. @@ -684,6 +696,8 @@ RETURN CODES: \begin{description} \item[OVSEC_KADM_UNK_PRINC] Principal does not exist. +\item[OVSEC_KADM_PASS_TOOSOON] The minimum lifetime for the current +key has not expired. \end{description} This function can also be used as part of a sequence to create a new @@ -705,8 +719,7 @@ KRB5_KDB_DISALLOW_ALL_TIX bit in the attributes field. \begin{verbatim} ovsec_kadm_ret_t -ovsec_kadm_get_principal(krb5_principal princ,, - ovsec_kadm_princ_ent_t *ent); +ovsec_kadm_get_principal(krb5_principal princ, ovsec_kadm_princ_ent_t *ent); \end{verbatim} Return the principal's attributes in allocated memory. The caller @@ -725,8 +738,7 @@ RETURN CODES: \begin{verbatim} ovsec_kadm_ret_t -ovsec_kadm_create_policy(ovsec_kadm_policy_ent_t, - ovsec_kadm_policy_mask); +ovsec_kadm_create_policy(ovsec_kadm_policy_ent_t, u_int32); \end{verbatim} Create a new policy. @@ -737,6 +749,8 @@ AUTHORIZATION REQUIRED: add \item Check to see if mask is valid, if not return OVSEC_KADM_BAD_MASK error. \item Check to see if the policy already exists, if so return OVSEC_KADM_DUP error. +\item If the PW_MIN_CLASSES bit is set and pw_min_classes is not 1, 2, +3, or 4, return OVSEC_KADM_BAD_CLASS. \item Create a new policy setting the appropriate fields determined by the mask. \end{enumerate} @@ -747,6 +761,8 @@ RETURN CODES: \item[OVSEC_KADM_DUP] Policy already exists \item[OVSEC_KADM_BAD_MASK] The mask is not valid for a create operation. +\item[OVSEC_KADM_BAD_CLASS] The specified number of character classes +is invalid. \end{description} \subsection{ovsec_kadm_delete_policy} @@ -777,8 +793,7 @@ RETURN CODES: \begin{verbatim} ovsec_kadm_ret_t -ovsec_kadm_modify_policy(ovsec_kadm_policy_ent_t, - ovsec_kadm_policy_mask); +ovsec_kadm_modify_policy(ovsec_kadm_policy_ent_t, u_int32); \end{verbatim} Modify an existing policy. Note that modifying a policy has no affect @@ -791,6 +806,8 @@ AUTHORIZATION REQUIRED: modify \item Check to see if mask is legal, if not return OVSEC_KADM_BAD_MASK error. \item Check to see if policy exists, if not return OVSEC_KADM_UNK_POLICY error. +\item If the PW_MIN_CLASSES bit is set and pw_min_classes is not 1, 2, +3, or 4, return OVSEC_KADM_BAD_CLASS. \item Update the fields specified in the mask. \end{enumerate} @@ -800,14 +817,15 @@ RETURN CODES: \item[OVSEC_KADM_UNK_POLICY] Policy not found. \item[OVSEC_KADM_BAD_MASK] The mask is not valid for a modify operation. +\item[OVSEC_KADM_BAD_CLASS] The specified number of character classes +is invalid. \end{description} \subsection{ovsec_kadm_get_policy} \begin{verbatim} ovsec_kadm_ret_t -ovsec_kadm_get_policy(char *, - ovsec_kadm_policy_ent_t *); +ovsec_kadm_get_policy(char *, ovsec_kadm_policy_ent_t *); \end{verbatim} AUTHORIZATION REQUIRED: get @@ -1015,6 +1033,10 @@ admin principal database. \item If a policy's reference count does not equal the number of principals that use the policy, the reference count is corrected. + +\item If a principal has the POLICY bit set in aux_attributes, and +its (pw_expiration - last_pwd_change) $>$ pw_max_life, the pw_expiration +field is set to last_pwd_change + pw_max_life. \end{itemize} The operations that are only performed if -p is not specified are: diff --git a/doc/kadm5/api-server-design.tex b/doc/kadm5/api-server-design.tex index a955cf2d1..760fbc491 100644 --- a/doc/kadm5/api-server-design.tex +++ b/doc/kadm5/api-server-design.tex @@ -4,15 +4,14 @@ \setlength{\parskip}{.7\baselineskip} \setlength{\parindent}{0pt} -\setcounter{secnumdepth}{4} -\setcounter{tocdepth}{4} \def\secure{OV*Secure} \def\v#1{\verb+#1+} +\def\k#1{K$_#1$} \title{OV*Secure Admin Server \\ Implementation Design} -\author{} -\date{\today} +\author{Barry Jaspan} +\date{DRAFT --- \today} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Make _ actually generate an _, and allow line-breaking after it. @@ -27,8 +26,6 @@ {\setlength{\parskip}{0pt}\tableofcontents} -This section describes the implementation design for the admin server. - \section{Overview} The admin server is implemented as a nearly-stateless transaction @@ -54,6 +51,16 @@ information. \item The policy database stores \secure{} policy information. \end{itemize} +The per-principal information stored in the admin principal database +consists of the principal's policy name and an array of the +principal's previous keys. The old keys are stored encrypted in the +key of the special principal ``kadmin/history'' that is created by +ovsec_kadm_create. Since a change in kadmin/history's key renders +every principal's key history array useless, it can only be changed +using the ovsec_kadm_edit utility; that program will reencrypt every +principal's key history in the new key. The admin server refuses all +requests to change kdamin/history's key. + \section{Main} The admin server starts by trapping all fatal signals and directing @@ -72,11 +79,6 @@ because it is a well-known, portable RPC mechanism. The underlying external data representation (xdr) mechanisms for wire encapsulation are well-known and extensible. -%The RPC specifics can be found in \verb+~access/src/rpc/acl.x+. -%[This, and all the other rpcgen files referenced in this document -%should be in appendices at some point.] Supporting data types are in -%\verb+~access/src/common/api_types.x+. - Authentication to the admin server will be handled by adding a GSS-API authentication type within the existing SUNRPC structure. This will require code modifications to SUNRPC, but the API and wire protocol do @@ -97,35 +99,36 @@ necessary bookkeeping information. The records are keyed by the ASCII representation of the principal's name, including the trailing NULL. \begin{verbatim} -#define MAX_PW_HIST 10 - typedef struct _osa_princ_ent_t { krb5_principal name; char * policy; - u_int32 pw_min_life; - u_int32 pw_max_life; - u_int32 pw_min_length; - u_int32 pw_min_classes; - u_int32 pw_history_num; u_int32 aux_attributes; - krb5_keyblock old_keys[MAX_PW_HIST]; + u_int32 num_old_keys; u_int32 next_old_key; - - u_int32 expansion[8]; + krb5_kvno admin_history_kvno; + krb5_encrypted_keyblock *old_keys; } osa_princ_ent_rec, *osa_princ_ent_t; \end{verbatim} -The only fields that are different from ovsec_kadm_principal_ent_t are -old_keys and next_key. +The fields that are different from ovsec_kadm_principal_ent_t are: \begin{description} -\item[old_keys] The array of previous keys used for password history -checking. Only pw_history_num of these keys should be checked. +\item[num_old_keys] The number of previous keys in the old_keys array. +This value must be 0 $\le$ num_old_keys $<$ pw_history_num. -\item[next_key] The index into old_keys where the next key should be -inserted. This value is always computed modulo pw_history_num. +\item[next_old_key] The index into old_keys where the next key should +be inserted. This value must be 0 $\le$ next_old_key $\le$ +num_old_keys. + +\item[admin_history_kvno] The key version number of the admin/history +principal's key used to encrypt the values in old_keys. If the admin +server finds that admin/history's kvno is different from the value in +this field, an error message is logged. (XXX where?) + +\item[old_keys] The array of the principal's previous keys, each +encrypted in the admin/history key. There are num_old_keys elements. \end{description} \subsection{Policy, osa_policy_ent_t} @@ -145,7 +148,6 @@ typedef struct _osa_policy_ent_t { u_int32 pw_history_num; u_int32 refcnt; - u_int32 expansion[8]; } osa_policy_ent_rec, *osa_policy_ent_t; \end{verbatim} @@ -223,7 +225,8 @@ presented here. \item[OSA_ADB_FAILURE] General failure. \end{description} -Unless otherwise specified, database functions return OSA_ADB_OK. +Database functions can also return system errors. Unless otherwise +specified, database functions return OSA_ADB_OK. \begin{verbatim} osa_adb_ret_t @@ -378,117 +381,61 @@ void krb5_dbm_db_free_principal(krb5_db_entry *entries, int nentries) Frees entries returned by krb5_dbm_db_get_principal. nentries entries in the array entries will be freed. -\subsubsection{Access Initialization} - -Before it is possible to access keys from the Kerberos database, the -Kerberos master key must be acquired so that it can be used to encrypt -and decrypt principal keys as necessary. +\subsubsection{Initialization and Key Access} -Accessing principal keys from the Kerberos database is not as simple -as calling krb5_dbm_db_get_principal. The following function (from -the \v{krb524} server) performs the necessary initialization. +Keys stored in the Kerberos database are encrypted in the Kerberos +master key. The admin server will therefore have to acquire the key +before it can perform any key-changing operations, and will have to +decrypt and encrypt the keys retrieved from and placed into the +database via krb5_db_get_principal and _put_principal. This section +describes the internal admin server API that will be used to perform +these functions. \begin{verbatim} -#include <krb5/krb5.h> -#include <krb5/asn1.h> -#include <krb5/kdb.h> -#include <krb5/kdb_dbm.h> -#ifdef PROVIDE_DES_CBC_CRC -#include <krb5/mit-des.h> -#endif - krb5_principal master_princ; krb5_encrypt_block master_encblock; krb5_keyblock master_keyblock; -void init_master() -{ - int ret; - char *realm; - - if (ret = krb5_get_default_realm(&realm)) { - com_err(whoami, ret, "getting default realm"); - cleanup_and_exit(1); - } - if (ret = krb5_db_setup_mkey_name(NULL, realm, (char **) 0, - &master_princ)) { - com_err(whoami, ret, "while setting up master key name"); - cleanup_and_exit(1); - } - -#ifdef PROVIDE_DES_CBC_CRC - master_encblock.crypto_entry = &mit_des_cryptosystem_entry; -#else - error(You gotta figure out what cryptosystem to use in the KDC); -#endif - - master_keyblock.keytype = KEYTYPE_DES; - if (ret = krb5_db_fetch_mkey(master_princ, &master_encblock, - FALSE, /* non-manual type-in */ - FALSE, /* irrelevant, given prev. arg */ - 0, &master_keyblock)) { - com_err(whoami, ret, "while fetching master key"); - cleanup_and_exit(1); - } - - if (ret = krb5_db_init()) { - com_err(whoami, ret, "while initializing master database"); - cleanup_and_exit(1); - } - if (ret = krb5_process_key(&master_encblock, &master_keyblock)) { - krb5_db_fini(); - com_err(whoami, ret, "while processing master key"); - cleanup_and_exit(1); - } -} +void kdc_init_master() \end{verbatim} -\subsubsection{Reading Principals and Keys} +kdc_init_master opens the database and acquires the master key. It +also sets the global variables master_princ, master_encblock, and +master_keyblock: + +\begin{itemize} +\item master_princ is set to the name of the Kerberos master principal +(\v{K/M@REALM}). + +\item master_encblock is something I have no idea about. -The following function, taken from \v{krb524d} and modified somewhat, -shows how to read a principal from the database and decrypt its key. -server, key, and kvno must all point to allocated storage that will be -filled in. The returned values must be freed with -krb5_db_free_principal and krb5_free_keyblock_contents. +\item master_keyblock is the Kerberos master key +\end{itemize} \begin{verbatim} -krb5_error_code kdc_get_server(service, server, key, kvno) - krb5_principal service; - krb5_db_entry *server; - krb5_keyblock *key; - krb5_kvno *kvno; -{ - krb5_error_code ret; - int nprincs; - krb5_boolean more; - - nprincs = 1; - if (ret = krb5_db_get_principal(service, server, &nprincs, &more)) - return(ret); - - if (more) { - krb5_db_free_principal(server, nprincs); - return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE); - } else if (nprincs != 1) { - krb5_db_free_principal(server, nprincs); - return(KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN); - } - - /* - * convert server.key into a real key (it is encrypted in the - * database) - */ - ret = krb5_kdc_decrypt_key(&master_encblock, server->key, key); - if (kvno) - *kvno = server->kvno; - return ret; -} +krb5_error_code kdb_get_entry_and_key(krb5_principal principal, + krb5_db_entry *entry, + krb5_keyblock *key) \end{verbatim} -\subsubsection{Writing Principals and Keys} +kdb_get_entry_and_key retrieves the named principal's entry from the +database in entry, and decrypts its key into key. The caller must +free entry with krb5_dbm_db_free_principal and free key-$>$contents with +free.\footnote{The caller should also \v{memset(key-$>$contents, 0, +key-$>$length)}. There should be a function krb5_free_keyblock_contents +for this, but there is not.} + +\begin{verbatim} +krb5_error_code kdb_put_entry_pw(krb5_db_entry *entry, char *pw) +\end{verbatim} -I don't know how to do this yet, but the code is contained in -\v{src/admin/edit/kdb5_edit.c}. +kdb_put_entry_pw stores entry in the database. All the entry values +must already be set; this function does not change any of them except +the key. pw, the NULL-terminated password string, is converted to a +key using string-to-key with the salt type specified in +entry-$>$salt_type.\footnote{The salt_type should be set based on the +command line arguments to the kadmin server (see the ``Command Line'' +section of the functional specification).} \section{Admin Principal and Policy Database Implementation} @@ -533,10 +480,8 @@ that are not addresed by the functional specifications. If the named principal exists in either the Kerberos or admin principal database, but not both, return OVSEC_KADM_BAD_DB. -Initialize the elements of the key history array to contain DES keys -of all zero bits; such a key is guaranteed to be invalid (it does not -have proper parity) and so will never generate a false -OVSEC_KADM_PASS_REUSE error. +The principal's initial key is not stored in the key history array at +creation time. \subsection{ovsec_kadm_delete_principal} @@ -548,29 +493,50 @@ principal database, but not both, return OVSEC_KADM_BAD_DB. If the named principal exists in either the Kerberos or admin principal database, but not both, return OVSEC_KADM_BAD_DB. -If PW_HISTORY is specified and the new value $n$ is smaller than the -old value, copy the key values so that the $n$ most recent keys end up -in the part of the history array that will be checked by -ovsec_kadm_chpass_principal. If the new value $n$ is larger than the -old value, initialize the previously unused elements to all have DES -keys with all zero bits. - -\subsection{ovsec_kadm_chpass_principal} - -When comparing the new key to the elements of the key history array, -always compare it to the first pw_history_num values. Even if fewer -than pw_history_num keys have been placed into the array, the create -and modify functions guarantee that the unused elements will be -invalid DES keys and will therefore not result in a false -OVSEC_KADM_PASS_REUSE error. - -Insert the new key as the next_key element in the history array, and -increment next_key by one modulo pw_history_num. +If pw_history_num changes and the new value $n$ is smaller than the +current value of num_old_keys, old_keys should end up with the $n$ +most recent keys; these are found by counting backwards $n$ elements +in old_keys from next_old_key. next_old_keys should then be reset to +0, the oldest of the saved keys, and num_old_keys set to $n$, the +new actual number of old keys in the array. + +\subsection{ovsec_kadm_chpass_principal, randkey_principal} + +The algorithm for determining whether a password is in the principal's +key history is complicated by the use of the kadmin/history \k{h} +encrypting key. + +\begin{enumerate} +\item For ovsec_kadm_chpass_principal, convert the password to a key +using string-to-key and the salt method specified by the command line +arguments. + +\item If the POLICY bit is set and pw_history_num is not zero, check +if the new key is in the history. +\begin{enumerate} +\item Retrieve the principal's current key and decrypt it with \k{M}. +If it is the same as the new key, return OVSEC_KADM_PASS_REUSE. +\item Retrieve the kadmin/history key \k{h} and decrypt it with \k{M}. +\item Encrypt the principal's new key in \k{h}. +\item If the principal's new key encrypted in \k{h} is in old_keys, +return OVSEC_KADM_PASS_REUSE. +\item Encrypt the principal's current key in \k{h} and store it in +old_keys. +\item Erase the memory containing \k{h}. +\end{enumerate} + +\item Encrypt the principal's new key in \k{M} and store it in the +database. +\item Erase the memory containing \k{M}. +\end{enumerate} + +To store the an encrypted key in old_keys, insert it as the +next_old_key element of old_keys, and increment next_old_key by one +modulo pw_history_num. \subsection{ovsec_kadm_get_principal} If the named principal exists in either the Kerberos or admin principal database, but not both, return OVSEC_KADM_BAD_DB. - \end{document} |