"Fossies" - the Fresh Open Source Software Archive

Member "krb5-1.18/doc/kadm5/api-server-design.tex" (12 Feb 2020, 46633 Bytes) of package /linux/misc/krb5-1.18.tar.gz:

As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) TeX and LaTeX source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file.

    1 % This document is included for historical purposes only, and does not
    2 % apply to krb5 today.
    4 \documentstyle[12pt,fullpage]{article}
    6 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    7 %% Make _ actually generate an _, and allow line-breaking after it.
    8 \let\underscore=\_
    9 \catcode`_=13
   10 \def_{\underscore\penalty75\relax}
   11 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   13 \setlength{\parskip}{.7\baselineskip}
   14 \setlength{\parindent}{0pt}
   16 \def\v#1{\verb+#1+}
   17 \def\k#1{K$_#1$}
   19 \title{KADM5 Library and Server \\ Implementation Design}
   20 \author{Barry Jaspan}
   22 \begin{document}
   24 \sloppy
   25 \maketitle
   27 {\setlength{\parskip}{0pt}\tableofcontents}
   29 \section{Overview}
   31 The KADM5 administration system is designed around the KADM5 API.  The
   32 ``server-side'' library libkadm5srv.a implements the KADM5 API by
   33 operating directly on the underlying KDC and admin databases.  The
   34 ``client-side'' library libkadm5clnt.a implements the KADM5 API via an
   35 RPC mechanism.  The administration server kadmind accepts RPC requests
   36 from the client-side library and translates them into calls to the
   37 server-side library, performing authentication, authorization, and
   38 logging along the way.
   40 The two libraries, libkadm5clnt.a and libkadm5srv.a, export the
   41 identical kadm5 interface; for example, both contain definitions for
   42 kadm5_get_principal, and all other kadm5 functions.  In most cases,
   43 the client library function just marshalls arguments and results into
   44 and out of an RPC call, whereas the server library function performs
   45 the actual operation on the database file.  kadm5_init_*, however, are
   46 substantially different even though they export the same interface: on
   47 the client, they establish the RPC connection and GSS-API context,
   48 whereas on the server side the open the database files, read in the
   49 password dictionary, and the like.  Also, the kadm5_free functions
   50 operate on local process memory in both libraries.
   52 The admin server is implemented as a nearly-stateless transaction
   53 server, where each admin API function represents a single transaction.
   54 No per-client or per-connection information is stored; only local
   55 database handles are maintained between requests.  The RPC mechanism
   56 provides access to remote callers' authentication credentials for
   57 authorization purposes.
   59 The admin API is exported via an RPC interface that hides all details
   60 about network encoding, authentication, and encryption of data on the
   61 wire.  The RPC mechanism does, however, allow the server to access the
   62 underlying authentication credentials for authorization purposes.
   64 The admin system maintains two databases:
   65 %
   66 \begin{itemize}
   67 \item The master Kerberos (KDC) database is used to store all the
   68 information that the Kerberos server understands, thus allowing the
   69 greatest functionality with no modifications to a standard KDC.  
   71 \item The KDC database also stores kadm5-specific per-principal
   72 information in each principal's krb5_tl_data list.  In a prior
   73 version, this data was stored in a separate admin principal database;
   74 thus, when this document refers to ``the admin principal database,''
   75 it now refers to the appropriate krb5_tl_data entries in the KDC
   76 database.
   78 \item The policy database stores kadm5 policy information.
   79 \end{itemize}
   81 The per-principal information stored in the admin principal database
   82 consists of the principal's policy name and an array of the
   83 principal's previous keys.  The old keys are stored encrypted in the
   84 key of the special principal ``kadmin/history'' that is created by the
   85 server library when it is first needed.  Since a change in
   86 kadmin/history's key renders every principal's key history array
   87 useless, it can only be changed using the ovsec_adm_edit utility; that
   88 program will reencrypt every principal's key history in the new
   89 key.\footnote{ovsec_adm_edit has not yet been implemented, and there
   90 are currently no plans to implement it; thus, the history cannot
   91 currently be changed.}  The server library refuses all requests to
   92 change kadmin/history's key.
   94 \section{API Handles}
   96 Each call to kadm5_init_* on the client or server creates a new API
   97 handle.  The handles encapsulate the API and structure versions
   98 specified by kadm5_init_*'s caller and all other internal data needed
   99 by the library.  A process can have multiple open API handles
  100 simultaneously by calling kadm5_init_* multiple times, and call can
  101 specify a different version, client or service principal, and so
  102 forth.
  104 Each kadm5 function verifies the handle it is given with the
  106 differs for the client and server library because the handle types
  107 used by those libraries differ, so it is defined in both
  108 $<$client_internal.h$>$ and $<$server_internal.h$>$ in the library
  109 source directory.  In each header file, CHECK_HANDLE first calls
  110 GENERIC_CHECK_HANDLE, defined in $<$admin_internal.h$>$, which
  111 verifies the magic number, API version, and structure version that is
  112 contained in both client and server handles.  CHECK_HANDLE then calls
  113 either CLIENT_CHECK_HANDLE or SERVER_CHECK_HANDLE respectively to
  114 verify the client- or server-library specific handle fields.
  116 The CHECK_HANDLE macro is useful because it inlines the handle check
  117 instead of requiring a separate function call.  However, using
  118 CHECK_HANDLE means that a source file cannot be compiled once and
  119 included into both the client and server library, because CHECK_HANDLE
  120 is always either specific to either the client or server library, not
  121 both.  There are a number of functions that can be implemented with
  122 the same code in both the client and server libraries, however,
  123 including all of the kadm5_free functions and
  124 kadm5_chpass_principal_util.  The _KADM5_CHECK_HANDLE macro solves
  125 this problem; instead of inlining the handle check, it calls the
  126 function _kadm5_check_handle which is defined separately in both the
  127 client and server library, in client_init.c and server_init.c.
  128 Since these two files are only compiled once and put in a single
  129 library, they simply verify the handle they are passed with
  130 CHECK_HANDLE and return the result.
  132 \section{API Versioning}
  134 The KADM5 system was designed by OpenVision to support multiple
  135 versions of the KADM5 API.  MIT has not adopted this level of support,
  136 and considers the KADM5 C API to be unstable from release to release.
  137 This section describes the original design intent; bear in mind that
  138 only the most recent API is supported by current MIT krb5 releases,
  139 and that the API version does not necessarily change with API changes
  140 unless there is a need to do so for wire compatibility.
  142 Historically, three versions of the KADM5 API have existed:
  143 KADM5_API_VERSION_1 through KADM5_API_VERSION_3.  The first version
  144 was equivalent to the initial OpenVision API,
  145 OVSEC_KADM_API_VERSION_1; the second was created during the initial
  146 integration of the OpenVision system into the MIT release; and the
  147 third was created for MIT krb5 1.8 to add lockout fields to policy
  148 entries.  MIT dropped wire compatibility support for version 1 in MIT
  149 krb5 1.8 (as version 1 was never used in shipped MIT code), but
  150 retains wire compatibility support for version 2.
  152 Implementing a versioned API in C via with both local and RPC access
  153 presents a number of design issues, some of them quite subtle.  The
  154 contexts in which versioning considerations must be made include:
  156 \begin{enumerate}
  157 \item Typedefs, function declarations, and defined constants depend on
  158 the API version a client is written to and must be correct at compile
  159 time.
  161 \item Each function in the server library must behave according to the
  162 API version specified by the caller at runtime to kadm5_init_*.
  164 \item The XDR functions used by the RPC layer to transmit function
  165 arguments and results must encode data structures correctly depending
  166 on the API version specified by the client at runtime.
  168 \item Each function in the client library must behave according to the
  169 API version specified by the caller at runtime to kadm5_init_*.
  171 \item The RPC server (kadmind) must accept calls from a client using
  172 any supported API version, and must then invoke the function in the
  173 server library corresponding to the RPC with the API version indicated
  174 by the client caller.
  176 \item When a first API function is invoked that needs to call a second
  177 function in the API on its own behalf, and that second API function's
  178 behavior depends on the API version specified, the first API function
  179 must either be prepared to call the second API function at whatever
  180 version its caller specifies or have a means of always calling the
  181 second API function at a pre-determined version.
  182 \end{enumerate}
  184 The following functions describe how each context is handled.
  186 \subsection{Designing for future compatibility}
  188 Any code whose behavior depends on the API version should be written
  189 so as to be compatible with future, currently unknown API versions on
  190 the grounds that any particuarly piece of API behavior will most
  191 likely not change between versions.  For example, in the current
  192 system, the code is not written as ``if this is VERSION_1, do X, else
  193 if this is VERSION_2, do Y''; instead, it is written as ``if this is
  194 VERSION_1, do X; else, do Y.''  The former will require additional
  195 work when VERSION_3 is defined, even if ``do Y'' is still the correct
  196 action, whereas the latter will work without modification in that
  197 case.
  199 \subsection{Header file declarations}
  201 Typedefs, defined constants and macros, and function declarations may
  202 change between versions.  A client is always written to a single,
  203 specific API version, and thus expects the header files to define
  204 everything according to that API.  Failure of a header file to define
  205 values correctly will result in either compiler warnings (e.g. if the
  206 pointer type of a function argument changes) or fatal errors (e.g. if
  207 the number of arguments to a function changes, or the fields of a
  208 structure change).  For example, in VERSION_1, kadm5_get_policy took a
  209 pointer to a pointer to a structure, and in VERSION_2 it takes a
  210 pointer to a structure; that would generate a warning if not correct.
  211 In VERSION_1, kadm5_randkey_principal accepted three arguments but in
  212 VERSION_2 accepts four; that would generate a fatal error.
  214 The header file defines everything correctly based on the value of the
  215 USE_KADM5_API_VERSION constant.  The constant can be assigned to an
  216 integer corresponding to any supported API version, and defaults to
  217 the newest version.  The header files then simply use an \#ifdef to
  218 include the right definitions:
  219 %
  220 \begin{verbatim}
  221 #if USE_KADM5_API_VERSION == 1
  222 kadm5_ret_t    kadm5_get_principal(void *server_handle,
  223                                    krb5_principal principal,
  224                                    kadm5_principal_ent_t *ent);
  225 #else
  226 kadm5_ret_t    kadm5_get_principal(void *server_handle,
  227                                    krb5_principal principal,
  228                                    kadm5_principal_ent_t ent,
  229                                    long mask);
  230 #endif
  231 \end{verbatim}
  233 \subsection{Server library functions}
  235 Server library functions must know how many and what type of arguments
  236 to expect, and must operate on those arguments correctly, based on the
  237 API version with which they are invoked.  The API version is contained
  238 in the handle that is alwasy passed as their first argument, generated
  239 by kadm5_init_* (to which the client specified the API version to use
  240 at run-time).
  242 In general, it is probably unsafe for a compiled function in a library
  243 to re-interpret the number and type of defined arguments at run-time
  244 since the calling conventions may not allow it; for example, a
  245 function whose first argument was a short in one version and a pointer
  246 in the next might fail if it simply typed-casted the argument.  In
  247 that case, the function would have to written to take variable
  248 arguments (i.e. use $<$stdarg.h$>$) and extract them from the stack
  249 based on the API version.  Alternatively, a separate function for each
  250 API version could be defined, and $<$kadm5/admin.h$>$ could be written
  251 to \v{\#define} the exported function name based on the value of
  254 In the current system, it turns out, that isn't necessary, and future
  255 implementors should take try to ensure that no version has semantics
  256 that will cause such problems in the future.  All the functions in
  257 KADM5 that have different arguments or results between VERSION_1 and
  258 VERSION_2 do so simply by type-casting their arguments to the
  259 appropriate version and then have separate code paths to handle each
  260 one correctly.  kadm5_get_principal, in svr_principal.c, is a good
  261 example.  In VERSION_1, it took the address of a pointer to a
  262 kadm5_principal_ent_t to fill in with a pointer to allocated memory;
  263 in VERSION_2, it takes a pointer to a structure to fill in, and a mask
  264 of which fields in that structure should be filled in.  Also, the
  265 contents of the kadm5_principal_ent_t changed slightly between the two
  266 versions.  kadm5_get_principal handles versioning as follows
  267 (following along in the source code will be helpful):
  269 \begin{enumerate}
  270 \item If VERSION_1, it saves away its entry argument (address of a
  271 pointer to a structure) and resets its value to contain the address of
  272 a locally stack-allocated entry structure; this allows most of the
  273 function to written once, in terms of VERSION_2 semantics.  If
  274 VERSION_1, it also resets its mask argument to be
  275 KADM5_PRINCIPAL_NORMAL_MASK, because that is the equivalent to
  276 VERSION_1 behavior, which was to return all the fields of the
  277 structure.
  279 \item The bulk of the function is implemented as expected for
  280 VERSION_2.
  282 \item The new fields in the VERSION_2 entry structure are assigned
  283 inside a block that is only execute if the caller specified
  284 VERSION_2.  This saves a little time for a VERSION_1 caller.
  286 \item After the entry structure is filled, the function checks again
  287 if it was called as VERSION_1.  If so, it allocates a new
  288 kadm5_principal_ent_t_v1 structure (which is conveniently defined in
  289 the header file) with malloc, copies the appropriate values from the
  290 entry structure into the VERSION_1 entry structure, and then writes
  291 the address of the newly allocated memory into address specified by
  292 the original entry argument which it had previously saved away.
  293 \end{enumerate}
  295 There is another complication involved in a function re-interpreting
  296 the number of arguments it receives at compile time---it cannot assign
  297 any value to an argument for which the client did not pass a value.
  298 For example, a VERSION_1 client only passes three arguments to
  299 kadm5_get_principal.  If the implementation of kadm5_get_principal
  300 notices that the caller is VERSION_1 and therefore assigns its fourth
  301 argument, mask, to a value that mimics the VERSION_1 behavior, it may
  302 inadvertently overwrite data on its caller's stack.  This problem can
  303 be avoided simply by using a true local variable in such cases,
  304 instead of treating an unpassed argument as a local variable.
  306 \subsection{XDR functions}
  308 The XDR functions used to encode function arguments and results must
  309 know how to encode the data for any API version.  This is important
  310 both so that all the data gets correctly transmitted and so that
  311 protocol compatibility between clients or servers using the new
  312 library but an old API version is maintained; specific, new kadmind
  313 servers should support old kadm5 clients.
  315 The signature of all XDR functions is strictly defined: they take the
  316 address of an XDR function and the address of the data object to be
  317 encoded or decoded.  It is thus impossible to provide the API version
  318 of the data object as an additional argument to an XDR function.
  319 There are two other means to convey the information, storing the API
  320 version to use as a field in the data object itself and creating
  321 separate XDR functions to handle each different version of the data
  322 object, and both of them are used in KADM5.
  324 In the client library, each kadm5 function collects its arguments into
  325 a single structure to be passed by the RPC; similarly, it expects all
  326 of the results to come back as a single structure from the RPC that it
  327 will then decode back into its constituent pieces (these are the
  328 standard ONC RPC semantics).  In order to pass versioning information
  329 to the XDR functions, each function argument and result datatype has a
  330 filed to store the API version.  For example, consider
  331 kadm5_get_principal's structures:
  332 %
  333 \begin{verbatim}
  334 struct gprinc_arg {
  335         krb5_ui_4 api_version;
  336         krb5_principal princ;
  337         long mask;
  338 };
  339 typedef struct gprinc_arg gprinc_arg;
  340 bool_t xdr_gprinc_arg();
  342 struct gprinc_ret {
  343         krb5_ui_4 api_version;
  344         kadm5_ret_t code;
  345         kadm5_principal_ent_rec rec;
  346 };
  347 typedef struct gprinc_ret gprinc_ret;
  348 bool_t xdr_gprinc_ret();
  349 \end{verbatim}
  350 %
  351 kadm5_get_principal (in client_principal.c) assigns the api_version
  352 field of the gprinc_arg to the version specified by its caller,
  353 assigns the princ field based on its arguments, and assigns the mask
  354 field from its argument if the caller specified VERSION_2.  It then
  355 calls the RPC function clnt_call, specifying the XDR functions
  356 xdr_gprinc_arg and xdr_gprinc_ret to handle the arguments and results.
  358 xdr_gprinc_arg is invoked with a pointer to the gprinc_arg structure
  359 just described.  It first encodes the api_version field; this allows
  360 the server to know what to expect.  It then encodes the krb5_principal
  361 structure and, if api_version is VERSION_2, the mask.  If api_version
  362 is not VERSION_2, it does not encode {\it anything} in place of the
  363 mask, because an old VERSION_1 server will not expect any other data
  364 to arrive on the wire there.
  366 The server performs the kadm5_get_principal call and returns its
  367 results in an XDR encoded gprinc_ret structure.  clnt_call, which has
  368 been blocking until the results arrived, invokes xdr_gprinc_ret with a
  369 pointer to the encoded data for it to decode.  xdr_gprinc_ret first
  370 decodes the api_version field, and then the code field since that is
  371 present in all versions to date.  The kadm5_principal_ent_rec presents
  372 a problem, however.  The structure does not itself contain an
  373 api_version field, but the structure is different between the two
  374 versions.  Thus, a single XDR function cannot decode both versions of
  375 the structure because it will have no way to decide which version to
  376 expect.  The solution is to have two functions,
  377 kadm5_principal_ent_rec_v1 and kadm5_principal_ent_rec, which always
  378 decode according to VERSION_1 or VERSION_2, respectively.  gprinc_ret
  379 knows which one to invoke because it has the api_version field
  380 returned by the server (which is always the same as that specified by
  381 the client in the gpring_arg).
  383 In hindsight, it probably would have been better to encode the API
  384 version of all structures directly in a version field in the structure
  385 itself; then multiple XDR functions for a single data type wouldn't be
  386 necessary, and the data objects would stand complete on their own.
  387 This can be added in a future API version if desired.
  389 \subsection{Client library functions}
  391 Just as with server library functions, client library functions must
  392 be able to interpret their arguments and provide result according to
  393 the API version specified by the caller.  Again, kadm5_get_principal
  394 (in client_principal.c) is a good example.  The gprinc_ret structure
  395 that it gets back from clnt_call contains a kadm5_principal_ent_rec or
  396 a kadm5_principal_ent_rec_v1 (the logic is simplified somewhat because
  397 the VERSION_2 structure only has new fields added on the end).  If
  398 kadm5_get_principal was invoked with VERSION_2, that structure should
  399 be copied into the pointer provided as the entry argument; if it was
  400 invoked with VERSION_1, however, the structure should be copied into
  401 allocated memory whose address is then written into the pointer
  402 provided by the entry argument.  Client library functions make this
  403 determination based on the API version specified in the provided
  404 handle, just like server library functions do.
  406 \subsection{Admin server stubs}
  408 When an RPC call arrives at the server, the RPC layer authenticates
  409 the call using the GSS-API, decodes the arguments into their
  410 single-structure form (ie: a gprinc_arg) and dispatches the call to a
  411 stub function in the server (in server_stubs.c).  The stub function
  412 first checks the caller's authorization to invoke the function and, if
  413 authorized, calls the kadm5 function corresponding to the RPC function
  414 with the arguments specified in the single-structure argument.
  416 Once again, kadm5_get_principal is a good example for the issues
  417 involved.  The contents of the gprinc_arg given to the stub
  418 (get_principal_1) depends on the API version the caller on the client
  419 side specified; that version is available to the server in the
  420 api_version field of the gprinc_arg.  When the server calls
  421 kadm5_get_principal in the server library, it must give that function
  422 an API handle that contains the API version requested by the client;
  423 otherwise the function semantics might not be correct.  One
  424 possibility would be for the server to call kadm5_init for each client
  425 request, specifing the client's API version number and thus generating
  426 an API handle with the correct version, but that would be
  427 prohibitively inefficient.  Instead, the server dips down in the
  428 server library's internal abstraction barrier, using the function
  429 new_server_handle to cons up a server handle based on the server's own
  430 global_server_handle but using the API version specified by the
  431 client.  The server then passes the newly generated handle to
  432 kadm5_get_principal, ensuring the right behavior, and creates the
  433 gprinc_ret structure in a manner similar to that described above.
  435 Although new_server_handle solves the problem of providing the server
  436 with an API handle containing the right API version number, it does
  437 not solve another problem: that a single source file, server_stubs.c,
  438 needs to be able to invoke functions with arguments appropriate for
  439 multiple API versions.  If the client specifies VERSION_1, for
  440 example, the server must invoke kadm5_get_principal with three
  441 arguments, but if the client specifies VERSION_2 the server must
  442 invoke kadm5_get_principal with four arguments.  The compiler will not
  443 allow this inconsistency.  The server defines wrapper functions in a
  444 separate source file that match the old version, and the separate
  445 source file is compiled with USE_KADM5_API_VERSION set to the old
  446 version; see kadm5_get_principal_v1 in server_glue_v1.c.  The server
  447 then calls the correct variant of kadm5_get_principal_* based on the
  448 API version and puts the return values into the gprinc_ret in a manner
  449 similar to that described above.
  451 Neither of these solutions are necessarily correct.  new_server_handle
  452 violates the server library's abstraction barrier and is at best a
  453 kludge; the server library should probably export a function to
  454 provide this behavior without violating the abstraction;
  455 alternatively, the librar should be modified so that having the server
  456 call kadm5_init for each client RPC request would not be too
  457 inefficient.  The glue functions in server_glue_v1.c really are not
  458 necessary, because the server stubs could always just pass dummy
  459 arguments for the extra arguments; after all, the glue functions pass
  460 {\it nothing} for the extra arguments, so they just end up as stack
  461 garbage anyway.
  463 Another alternative to the new_server_handle problem is to have the
  464 server always invoke server library functions at a single API version,
  465 and then have the stubs take care of converting the function arguments
  466 and results back into the form expected by the caller.  In general,
  467 however, this might require the stubs to duplicate substantial logic
  468 already present in the server library and further violate the server
  469 library's abstraction barrier.
  471 \subsection{KADM5 self-reference}
  473 Some kadm5 functions call other kadm5 functions ``on their own
  474 behalf'' to perform functionality that is necessary but that does not
  475 directly affect what the client sees.  For example,
  476 kadm5_chpass_principal has to enforce password policies; thus, it
  477 needs to call kadm5_get_principal and, if the principal has a policy,
  478 kadm5_get_policy and kadm5_modify_principal in the process of changing
  479 a principal's password.  This leads to a complication: what API handle
  480 should kadm5_chpass_principal pass to the other kadm5 functions it
  481 calls?
  483 The ``obvious,'' but wrong, answer is that it should pass the handle
  484 it was given by its caller.  The caller may provide an API handle
  485 specifying any valid API version.  Although the semantics of
  486 kadm5_chpass_principal did not change between VERSION_1 and VERSION_2,
  487 the declarations of both kadm5_get_principal and kadm5_get_policy
  488 did.  Thus, to use the caller's API handle, kadm5_chpass_principal
  489 will have to have a separate code path for each API version, even
  490 though it itself did not change bewteen versions, and duplicate a lot
  491 of logic found elsewhere in the library.
  493 Instead, each API handle contains a ``local-use handle,'' or lhandle,
  494 that kadm5 functions should use to call other kadm5 functions.  For
  495 example, the client-side library's handle structure is:
  496 %
  497 \begin{verbatim}
  498 typedef struct _kadm5_server_handle_t {
  499         krb5_ui_4       magic_number;
  500         krb5_ui_4       struct_version;
  501         krb5_ui_4       api_version;
  502         char *          cache_name;
  503         int             destroy_cache;
  504         CLIENT *        clnt;
  505         krb5_context    context;
  506         kadm5_config_params params;
  507         struct _kadm5_server_handle_t *lhandle;
  508 } kadm5_server_handle_rec, *kadm5_server_handle_t;
  509 \end{verbatim}
  510 %
  511 The lhandle field is allocated automatically when the handle is
  512 created.  All of the fields of the API handle that are accessed
  513 outside kadm5_init are also duplicated in the lhandle; however, the
  514 api_version field of the lhandle is always set to a {\it constant}
  515 value, regardless of the API version specified by the caller to
  516 kadm5_init.  In the current implementation, the lhandle's api_version
  517 is always VERSION_2.
  519 By passing the caller's handle's lhandle to recursively called kadm5
  520 functions, a kadm5 function is assured of invoking the second kadm5
  521 function with a known API version.  Additionally, the lhandle's
  522 lhandle field points back to the lhandle, in case kadm5 functions call
  523 themselves more than one level deep; handle$->$lhandle always points
  524 to the same lhandle, no matter how many times the indirection is
  525 performed.
  527 This scheme might break down if a kadm5 function has to call another
  528 kadm5 function to perform operations that they client will see and for
  529 its own benefit, since the semantics of the recursively-called kadm5
  530 function may depend on the API version specified and the client may be
  531 depending on a particular version's behavior.  Future implementators
  532 should avoid creating a situation in which this is possible.
  534 \section{Server Main}
  536 The admin server starts by trapping all fatal signals and directing
  537 them to a cleanup-and-exit function.  It then creates and exports the
  538 RPC interface and enters its main loop.
  540 The main loop dispatches all incoming requests to the RPC mechanism.
  541 In a previous version, after 15 seconds of inactivity, the server
  542 closed all open databases; each database was be automatically reopened
  543 by the API function implementations as necessary.  That behavior
  544 existed to protect against loss of written data before the process
  545 exited.  The current database libraries write all changes out to disk
  546 immediately, however, so this behavior is no longer required or
  547 performed.
  549 \section{Remote Procedure Calls}
  551 The RPC for the Admin system will be based on ONC RPC.  ONC RPC is
  552 used because it is a well-known, portable RPC mechanism.  The
  553 underlying external data representation (xdr) mechanisms for wire
  554 encapsulation are well-known and extensible.  Authentication to the
  555 admin server and encryption of all RPC functional arguments and
  556 results are be handled via the AUTH_GSSAPI authentication flavor of
  557 ONC RPC.
  559 \section{Database Record Types}
  560 \label{sec:db-types}
  562 \subsection{Admin Principal, osa_princ_ent_t}
  564 The admin principal database stores records of the type
  565 osa_princ_ent_t (declared in $<$kadm5/adb.h$>$), which is the
  566 subset of the kadm5_principal_ent_t structure that is not stored
  567 in the Kerberos database plus the necessary bookkeeping information.
  568 The records are keyed by the ASCII representation of the principal's
  569 name, including the trailing NULL.
  571 \begin{verbatim}
  572 typedef struct _osa_pw_hist_t {
  573      int n_key_data;
  574      krb5_key_data *key_data;
  575 } osa_pw_hist_ent, *osa_pw_hist_t;
  577 typedef struct _osa_princ_ent_t {
  578         char * policy;
  579         u_int32 aux_attributes;
  581         unsigned int old_key_len;
  582         unsigned int old_key_next;
  583         krb5_kvno admin_history_kvno;
  584         osa_pw_hist_ent *old_keys;
  587         u_int32 num_old_keys;
  588         u_int32 next_old_key;
  589         krb5_kvno admin_history_kvno;
  590         osa_pw_hist_ent *old_keys;
  591 } osa_princ_ent_rec, *osa_princ_ent_t;
  592 \end{verbatim}
  594 The fields that are different from kadm5_principal_ent_t are:
  596 \begin{description}
  597 \item[num_old_keys] The number of previous keys in the old_keys array.
  598 This value must be 0 $\le$ num_old_keys $<$ pw_history_num.
  600 \item[old_key_next] The index into old_keys where the next key should
  601 be inserted.  This value must be 0 $\le$ old_key_next $\le$
  602 num_old_keys.
  604 \item[admin_history_kvno] The key version number of the kadmin/history
  605 principal's key used to encrypt the values in old_keys.  If the server
  606 library finds that kadmin/history's kvno is different from the value
  607 in this field, it returns KADM5_BAD_HIST_KEY.
  609 \item[old_keys] The array of the principal's previous passwords, each
  610 encrypted in the kadmin/history key.  There are num_old_keys
  611 elements.  Each ``password'' in the array is itself an array of
  612 n_key_data krb5_key_data structures, one for each keysalt type the
  613 password was encoded in.
  614 \end{description}
  616 \subsection{Policy, osa_policy_ent_t}
  618 The policy database stores records of the type osa_policy_ent_t
  619 (declared in $<$kadm5/adb.h$>$) , which is all of
  620 kadm5_policy_ent_t plus necessary bookkeeping information.  The
  621 records are keyed by the policy name.
  623 \begin{verbatim}
  624 typedef struct _osa_policy_ent_t {
  625         char *policy;
  627         u_int32 pw_min_life;
  628         u_int32 pw_max_life;
  629         u_int32 pw_min_length;
  630         u_int32 pw_min_classes;
  631         u_int32 pw_history_num;
  633         u_int32 refcnt;
  634 } osa_policy_ent_rec, *osa_policy_ent_t;
  635 \end{verbatim}
  637 \subsection{Kerberos, krb5_db_entry}
  639 The Kerberos database stores records of type krb5_db_entry, which is
  640 defined in the $<$k5-int.h$>$ header file.  The semantics of each
  641 field are defined in the libkdb functional specification.
  643 \section{Database Access Methods}
  645 \subsection{Principal and Policy Databases}
  647 This section describes the database abstraction used for the admin
  648 policy database; the admin principal database used to be treated in
  649 the same manner but is now handled more directly as krb5_tl_data;
  650 thus, nothing in this section applies to it any more.  Since both
  651 databases export equivalent functionality, the API is only described
  652 once.  The character T is used to represent both ``princ'' and
  653 ``policy''. The location of the principal database is defined by the
  654 configuration parameters given to any of the kadm5_init functions in
  655 the server library.
  657 Note that this is {\it only} a database abstraction.  All functional
  658 intelligence, such as maintaining policy reference counts or sanity
  659 checking, must be implemented above this layer.
  661 Prototypes for the osa functions are supplied in
  662 $<$kadm5/adb.h$>$. The routines are defined in libkadm5srv.a. They
  663 require linking with the Berkely DB library.
  665 \subsubsection{Error codes}
  667 The database routines use com_err for error codes.  The error code
  668 table name is ``adb'' and the offsets are the same as the order
  669 presented here. The error table header file is
  670 $<$kadm5/adb_err.h$>$. Callers of the OSA routines should first call
  671 init_adb_err_tbl() to initialize the database table.
  673 \begin{description}
  674 \item[OSA_ADB_OK] Operation successful.
  675 \item[OSA_ADB_FAILURE] General failure.
  676 \item[OSA_ADB_DUP] Operation would create a duplicate database entry.
  677 \item[OSA_ADB_NOENT] Named entry not in database.
  678 \item[OSA_ADB_BAD_PRINC] The krb5_principal structure is invalid.
  679 \item[OSA_ADB_BAD_POLICY] The specified policy name is invalid.
  680 \item[OSA_ADB_XDR_FAILURE] The principal or policy structure cannot be
  681 encoded for storage.
  682 \item[OSA_ADB_BADLOCKMODE] Bad lock mode specified.
  683 \item[OSA_ADB_CANTLOCK_DB] Cannot lock database, presumably because it
  684 is already locked.
  685 \item[OSA_ADB_NOTLOCKED] Internal error, database not locked when
  686 unlock is called.
  687 \item[OSA_ADB_NOLOCKFILE] KADM5 administration database lock file missing.
  688 \end{description}
  690 Database functions can also return system errors.  Unless otherwise
  691 specified, database functions return OSA_ADB_OK.
  693 \subsubsection{Locking}
  695 All of the osa_adb functions except open and close lock and unlock the
  696 database to prevent concurrency collisions.  The overall locking
  697 algorithm is as follows:
  699 \begin{enumerate}
  700 \item osa_adb_open_T calls osa_adb_init_db to allocate the osa_adb_T_t
  701 structure and open the locking file for further use.
  703 \item Each osa_adb functions locks the locking file and opens the
  704 appropriate database with osa_adb_open_and_lock, performs its action,
  705 and then closes the database and unlocks the locking file with
  706 osa_adb_close_and_unlock.
  708 \item osa_adb_close_T calls osa_adb_fini_db to close the locking file
  709 and deallocate the db structure.
  710 \end{enumerate}
  712 Functions which modify the database acquire an exclusive lock, others
  713 acqure a shared lock.  osa_adb_iter_T acquires an exclusive lock for
  714 safety but as stated below consequences of modifying the database in
  715 the iteration function are undefined.
  717 \subsubsection{Function descriptions}
  719 \begin{verbatim}
  720 osa_adb_ret_t osa_adb_create_T_db(kadm5_config_params *params)
  721 \end{verbatim}
  722 %
  723 Create the database and lockfile specified in params.  The database
  724 must not already exist, or EEXIST is returned.  The lock file is only
  725 created after the database file has been created successfully.
  727 \begin{verbatim}
  728 osa_adb_ret_t osa_adb_rename_T_db(kadm5_config_params *fromparams,
  729                   kadm5_config_params *toparams)
  730 \end{verbatim}
  731 %
  732 Rename the database named by fromparams to that named by toparams.
  733 The fromparams database must already exist; the toparams database may
  734 exist or not.  When the function returns, the database named by
  735 fromparams no longer exists, and toparams has been overwritten with
  736 fromparams.  This function acquires a permanent lock on both databases
  737 for the duration of its operation, so a failure is likely to leave the
  738 databases unusable.
  740 \begin{verbatim}
  741 osa_adb_ret_t osa_adb_destroy_policy_db(kadm5_config_params *params)
  742 \end{verbatim}
  743 %
  744 Destroy the database named by params.  The database file and lock file
  745 are deleted.
  747 \begin{verbatim}
  748 osa_adb_ret_t
  749 osa_adb_open_T(osa_adb_T_t *db, char *filename);
  750 \end{verbatim}
  751 %
  752 Open the database named filename.  Returns OSA_ADB_NOLOCKFILE if the
  753 database does not exist or if the lock file is missing.  The database
  754 is not actually opened in the operating-system file sense until a lock
  755 is acquire.
  757 \begin{verbatim}
  758 osa_adb_ret_t
  759 osa_adb_close_T(osa_adb_T_t db);
  760 \end{verbatim}
  761 %
  762 Release all shared or exclusive locks (on BOTH databases, since they
  763 use the same lock file) and close the database.
  765 It is an error to exit while a permanent lock is held;
  766 OSA_ADB_NOLOCKFILE is returned in this case.
  768 \begin{verbatim}
  769 osa_adb_ret_t osa_adb_get_lock(osa_adb_T_t db, int mode)
  770 \end{verbatim}
  772 Acquire a lock on the administration databases; note that both
  773 databases are locked simultaneously by a single call.  The mode
  774 argument can be OSA_ADB_SHARED, OSA_ADB_EXCLUSIVE, or
  775 OSA_ADB_PERMANENT.  The first two and the third are really disjoint
  776 locking semantics and should not be interleaved.
  778 Shared and exclusive locks have the usual semantics, and a program can
  779 upgrade a shared lock to an exclusive lock by calling the function
  780 again.  A reference count of open locks is maintained by this function
  781 and osa_adb_release_lock so the functions can be called multiple
  782 times; the actual lock is not released until the final
  783 osa_adb_release_lock.  Note, however, that once a lock is upgraded
  784 from shared to exclusive, or from exclusive to permanent, it is not
  785 downgraded again until released completely.  In other words,
  786 get_lock(SHARED), get_lock(EXCLUSIVE), release_lock() leaves the
  787 process with an exclusive lock with a reference count of one.  An
  788 attempt to get a shared or exclusive lock that conflicts with another
  789 process results in the OSA_ADB_CANLOCK_DB error code.
  791 This function and osa_adb_release_lock are called automatically as
  792 needed by all other osa_adb functions to acquire shared and exclusive
  793 locks and so are not normally needed.  They can be used explicitly by
  794 a program that wants to perform multiple osa_adb functions within the
  795 context of a single lock.
  797 Acquiring an OSA_ADB_PERMANENT lock is different.  A permanent lock
  798 consists of first acquiring an exclusive lock and then {\it deleting
  799 the lock file}.  Any subsequent attempt to acquire a lock by a
  800 different process will fail with OSA_ADB_NOLOCKFILE instead of
  801 OSA_ADB_CANTLOCK_DB (attempts in the same process will ``succeed''
  802 because only the reference count gets incremented).  The lock file is
  803 recreated by osa_adb_release_lock when the last pending lock is released.
  805 The purpose of a permanent lock is to absolutely ensure that the
  806 database remain locked during non-atomic operations.  If the locking
  807 process dies while holding a permanent lock, all subsequent osa_adb
  808 operations will fail, even through a system reboot.  This is useful,
  809 for example, for ovsec_adm_import which creates both new database
  810 files in a temporary location and renames them into place.  If both
  811 renames do not fully complete the database will probably be
  812 inconsistent and everything should stop working until an administrator
  813 can clean it up.
  815 \begin{verbatim}
  816 osa_adb_ret_t osa_adb_release_lock(osa_adb_T_t db)
  817 \end{verbatim}
  819 Releases a shared, exclusive, or permanent lock acquired with
  820 osa_adb_get_lock, or just decrements the reference count if multiple
  821 locks are held.  When a permanent lock is released, the lock file is
  822 re-created.
  824 All of a process' shared or exclusive database locks are released when
  825 the process terminates.  A permanent lock is {\it not} released when
  826 the process exits (although the exclusive lock it begins with
  827 obviously is).
  829 \begin{verbatim}
  830 osa_adb_ret_t
  831 osa_adb_create_T(osa_adb_T_t db, osa_T_ent_t entry);
  832 \end{verbatim}
  833 %
  834 Adds the entry to the database.  All fields are defined.  Returns
  835 OSA_ADB_DUP if it already exists.
  837 \begin{verbatim}
  838 osa_adb_ret_t
  839 osa_adb_destroy_T(osa_adb_T_t db, osa_T_t name);
  840 \end{verbatim}
  842 Removes the named entry from the database.  Returns OSA_ADB_NOENT if
  843 it does not exist.
  845 \begin{verbatim}
  846 osa_adb_ret_t
  847 osa_adb_get_T(osa_adb_T_t db, osa_T_t name,
  848         osa_princ_ent_t *entry); 
  849 \end{verbatim}
  851 Looks up the named entry in the db, and returns it in *entry in
  852 allocated storage that must be freed with osa_adb_free_T.  Returns
  853 OSA_ADB_NOENT if name does not exist, OSA_ADB_MEM if memory cannot be
  854 allocated.
  856 \begin{verbatim}
  857 osa_adb_ret_t
  858 osadb_adb_put_T(osa_adb_T_t db, osa_T_ent_t entry);
  859 \end{verbatim}
  861 Modifies the existing entry named in entry.  All fields must be filled
  862 in.  Returns OSA_DB_NOENT if the named entry does not exist.  Note
  863 that this cannot be used to rename an entry; rename is implemented by
  864 deleting the old name and creating the new one (NOT ATOMIC!).
  866 \begin{verbatim}
  867 void osa_adb_free_T(osa_T_ent_t);
  868 \end{verbatim}
  870 Frees the memory associated with an osa_T_ent_t allocated by
  871 osa_adb_get_T.
  873 \begin{verbatim}
  874 typedef osa_adb_ret_t (*osa_adb_iter_T_func)(void *data,
  875                                     osa_T_ent_t entry);
  877 osa_adb_ret_t osa_adb_iter_T(osa_adb_T_t db, osa_adb_iter_T_func func, 
  878                     void *data);
  879 \end{verbatim}
  881 Iterates over every entry in the database.  For each entry ent in the
  882 database db, the function (*func)(data, ent) is called.  If func
  883 returns an error code, osa_adb_iter_T returns an error code.  If all
  884 invokations of func return OSA_ADB_OK, osa_adb_iter_T returns
  885 OSA_ADB_OK.  The function func is permitted to access the database,
  886 but the consequences of modifying the database during the iteration
  887 are undefined.
  889 \subsection{Kerberos Database}
  891 Kerberos uses the libkdb interface to store krb5_db_entry records.  It
  892 can be accessed and modified in parallel with the Kerberos server,
  893 using functions that are defined inside the KDC and the libkdb.a.  The
  894 libkdb interface is defined in the libkdb functional specifications.
  896 \subsubsection{Initialization and Key Access}
  898 Keys stored in the Kerberos database are encrypted in the Kerberos
  899 master key.  The admin server will therefore have to acquire the key
  900 before it can perform any key-changing operations, and will have to
  901 decrypt and encrypt the keys retrieved from and placed into the
  902 database via krb5_db_get_principal and _put_principal.  This section
  903 describes the internal admin server API that will be used to perform
  904 these functions.
  906 \begin{verbatim}
  907 krb5_principal master_princ;
  908 krb5_encrypt_block master_encblock;
  909 krb5_keyblock master_keyblock;
  911 void kdc_init_master()
  912 \end{verbatim}
  914 kdc_init_master opens the database and acquires the master key.  It
  915 also sets the global variables master_princ, master_encblock, and
  916 master_keyblock:
  918 \begin{itemize}
  919 \item master_princ is set to the name of the Kerberos master principal
  920 (\v{K/M@REALM}).
  922 \item master_encblock is something I have no idea about.
  924 \item master_keyblock is the Kerberos master key
  925 \end{itemize}
  927 \begin{verbatim}
  928 krb5_error_code kdb_get_entry_and_key(krb5_principal principal,
  929                                       krb5_db_entry *entry,
  930                                       krb5_keyblock *key)
  931 \end{verbatim}
  933 kdb_get_entry_and_key retrieves the named principal's entry from the
  934 database in entry, and decrypts its key into key.  The caller must
  935 free entry with krb5_dbm_db_free_principal and free key-$>$contents with
  936 free.\footnote{The caller should also \v{memset(key-$>$contents, 0,
  937 key-$>$length)}.  There should be a function krb5_free_keyblock_contents
  938 for this, but there is not.}
  940 \begin{verbatim}
  941 krb5_error_code kdb_put_entry_pw(krb5_db_entry *entry, char *pw)
  942 \end{verbatim}
  944 kdb_put_entry_pw stores entry in the database.  All the entry values
  945 must already be set; this function does not change any of them except
  946 the key.  pw, the NULL-terminated password string, is converted to a
  947 key using string-to-key with the salt type specified in
  948 entry-$>$salt_type.\footnote{The salt_type should be set based on the
  949 command line arguments to the kadmin server (see the ``Command Line''
  950 section of the functional specification).}
  952 \section{Admin Principal and Policy Database Implementation}
  954 The admin principal and policy databases will each be stored in a
  955 single hash table, implemented by the Berkeley 4.4BSD db library.
  956 Each record will consist of an entire osa_T_ent_t.  The key into the
  957 hash table is the entry name (for principals, the ASCII representation
  958 of the name).  The value is the T entry structure.  Since the key and
  959 data must be self-contained, with no pointers, the Sun xdr mechanisms
  960 will be used to marshal and unmarshal data in the database.
  962 The server in the first release will be single-threaded in that a
  963 request will run to completion (or error) before the next will run,
  964 but multiple connections will be allowed simultaneously.
  966 \section{ACLs, acl_check}
  968 The ACL mechanism described in the ``Authorization ACLs'' section of
  969 the functional specifications will be implemented by the acl_check
  970 function.
  972 \begin{verbatim}
  973 enum access_t {
  974         ACCESS_DENIED = 0,
  975         ACCESS_OK = 1,
  976 };
  978 enum access_t acl_check(krb5_principal princ, char *priv);
  979 \end{verbatim}
  981 The priv argument must be one of ``get'', ``add'', ``delete'', or
  982 ``modify''.  acl_check returns 1 if the principal princ has the named
  983 privilege, 0 if it does not.
  985 \section{Function Details}
  987 This section discusses specific design issues for Admin API functions
  988 that are not addresed by the functional specifications.
  990 \subsection{kadm5_create_principal}
  992 If the named principal exists in either the Kerberos or admin
  993 principal database, but not both, return KADM5_BAD_DB.
  995 The principal's initial key is not stored in the key history array at
  996 creation time.
  998 \subsection{kadm5_delete_principal}
 1000 If the named principal exists in either the Kerberos or admin
 1001 principal database, but not both, return KADM5_BAD_DB.
 1003 \subsection{kadm5_modify_principal}
 1005 If the named principal exists in either the Kerberos or admin
 1006 principal database, but not both, return KADM5_BAD_DB.
 1008 If pw_history_num changes and the new value $n$ is smaller than the
 1009 current value of num_old_keys, old_keys should end up with the $n$
 1010 most recent keys; these are found by counting backwards $n$ elements
 1011 in old_keys from old_key_next.  old_key_nexts should then be reset to
 1012 0, the oldest of the saved keys, and num_old_keys set to $n$, the
 1013 new actual number of old keys in the array.  
 1015 \subsection{kadm5_chpass_principal, randkey_principal}
 1017 The algorithm for determining whether a password is in the principal's
 1018 key history is complicated by the use of the kadmin/history \k{h}
 1019 encrypting key.  
 1021 \begin{enumerate}
 1022 \item For kadm5_chpass_principal, convert the password to a key
 1023 using string-to-key and the salt method specified by the command line
 1024 arguments.
 1026 \item If the POLICY bit is set and pw_history_num is not zero, check
 1027 if the new key is in the history.
 1028 \begin{enumerate}
 1029 \item Retrieve the principal's current key and decrypt it with \k{M}.
 1030 If it is the same as the new key, return KADM5_PASS_REUSE.
 1031 \item Retrieve the kadmin/history key \k{h} and decrypt it with \k{M}.
 1032 \item Encrypt the principal's new key in \k{h}.
 1033 \item If the principal's new key encrypted in \k{h} is in old_keys,
 1034 return KADM5_PASS_REUSE.
 1035 \item Encrypt the principal's current key in \k{h} and store it in
 1036 old_keys.
 1037 \item Erase the memory containing \k{h}.
 1038 \end{enumerate}
 1040 \item Encrypt the principal's new key in \k{M} and store it in the
 1041 database.
 1042 \item Erase the memory containing \k{M}.
 1043 \end{enumerate}
 1045 To store the an encrypted key in old_keys, insert it as the
 1046 old_key_next element of old_keys, and increment old_key_next by one
 1047 modulo pw_history_num.
 1049 \subsection{kadm5_get_principal}
 1051 If the named principal exists in either the Kerberos or admin
 1052 principal database, but not both, return KADM5_BAD_DB.
 1054 \end{document}