From: Barry Jaspan Date: Thu, 7 Oct 1993 15:23:51 +0000 (+0000) Subject: Initial revision X-Git-Tag: krb5-1.0-beta3~188 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=ba5c693c1fb575e6e35fd159659e0c5873af1cf2;p=krb5.git Initial revision git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@2650 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/doc/kadm5/api-funcspec.tex b/doc/kadm5/api-funcspec.tex new file mode 100644 index 000000000..56602541b --- /dev/null +++ b/doc/kadm5/api-funcspec.tex @@ -0,0 +1,1032 @@ +\documentstyle[12pt,fullpage,changebar]{article} + +% $Id$ + +\setlength{\parskip}{.7\baselineskip} +\setlength{\parindent}{0pt} + +\def\secure{OV*Secure} +\def\v#1{\verb+#1+} + +\title{OV*Secure Admin \\ Functional Specifications} +\author{} +\date{\today} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Make _ actually generate an _, and allow line-breaking after it. +\let\underscore=\_ +\catcode`_=13 +\def_{\underscore\penalty75\relax} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\begin{document} + +\maketitle + +{\setlength{\parskip}{0pt}\tableofcontents} + +\section{Admin API} + +This section describes the Admin API that can be used to maintain +principals and policies. It describes the data structures used for +each function and the interpretation of each data type field, the +semantics of each API function, and the possible return codes. + +The Admin API is intended to be used by remote clients using an RPC +interface. It is implemented by the admin server running on the +Kerberos master database. It may also be possible for a program +running on the Kerberos master database to use the Admin API directly, +without going through the admin server. + +\subsection{Policies and Password Quality} + +The Admin API Password Quality mechanism provides the following +controls. Note that two strings are defined to be ``significantly +different'' if they differ by at least two characters. + +\begin{itemize} +\item A minimum length can be required; a password with +fewer than the specified number of characters will not be accepted. + +\item A minimum number of character classes can be required; a +password that does not contain at least one character from at least +the specified number of character classes will not be accepted. The +character classes are defined by islower(), isupper(), isdigit(), +ispunct(), and other. + +\item Passwords can be required to be different from +previous passwords; a password that generates the same encryption key +as any of the principal's specified previous number of passwords will +not be accepted. This comparision is performed on the encryption keys +generated from the passwords, not on the passwords themselves. + +\item A single ``forbidden password'' dictionary can be specified for all +users; a password that is not significantly different from every word +in the dictionary will not be accepted. + +\item A password that is not significantly different from each +component and the realm of the principal's name will not be accepted. +\end{itemize} + +\subsection{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. + +\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. + +\begin{figure}[htbp] +\begin{verbatim} +typedef struct _ovsec_kadm_principal_ent_t { + krb5_principal principal; + + krb5_timestamp princ_expire_time; + krb5_timestamp last_pwd_change; + krb5_timestamp pw_expiration; + krb5_deltat max_life; + krb5_principal mod_name; + krb5_timestamp mod_date; + krb5_flags attributes; + krb5_kvno kvno; + 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} +\caption{Definition of ovsec_kadm_principal_ent_t.} +\label{fig:princ-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}. + +\begin{description} +\item[principal] The name of the principal; must conform to Kerberos +naming specifications. + +\item[princ_expire_time] The expire time of the principal as a Unix +timestamp. No Kerberos tickets will be issued for a principal after +its expire time. + +\item[last_pwd_change] The time this principal's password was last +changed, as a Unix timestamp. + +\item[pw_expiration] The expire time of the user's current password, as a +Unix timestamp. No application service tickets will be issued for the +principal once the password expire time has passed. Note that the +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[mod_name] The name of the Kerberos principal that most recently +modified this principal. + +\item[mod_date] The time this principal was last modified, as a Unix +timestamp. + +\item[kvno] The version of the principal's current key. + +\item[mkvno] The version of the Kerberos Master Key in effect when +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}. +\end{description} + +\subsection{Policies, ovsec_kadm_policy_ent_t} +\label{sec:policy-fields} + +If the POLICY bit is set in aux_attributes, the \v{policy} name field +in the ovsec_kadm_principal_ent_t structure refers to a password +policy entry defined in a \v{ovsec_kadm_policy_ent_t}. + +\begin{verbatim} +typedef struct _ovsec_kadm_policy_ent_t { + 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 policy_refcnt; +} ovsec_kadm_policy_ent_rec, *ovsec_kadm_policy_ent_t; +\end{verbatim} + +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. + +\begin{description} +\item[name] The name of this policy, as a NULL-terminated string. +The ASCII characters between 32 (space) and 126 (tilde), inclusive, +are legal. + +\item[pw_min_life] The minimum password lifetime, in seconds. +A principal cannot change its password before pw_min_life seconds have +passed since last_pwd_change. + +\item[pw_max_life] The default duration, in seconds, used to compute +pw_expiration when a principal's password is changed. + +\item[pw_min_length] The minimum password length, in characters. A +principal cannot set its password to anything with fewer than this +number of characters. + +\item[pw_min_classes] The minimum number of character classes in the +password. This value can only be 1, 2, 3, or 4. A principal cannot +set its password to anything with fewer than this number of character +classes in it. + +\item[pw_history_num] The number of past passwords that are +stored for the principal; its maximum value is 10. A principal cannot +set its password to any of its previous pw_history_num passwords. + +\item[refcnt] The number of principals currently using this policy. +A policy cannot be deleted unless this number is zero. +\end{description} + +\subsection{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. + +The masks for principals are in table \ref{tab:princ-bits} and the +masks for policies are in table \ref{tab:policy-bits}. The +OVSEC_KADM_ prefix has been removed from the Name fields. In the +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. + +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. + +\begin{table}[htbp] +\begin{tabular}{@{}lclll} +{\bf Name} & {\bf Value} & {\bf Field Affected} & {\bf Create} & + {\bf Modify} \\ +PRINCIPAL & 0x000001 & principal & M & F \\ +PRINC_EXPIRE_TIME & 0x000002 & princ_expire_time & O, never & O \\ +PW_EXPIRATION & 0x000004 & pw_expiration & O, now+pw_max_life & O \\ +LAST_PWD_CHANGE & 0x000008 & last_pwd_change & F & F \\ +ATTRIBUTES & 0x000010 & attributes & O, 0 & O \\ +MAX_LIFE & 0x000020 & max_life & O, K/M value & O \\ +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 \\ +\end{tabular} +\caption{Mask bits for creating/modifying principals.} +\label{tab:princ-bits} +\end{table} + +\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 +\end{tabular} +\caption{Mask bits for creating/modifying policies.} +\label{tab:policy-bits} +\end{table} + +\subsection{Error Codes} + +The error codes that can be returned by admin functions are listed +below. Error codes indicated with a ``*'' can be returned by every +admin function and always have the same meaning; these codes are +omitted from the list presented with each function. + +The admin system guarantees that a function that returns an error code +has no other side effect. + +The Admin system will use \v{com_err} for error codes. The error code +table name will be ``kadm'', and the offsets will be the same as the +order presented here. + +\begin{description} +\item[* OVSEC_KADM_OK] Operation successful. +\item[* OVSEC_KADM_FAILURE] Operation failed for unspecified reason. +\item[* OVSEC_KADM_AUTH_GET] Caller is not authorized to perform +operations requiring the ``get'' privilege. +\item[* OVSEC_KADM_AUTH_ADD] Caller is not authorized to perform +operations requiring the ``add'' privilege. +\item[* OVSEC_KADM_AUTH_MODIFY] Caller is not authorized to perform +operations requiring the ``modify'' privilege. +\item[* OVSEC_KADM_AUTH_DELETE] Caller is not authorized to perform +operations requiring the ``delete'' privilege. +\item[* OVSEC_KADM_BAD_ARG] Invalid arguments would result in a memory +error. +\item[* OVSEC_KADM_BAD_DB] A database inconsistency was detected. +\item[* OVSEC_KADM_MEM] Out of memory performing operation. +\item[OVSEC_KADM_DUP] The operation would create a duplicate principal or +policy. +\item[OVSEC_KADM_UNK_PRINC] The named principal does not exist. +\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_PASS_Q_TOOSHORT] The password does not contain enough +characters. +\item[OVSEC_KADM_PASS_Q_CLASS] The password must contain characters +from more character classes. +\item[OVSEC_KADM_PASS_Q_DICT] The password is in the password +dictionary. +\item[OVSEC_KADM_PASS_REUSE] The specified password is in the principal's +password history. +\item[OVSEC_KADM_PASS_TOOSOON] The current password's minimum lifetime +has not passed. +\end{description} + +\subsection{Authorization} + +Each Admin API function requires a specific authorization to run. +This version uses a simple named privilege system with the following +names and meanings: + +\begin{description} +\item[Get] Able to examine the attributes (NOT key data) of principals +and policies. +\item[Add] Able to add principals and policies. +\item[Modify] Able to modify attributes of existing principals and policies. +\item[Delete] Able to remove principals and policies. +\end{description} + +Privileges are specified via an external configuration file on the +Kerberos master server (see section \ref{sec:acls}). + +Each API function description identifies the privilege required to +perform it. + +\subsection{Function Overview} + +The functions provided by the Admin API, and the authorization they +require, are listed in the table below. The ``ovsec_kadm_'' prefix +has been removed from each function name. + +The function semantics in the following sections omit details that are +the same for every function. + +\begin{itemize} +\item The effects of every function are atomic. + +\item Every function performs an authorization check and returns +the appropriate OVSEC_KADM_AUTH_* error code if the caller does not +have the required privilege. No other information or error code is +ever returned to an unauthorized user. + +\item Every function checks its arguments for NULL pointers or other +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 Unless otherwise specified, all functions return OVSEC_KADM_OK. +\end{itemize} + +\begin{tabular}{@{}llp{3.24in}} +{\bf Function Name} & {\bf Authorization} & {\bf Operation} \\ + +create_principal & add & Create a new principal. \\ +delete_principal & delete & Delete a principal. \\ +modify_principal & modify & Modify the attributes of an existing + principal (not password). \\ +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. \\ +create_policy & add & Create a new policy. \\ +delete_policy & delete & Delete a policy. \\ +modify_policy & modify & Modify the attributes of a policy. \\ +get_policy & get & Retrieve a policy. \\ +free_princ & none & Free the memory associated with an + ovsec_kadm_principal_ent_t. \\ +free_policy & none & Free the memory assocated with an + ovsec_kadm_policy_ent_t. \\ +get_privs & none & Return the caller's admin server privileges. +\end{tabular} +\footnotetext[\thefootnote]{These functions also allow a principal to +perform the operation on itself; see the function's semantics for +details.} + +\subsection{ovsec_kadm_create_principal} + +\begin{verbatim} +ovsec_kadm_ret_t +ovsec_kadm_create_principal(ovsec_kadm_princ_ent_t, + ovsec_kadm_princ_mask_t, char *); +\end{verbatim} + +AUTHORIZATION REQUIRED: add + +\begin{enumerate} +\item Return OVSEC_KADM_BAD_MASK if the mask is invalid. +\item If the named principal exists, return OVSEC_KADM_DUP. +\item If the POLICY bit is set and the named policy does not exist, +return OVSEC_KADM_UNK_POLICY. +\item Store the principal, set the 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 the POLICY bit is set, increment the named policy's reference +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. +\end{enumerate} + +\item Set last_pwd_change and mod_date to now and set mod_name to caller. +\end{enumerate} + +RETURN CODES: + +\begin{description} +\item[OVSEC_KADM_BAD_MASK] The field mask is invalid for a create +operation. +\item[OVSEC_KADM_DUP] Principal already exists. +\item[OVSEC_KADM_UNK_POLICY] Policy named in entry does not exist. +\end{description} + +\subsection{ovsec_kadm_delete_principal} + +\begin{verbatim} +ovsec_kadm_ret_t +ovsec_kadm_delete_principal(krb5_principal); +\end{verbatim} + +AUTHORIZATION REQUIRED: delete + +\begin{enumerate} +\item Return OVSEC_KADM_UNK_PRINC if the principal does not exist. +\item If the POLICY bit is set in aux_attributes, decrement the named +policy's reference count by one. +\item Delete principal. +\end{enumerate} + +RETURN CODES: + +\begin{description} +\item[OVSEC_KADM_UNK_PRINC] Principal does not exist. +\end{description} + +\subsection{ovsec_kadm_modify_principal} + +\begin{verbatim} +ovsec_kadm_ret_t +ovsec_kadm_modify_principal(ovsec_kadm_prin_ent_t, + ovsec_kadm_princ_mask); +\end{verbatim} + +Modify the attributes of the principal named in +ovsec_kadm_princ_ent_t. This does not allow the principal to be +renamed or for its password to be changed. + +AUTHORIZATION REQUIRED: modify + +\begin{enumerate} +\item Return OVSEC_KADM_UNK_PRINC if the principal does not exist. +\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 Update policy reference counts. +\begin{enumerate} +\item If the POLICY bit is set, then increment policy count on new +policy. +\item If the POLICY or POLICY_CLR bit is set, and the POLICY bit in +aux_attributes is set, decrement policy count on old policy. +\end{enumerate} + +\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. +\end{enumerate} + +\item Update the fields specified in the mask. +\item Update mod_name field to caller and mod_date to now. +\end{enumerate} + +RETURN CODES: + +\begin{description} +\item[OVSEC_KADM_UNK_PRINC] Entry does not exist. +\item[OVSEC_KADM_BAD_MASK] The mask is not valid for a modify +operation. +\item[OVSEC_KADM_UNK_POLICY] The POLICY bit is set but the new +policy does not exist. +\end{description} + +\subsection{ovsec_kadm_rename_principal} + +\begin{verbatim} +ovsec_kadm_ret_t +ovsec_kadm_rename_principal(krb5_principal source, + krb5_principal target); +\end{verbatim} + +AUTHORIZATION REQUIRED: add and delete + +\begin{enumerate} +\item Check to see if source principal exists, if not return +OVSEC_KADM_UNK_PRINC error. +\item Check to see if target exists, if so return OVSEC_KADM_DUP error. +\item Rename principal. +\end{enumerate} + +RETURN CODES: + +\begin{description} +\item[OVSEC_KADM_UNK_PRINC] Source principal does not exist. +\item[OVSEC_KADM_DUP] Target principal already exist. +\end{description} + +\subsection{ovsec_kadm_chpass_principal} + +\begin{verbatim} +ovsec_kadm_ret_t +ovsec_kadm_chpass_principal(krb5_principal princ, char *pw); +\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. + +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. + +\begin{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 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 Update last_pwd_change and mod_date to now, update mod_name to +caller. +\end{enumerate} + +RETURN CODES: + +\begin{description} +\item[OVSEC_KADM_UNK_PRINC] Principal does not exist. +\item[OVSEC_KADM_PASS_Q_*] Requested password does not meet quality +standards. +\item[OVSEC_KADM_PASS_REUSE] Requested password is in user's +password history. +\item[OVSEC_KADM_PASS_TOOSOON] Current password has not reached minimum +life. +\end{description} + +\subsection{ovsec_kadm_randkey_principal} + +\begin{verbatim} +ovsec_kadm_ret_t +ovsec_kadm_randkey_principal(krb5_principal, krb5_keyblock **); +\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. + +\begin{enumerate} +\item If the principal does not exist, return OVSEC_KADM_UNK_PRINC. +\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 Update last_pwd_change and mod_date to now, update mod_name to +caller. +\end{enumerate} + +RETURN CODES: + +\begin{description} +\item[OVSEC_KADM_UNK_PRINC] Principal does not exist. +\end{description} + +This function can also be used as part of a sequence to create a new +principal with a random key. The steps to perform the operation +securely are + +\begin{enumerate} +\item Create the principal with ovsec_kadm_create_principal with a +random password string and with the KRB5_KDB_DISALLOW_ALL_TIX bit set +in the attributes field. + +\item Randomize the principal's key with ovsec_kadm_randkey_principal. + +\item Call ovsec_kadm_modify_principal to reset the +KRB5_KDB_DISALLOW_ALL_TIX bit in the attributes field. +\end{enumerate} + +\subsection{ovsec_kadm_get_principal} + +\begin{verbatim} +ovsec_kadm_ret_t +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 +must free the returned entry with ovsec_kadm_free_princ_ent. + +AUTHORIZATION REQUIRED: get, or the calling principal being the same +as the princ argument. + +RETURN CODES: + +\begin{description} +\item[OVSEC_KADM_UNK_PRINC] Principal does not exist. +\end{description} + +\subsection{ovsec_kadm_create_policy} + +\begin{verbatim} +ovsec_kadm_ret_t +ovsec_kadm_create_policy(ovsec_kadm_policy_ent_t, + ovsec_kadm_policy_mask); +\end{verbatim} + +Create a new policy. + +AUTHORIZATION REQUIRED: add + +\begin{enumerate} +\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 Create a new policy setting the appropriate fields determined +by the mask. +\end{enumerate} + +RETURN CODES: + +\begin{description} +\item[OVSEC_KADM_DUP] Policy already exists +\item[OVSEC_KADM_BAD_MASK] The mask is not valid for a create +operation. +\end{description} + +\subsection{ovsec_kadm_delete_policy} + +\begin{verbatim} +ovsec_kadm_ret_t +ovsec_kadm_delete_policy(char *); +\end{verbatim} + +Deletes a policy. + +AUTHORIZATION REQUIRED: delete + +\begin{enumerate} +\item Return OVSEC_KADM_UNK_POLICY if the named policy does not exist. +\item Return OVSEC_KADM_POLICY_REF if the named policy's refcnt is not 0. +\item Delete policy. +\end{enumerate} + +RETURN CODES: + +\begin{description} +\item[OVSEC_KADM_UNK_POLICY] Policy does not exist. +\item[OVSEC_KADM_POLICY_REF] Policy is being referenced. +\end{description} + +\subsection{ovsec_kadm_modify_policy} + +\begin{verbatim} +ovsec_kadm_ret_t +ovsec_kadm_modify_policy(ovsec_kadm_policy_ent_t, + ovsec_kadm_policy_mask); +\end{verbatim} + +Modify an existing policy. Note that modifying a policy has no affect +on a principal using the policy until the next time the principal's +password is changed. + +AUTHORIZATION REQUIRED: modify + +\begin{enumerate} +\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 Update the fields specified in the mask. +\end{enumerate} + +RETURN CODES: + +\begin{description} +\item[OVSEC_KADM_UNK_POLICY] Policy not found. +\item[OVSEC_KADM_BAD_MASK] The mask is not valid for a modify +operation. +\end{description} + +\subsection{ovsec_kadm_get_policy} + +\begin{verbatim} +ovsec_kadm_ret_t +ovsec_kadm_get_policy(char *, + ovsec_kadm_policy_ent_t *); +\end{verbatim} + +AUTHORIZATION REQUIRED: get + +Return the policy's attributes in allocated memory. The caller must +free the returned entry with ovsec_kadm_free_policy_ent. + +RETURN CODES: + +\begin{description} +\item[OVSEC_KADM_UNK_POLICY] Policy not found. +\end{description} + +\subsection{ovsec_kadm_free_princ_ent, _policy_ent} + +\begin{verbatim} +ovsec_kadm_ret_t +ovsec_kadm_free_princ_ent(ovsec_kadm_princ_ent_t *); +\end{verbatim} + +Free the memory that was allocated by a call to +ovsec_kadm_get_principal. + +AUTHORIZATION REQUIRED: none (local operation) + +\begin{verbatim} +ovsec_kadm_ret_t +ovsec_kadm_free_policy_ent(ovsec_kadm_policy_ent_t *); +\end{verbatim} + +Free memory that was allocated by a call to ovsec_kadm_get_policy. + +AUTHORIZATION REQUIRED: none (local operation) + +\subsection{ovsec_kadm_get_privs} + +\begin{verbatim} +ovsec_kadm_ret_t +ovsec_kadm_get_privs(u_int32 *); +\end{verbatim} + +Return the caller's admin server privileges in the integer pointed to +by the argument. The Admin API does not define any way for a +principal's privileges to be set. Note that this function will +probably be removed or drastically changed in future versions of this +system. + +The returned value is a bitmask indicating the caller's privileges: + +\begin{tabular}{llr} +{\bf Privilege} & {\bf Symbol} & {\bf Value} \\ +Get & OVSEC_KADM_PRIV_GET & 0x01 \\ +Add & OVSEC_KADM_PRIV_ADD & 0x02 \\ +Modify & OVSEC_KADM_PRIV_MODIFY & 0x04 \\ +Delete & OVSEC_KADM_PRIV_DELETE & 0x08 +\end{tabular} + +There is no guarantee that a caller will have a privilege indicated by +this function for any length of time; applications using this function +must still be prepared to handle all possible OVSEC_KADM_AUTH_* error +codes. + +\section{Server} + +The Admin API will be implemented by a server process running on the +same machine as the Kerberos server, and a client library to +communicate with the server. + +\subsection{Command Line} +\label{sec:commandline} + +The command line syntax of the admin server is + +\begin{verbatim} +admin_server [-createsalt normal|none] [-modifysalt normal|none|keep] +\end{verbatim} + +The -createsalt and -modifysalt arguments control the type of salt +used when creating and modifying keys in the Kerberos database, +respectively. ``normal'' means the standard V5 salt which uses the +principal and realm name. ``none'' means no salt, which is compatible +with Kerberos V4. ``keep'' means maintain the previous salt when a +key is changed. + +\subsection{Authorization ACLs} +\label{sec:acls} + +The admin server will use a simple ACL mechanism to grant privileges +to principals. The file {\tt /krb5/ovsec_admin_acl} will contain a +list of principals and their privileges. It is read at start-up, and +can only be reread by restarting the admin server. + +The format of this file is: + +\begin{itemize} +\item Blank lines or lines beginning with ``\#'' are ignored. + +\item ACL entry lines contain two fields separated by any number of +spaces or tabs. The first field is a Kerberos name that can +optionally have ``*'' as any component, and the second field is the +privilege list. + +\item The privilege list can contain a comma separated list of the +words ``get'', ``add'', ``modify'', and ``delete''. +\end{itemize} + +The principal named in the first field of each ACL entry has the +privileges listed in the second field the ACL entry. A principal +component name of ``*'' is a wildcard and matches any single +component; therefore, the name ``*/admin@FNORD.COM'' matches any +two-component principal name whose second component is ``admin'' in +the FNORD.COM realm. + +\subsection{Logging} + +The server will log each Admin API request. The information logged +will include the authentication name of the caller, the operation +performed, the arguments to the operation, and the return value. +Unauthorized requests will be identifiable by the OVSEC_KADM_AUTH +error code. + +\section{Tools} + +This section describes the tools that will create and maintain the +admin databases on the Kerberos master server. Some of the +information described here depends on design details; it is included +as part of the functional specifications because these tools are part +of the external interface of the administration system. + +\subsection{ovsec_adm_create} + +ovsec_adm_create creates and initializes the databases necessary for +the operation of the admin server. It accepts no command line +arguments. It should be run on the Kerberos master server. + +\begin{enumerate} +\item It creates the databases ``/krb5/ovsec_adm_princ'' and +``/krb5/ovsec_adm_policy''. + +\item It creates the principal ``kadmin@LOCAL.REALM'' in the Kerberos +database if it does not already exist, prompting the user for a +password. It sets the KRB5_KDB_DISALLOW_TGT_BASED bit in the +principal's attributes field. + +\item It creates entries in the admin principal database for all +principals already defined in the Kerberos database, but does not +assign a policy to any principal. +\end{enumerate} + +\subsection{ovsec_adm_edit} + +ovsec_adm_edit allows for low-level maintainance of the admin +principal and policy da\-ta\-ba\-ses.\footnote{We expect this program to +have more functionality in the future.} Its command line usage is + +\begin{verbatim} +ovsec_adm_edit [-dump admin|policy|both] [-restore admin|policy|both] +\end{verbatim} + +If the -dump argument is specified, it dumps either the admin +principal database, the policy database, or both to the standard +output. If the -restore argument is specified, it reads the principal +database, the policy database, or both from the standard input. For +both operations, if both databases are involved, the admin database is +first. + +Each database is represented by an integer in ASCII decimal +representation indicating the number of records, followed by the +records themselves. Each record in the database is printed in its +ASCII representation, separated by a tab character, with each record +followed by a newline. Strings that can contain spaces, tabs, or +newlines are enclosed in double quotes. + +The fields within each record are read and written in the same order +as they appear in the osa_princ_ent_t and osa_policy_ent_t, +respectively (see the design document). +% \ref{sec:db-types} + +\subsection{ovsec_check} + +ovsec_check checks the integrity of the Kerberos and \secure{} +databases. Its command line usage is + +\begin{verbatim} +ovsec_check [-p] [-n] +\end{verbatim} + +If the -n (``no corrections'') argument is specified, it only prints +warnings for detected inconsistencies and makes no attempt to correct +them. If the -p (``preen'') argument is specified, it will +automatically repair a specific subset of inconsistencies and print a +warning about other inconsistencies. If neither argument is +specified, it asks the user whether or not it should fix each +inconsistency, and prompts the user for any information it needs to do +so. + +The operations that are performed automatically if -p is specified +are: + +\begin{itemize} +\item If a principal exists in the Kerberos database that +does not exist in the admin principal database, it is added to the +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. +\end{itemize} + +The operations that are only performed if -p is not specified are: + +\begin{itemize} +\item If a principal exists in the principal admin +database that does not exist in the Kerberos database, it is created +in the Kerberos database with a password specified by the user. + +\item If a principal references a policy that does not exist, the user +is prompted to specify a new policy for the user or to specify that +the user should have no policy. +\end{itemize} + +\end{document} diff --git a/doc/kadm5/api-server-design.tex b/doc/kadm5/api-server-design.tex new file mode 100644 index 000000000..a955cf2d1 --- /dev/null +++ b/doc/kadm5/api-server-design.tex @@ -0,0 +1,576 @@ +\documentstyle[12pt,fullpage,changebar]{article} + +% $Id$ + +\setlength{\parskip}{.7\baselineskip} +\setlength{\parindent}{0pt} +\setcounter{secnumdepth}{4} +\setcounter{tocdepth}{4} + +\def\secure{OV*Secure} +\def\v#1{\verb+#1+} + +\title{OV*Secure Admin Server \\ Implementation Design} +\author{} +\date{\today} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Make _ actually generate an _, and allow line-breaking after it. +\let\underscore=\_ +\catcode`_=13 +\def_{\underscore\penalty75\relax} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\begin{document} + +\maketitle + +{\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 +server, where each admin API function represents a single transaction. +No per-client or per-connection information is stored; only local +database handles are maintained between requests. + +The admin API is exported via an RPC interface that hides all details +about network encoding, authentication, and encryption of data on the +wire. The RPC mechanism does, however, allow the server to access the +underlying authentication credentials for authorization purposes. + +The admin server accesses a total of three databases. + +\begin{itemize} +\item The master Kerberos database is used to store all the +information that the Kerberos server understands, thus allowing the +greatest functionality with no modifications to a standard KDC. + +\item The admin principal database stores \secure{}-specific per-principal +information. + +\item The policy database stores \secure{} policy information. +\end{itemize} + +\section{Main} + +The admin server starts by trapping all fatal signals and directing +them to a cleanup-and-exit function. It then creates and exports the +RPC interface and enters its main loop. + +The main loop dispatches all incoming requests to the RPC mechanism. +After 15 seconds of inactivity, the server closes all open databases; +each database will be automatically reopened by the API function +implementations as necessary. + +\section{Remote Procedure Calls} + +The RPC for the Admin system will be based on SUNRPC. SUNRPC is used +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 +not need to change. This may affect whether the RPC will use UDP or +TCP; although all the admin functions are stateless, the GSS-API +authentication binding will not be and it might be easier to use TCP +for this reason. + +\section{Database Record Types} +\label{sec:db-types} + +\subsection{Admin Principal, osa_princ_ent_t} + +The admin principal database stores records of the type +osa_princ_ent_t, which is the subset of the ovsec_kadm_principal_ent_t +structure that is not stored in the Kerberos database plus the +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 next_old_key; + + u_int32 expansion[8]; +} 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. + +\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[next_key] The index into old_keys where the next key should be +inserted. This value is always computed modulo pw_history_num. +\end{description} + +\subsection{Policy, osa_policy_ent_t} + +The policy database stores records of the type osa_policy_ent_t, which +is all of ovsec_kadm_policy_ent_t plus necessary bookkeeping +information. The records are keyed by the policy name. + +\begin{verbatim} +typedef struct _osa_policy_ent_t { + 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 refcnt; + u_int32 expansion[8]; +} osa_policy_ent_rec, *osa_policy_ent_t; +\end{verbatim} + +\subsection{Kerberos, krb5_db_entry} + +The Kerberos database stores records of type krb5_db_entry, which is +defined in the kdb.h header file. + +\begin{verbatim} +typedef struct _krb5_encrypted_keyblock { + krb5_keytype keytype; + int length; + krb5_octet *contents; +} krb5_encrypted_keyblock; + +typedef struct _krb5_db_entry { + krb5_principal principal; + krb5_encrypted_keyblock key; + krb5_kvno kvno; + krb5_deltat max_life; + krb5_deltat max_renewable_life; + krb5_kvno mkvno; + + krb5_timestamp expiration; + krb5_timestamp pw_expiration; + krb5_timestamp last_pwd_change; + krb5_timestamp last_success; + + krb5_timestamp last_failed; + krb5_kvno fail_auth_count; + + krb5_principal mod_name; + krb5_timestamp mod_date; + krb5_flags attributes; + krb5_int32 salt_type:8, + salt_length:24; + krb5_octet *salt; + krb5_encrypted_keyblock alt_key; + krb5_int32 alt_salt_type:8, + alt_salt_length:24; + krb5_octet *alt_salt; + + krb5_int32 expansion[8]; +} krb5_db_entry; +\end{verbatim} + +The interpretation of most of these fields is the same as given in the +``Principals, ovsec_kadm_principal_ent_t'' section of the functional +specification. The fields that are not defined there are not used by +\secure{}; however, the admin server preserves the value of any fields +it does not understand. + +\section{Database Access Methods} + +\subsection{Principal and Policy Databases} + +This section describes the database abstraction used for the admin +principal and policy databases. Since both databases export +equivalent functionality, the API is only described once. The +character T is used to represent both ``princ'' and ``policy''. + +Note that this is {\it only} a database abstraction. All functional +intelligence, such as maintaining policy reference counts or sanity +checking, must be implemented above this layer. + +The database routines use com_err for error codes. The error code +table name is ``kadb'' and the offsets are the same as the order +presented here. + +\begin{description} +\item[OSA_ADB_OK] Operation successful. +\item[OSA_ADB_DUP] Operation would create a duplicate database entry. +\item[OSA_ADB_NOENT] Named entry not in database. +\item[OSA_ADB_MEM] Out of memory performing operation. +\item[OSA_ADB_FAILURE] General failure. +\end{description} + +Unless otherwise specified, database functions return OSA_ADB_OK. + +\begin{verbatim} +osa_adb_ret_t +osa_adb_open_T(osa_adb_T_t *db); +\end{verbatim} +% +Open the database. Returns OSA_ADB_FAILURE if it cannot open the +database. + +\begin{verbatim} +osa_adb_ret_t +osa_adb_close_T(osa_adb_T_t db); +\end{verbatim} +% +Close an open database. + +\begin{verbatim} +osa_adb_ret_t +osa_adb_create_T(osa_adb_T_t db, ovsec_kadm_T_ent_t entry); +\end{verbatim} +% +Adds the entry to the database. All fields are defined. Returns +OSA_ADB_DUP if it already exists. + +\begin{verbatim} +osa_adb_ret_t +osa_adb_destroy_T(osa_adb_T_t db, ovsec_kadm_T_t name); +\end{verbatim} + +Removes the named entry from the database. Returns OSA_ADB_NOENT if +it does not exist. + +\begin{verbatim} +osa_adb_ret_t +osa_adb_get_T(osa_adb_T_t db, ovsec_kadm_T_t name, + ovsec_kadm_ent_T_t *entry); +\end{verbatim} + +Looks up the named entry in the db, and returns it in *entry in +allocated storage that must be freed with osa_adb_free_T. Returns +OSA_ADB_NOENT if name does not exist, OSA_ADB_MEM if memory cannot be +allocated. + +\begin{verbatim} +osa_adb_ret_t +osadb_adb_put_T(osa_adb_T_t db, ovsec_kadm_T_ent_t entry); +\end{verbatim} + +Modifies the existing entry named in entry. All fields must be filled +in. Returns OSA_DB_NOENT if the named entry does not exist. Note +that this cannot be used to rename an entry; rename is implemented by +deleting the old name and creating the new one (NOT ATOMIC!). + +\subsection{Kerberos Database} + +Kerberos uses dbm to store krb5_db_entry records. It can be accessed +and modified in parallel with the Kerberos server, using functions +that are defined inside the KDC and the libkdb.a. + +\subsubsection{Database Manipulation Functions} + +The following functions are declared in \v{lib/kdb/kdb_dbm.c} in the +Kerberos sources and are available in libkdb.a. They can return the +following error codes; error codes that can be returned by any +function are indicated with a ``*'' and are not listed specifically +for each function. + +\begin{description} +\item[* KRB5_KDB_NOTINITED] The database is not open; call +krb5_dbm_db_init. +\item[* KRB5_KDB_CANTLOCK_DB] The necessary lock cannot be acquired. Try +again later. +\item[* system errors] An error occurred accessing the database files. +\item[KRB5_KDB_DB_INUSE] The database was modified without the use +of proper locking.\footnote{This error occurs when the entire database +is swapped out from the under the process, say by a kdb5_edit restore. +It can only be returned by krb5_db_get_principal. It is not yet clear +what a program should do when it gets this error.} +\item[KRB5_KDB_NOENTRY] The principal to be deleted is not +in the database. +\end{description} + +\begin{verbatim} +krb5_dbm_db_init(void) +\end{verbatim} + +Opens the Kerberos database file (but does not actually call +dbm_open). This can be called even if the database is already open, +in which case it just returns success. + +\begin{verbatim} +krb5_dbm_db_fini(void) +\end{verbatim} + +Closes the database file; this MUST be called before the process +exits. Returns KRB5_KDB_DBNOTINITED if the database isn't open, but +that isn't really a fatal error. + +\begin{verbatim} +krb5_dbm_get_principal(krb5_principal searchfor, + krb5_db_entry *entries, int *nentries, krb5_boolean *more) +\end{verbatim} + +Search the database for the principal searchfor and write the results +into *entries. The interface is set up to handle wildcard gets, but +the code doesn't handle it: *nentries is assumed to be 1, and *more is +always returned as 0. + +This function does not retry if the database cannot be locked; that is +up to the caller. + +Returns KRB5_KDB_DB_INUSE. + +\begin{verbatim} +krb5_dbm_put_principal(krb5_db_entry *entries, int *nentries) +\end{verbatim} + +Stores *nentries elements from the entries array into the database. +On return *nentries is set to the number of entries actually written; +the first *nentries entries will have been written, even if an error +pis returned. + +This function does not retry if the database cannot be locked; that is +up to the caller. + +\begin{verbatim} +krb5_dbm_db_delete_principal(krb5_principal searchfor, int *nentries) +\end{verbatim} + +Removes the principal searchfor from the database. nentries will be +set to 0 or 1 on output, indicating the number of entries deleted (the +code does not currently support wildcards). + +Returns KRB5_KDB_NOENTRY. + +\begin{verbatim} +typedef krb5_error_code (*iter_func)(krb5_pointer, krb5_db_entry *); + +krb5_dbm_db_iterate(iter_func func, krb5_point func_arg) +\end{verbatim} + +Calls (*func)(func_arg, entry) for every entry in the database. If +func returns an error code, the iteration stops and that error code is +returned. + +Returns func error codes. + +\begin{verbatim} +void krb5_dbm_db_free_principal(krb5_db_entry *entries, int nentries) +\end{verbatim} + +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. + +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. + +\begin{verbatim} +#include +#include +#include +#include +#ifdef PROVIDE_DES_CBC_CRC +#include +#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); + } +} +\end{verbatim} + +\subsubsection{Reading Principals and Keys} + +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. + +\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; +} +\end{verbatim} + +\subsubsection{Writing Principals and Keys} + +I don't know how to do this yet, but the code is contained in +\v{src/admin/edit/kdb5_edit.c}. + +\section{Admin Principal and Policy Database Implementation} + +The admin principal and policy databases will each be stored in a +single hash table, implemented by the Berkeley 4.4BSD db library. +Each record will consist of an entire osa_T_ent_t. The key into the +hash table is the entry name (for principals, the ASCII representation +of the name). The value is the T entry structure. Since the key and +data must be self-contained, with no pointers, the Sun xdr mechanisms +will be used to marshal and unmarshal data in the database. + +The server in the first release will be single-threaded in that a +request will run to completion (or error) before the next will run, +but multiple connections will be allowed simultaneously. + +\section{ACLs, acl_check} + +The ACL mechanism described in the ``Authorization ACLs'' section of +the functional specifications will be implemented by the acl_check +function. + +\begin{verbatim} +enum access_t { + ACCESS_DENIED = 0, + ACCESS_OK = 1, +}; + +enum access_t acl_check(krb5_principal princ, char *priv); +\end{verbatim} + +The priv argument must be one of ``get'', ``add'', ``delete'', or +``modify''. acl_check returns 1 if the principal princ has the named +privilege, 0 if it does not. + +\section{Function Details} + +This section discusses specific design issues for Admin API functions +that are not addresed by the functional specifications. + +\subsection{ovsec_kadm_create_principal} + +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. + +\subsection{ovsec_kadm_delete_principal} + +If the named principal exists in either the Kerberos or admin +principal database, but not both, return OVSEC_KADM_BAD_DB. + +\subsection{ovsec_kadm_modify_principal} + +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. + +\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}