xref: /freebsd/crypto/heimdal/doc/doxyout/krb5/html/krb5_introduction.html (revision 6a068746777241722b2b32c5d0bc443a2a64d80b)
1ae771770SStanislav Sedov<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2ae771770SStanislav Sedov<html><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
3ae771770SStanislav Sedov<title>HeimdalKerberos5library: Introduction to the Kerberos 5 API</title>
4ae771770SStanislav Sedov<link href="doxygen.css" rel="stylesheet" type="text/css">
5ae771770SStanislav Sedov<link href="tabs.css" rel="stylesheet" type="text/css">
6ae771770SStanislav Sedov</head><body>
7ae771770SStanislav Sedov<p>
8ae771770SStanislav Sedov<a href="http://www.h5l.org/"><img src="http://www.h5l.org/keyhole-heimdal.png" alt="keyhole logo"/></a>
9ae771770SStanislav Sedov</p>
10ae771770SStanislav Sedov<!-- end of header marker -->
11ae771770SStanislav Sedov<!-- Generated by Doxygen 1.5.6 -->
12ae771770SStanislav Sedov<div class="navigation" id="top">
13ae771770SStanislav Sedov  <div class="tabs">
14ae771770SStanislav Sedov    <ul>
15ae771770SStanislav Sedov      <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
16ae771770SStanislav Sedov      <li><a href="pages.html"><span>Related&nbsp;Pages</span></a></li>
17ae771770SStanislav Sedov      <li><a href="modules.html"><span>Modules</span></a></li>
18ae771770SStanislav Sedov      <li><a href="annotated.html"><span>Data&nbsp;Structures</span></a></li>
19ae771770SStanislav Sedov    </ul>
20ae771770SStanislav Sedov  </div>
21ae771770SStanislav Sedov</div>
22ae771770SStanislav Sedov<div class="contents">
23ae771770SStanislav Sedov<h1><a class="anchor" name="krb5_introduction">Introduction to the Kerberos 5 API </a></h1><h2><a class="anchor" name="api_overview">
24ae771770SStanislav SedovKerberos 5 API Overview</a></h2>
25ae771770SStanislav SedovAll functions are documented in manual pages. This section tries to give an overview of the major components used in Kerberos library, and point to where to look for a specific function.<h3><a class="anchor" name="intro_krb5_context">
26ae771770SStanislav SedovKerberos context</a></h3>
27ae771770SStanislav SedovA kerberos context (krb5_context) holds all per thread state. All global variables that are context specific are stored in this structure, including default encryption types, credential cache (for example, a ticket file), and default realms.<p>
28ae771770SStanislav SedovThe internals of the structure should never be accessed directly, functions exist for extracting information.<p>
29ae771770SStanislav SedovSee the manual page for <a class="el" href="group__krb5.html#gbd94206e186c58a093975424a4a567a8">krb5_init_context()</a> how to create a context and module <a class="el" href="group__krb5.html">Heimdal Kerberos 5 library</a> for more information about the functions.<h3><a class="anchor" name="intro_krb5_auth_context">
30ae771770SStanislav SedovKerberos authentication context</a></h3>
31ae771770SStanislav SedovKerberos authentication context (krb5_auth_context) holds all context related to an authenticated connection, in a similar way to the kerberos context that holds the context for the thread or process.<p>
32ae771770SStanislav SedovThe krb5_auth_context is used by various functions that are directly related to authentication between the server/client. Example of data that this structure contains are various flags, addresses of client and server, port numbers, keyblocks (and subkeys), sequence numbers, replay cache, and checksum types.<h3><a class="anchor" name="intro_krb5_principal">
33ae771770SStanislav SedovKerberos principal</a></h3>
34ae771770SStanislav SedovThe Kerberos principal is the structure that identifies a user or service in Kerberos. The structure that holds the principal is the krb5_principal. There are function to extract the realm and elements of the principal, but most applications have no reason to inspect the content of the structure.<p>
35ae771770SStanislav SedovThe are several ways to create a principal (with different degree of portability), and one way to free it.<p>
36ae771770SStanislav SedovSee also the page <a class="el" href="krb5_principal_intro.html">The principal handing functions.</a> for more information and also module <a class="el" href="group__krb5__principal.html">Heimdal Kerberos 5 principal functions</a>.<h3><a class="anchor" name="intro_krb5_ccache">
37ae771770SStanislav SedovCredential cache</a></h3>
38ae771770SStanislav SedovA credential cache holds the tickets for a user. A given user can have several credential caches, one for each realm where the user have the initial tickets (the first krbtgt).<p>
39ae771770SStanislav SedovThe credential cache data can be stored internally in different way, each of them for different proposes. File credential (FILE) caches and processes based (KCM) caches are for permanent storage. While memory caches (MEMORY) are local caches to the local process.<p>
40ae771770SStanislav SedovCaches are opened with <a class="el" href="group__krb5__ccache.html#ge8ab9d6f4af5710dab860f2806a7d13b">krb5_cc_resolve()</a> or created with <a class="el" href="group__krb5__ccache.html#g86c0f70d0c2b5de2d876edf4b693b5b9">krb5_cc_new_unique()</a>.<p>
41ae771770SStanislav SedovIf the cache needs to be opened again (using <a class="el" href="group__krb5__ccache.html#ge8ab9d6f4af5710dab860f2806a7d13b">krb5_cc_resolve()</a>) <a class="el" href="group__krb5__ccache.html#gebc0dd2a77529c05fb49e27235da7017">krb5_cc_close()</a> will close the handle, but not the remove the cache. <a class="el" href="group__krb5__ccache.html#g3115bcccd71594374831caa9a07b1290">krb5_cc_destroy()</a> will zero out the cache, remove the cache so it can no longer be referenced.<p>
42ae771770SStanislav SedovSee also <a class="el" href="krb5_ccache_intro.html">The credential cache functions</a> and <a class="el" href="group__krb5__ccache.html">Heimdal Kerberos 5 credential cache functions</a> .<h3><a class="anchor" name="intro_krb5_error_code">
43ae771770SStanislav SedovKerberos errors</a></h3>
44ae771770SStanislav SedovKerberos errors are based on the com_err library. All error codes are 32-bit signed numbers, the first 24 bits define what subsystem the error originates from, and last 8 bits are 255 error codes within the library. Each error code have fixed string associated with it. For example, the error-code -1765328383 have the symbolic name KRB5KDC_ERR_NAME_EXP, and associated error string ``Client's entry in database has expired''.<p>
45ae771770SStanislav SedovThis is a great improvement compared to just getting one of the unix error-codes back. However, Heimdal have an extention to pass back customised errors messages. Instead of getting ``Key table entry not found'', the user might back ``failed to find host/host.example.com@EXAMLE.COM(kvno 3) in keytab /etc/krb5.keytab (des-cbc-crc)''. This improves the chance that the user find the cause of the error so you should use the customised error message whenever it's available.<p>
46ae771770SStanislav SedovSee also module <a class="el" href="group__krb5__error.html">Heimdal Kerberos 5 error reporting functions</a> .<h3><a class="anchor" name="intro_krb5_keytab">
47ae771770SStanislav SedovKeytab management</a></h3>
48ae771770SStanislav SedovA keytab is a storage for locally stored keys. Heimdal includes keytab support for Kerberos 5 keytabs, Kerberos 4 srvtab, AFS-KeyFile's, and for storing keys in memory.<p>
49ae771770SStanislav SedovKeytabs are used for servers and long-running services.<p>
50ae771770SStanislav SedovSee also <a class="el" href="krb5_keytab_intro.html">The keytab handing functions</a> and <a class="el" href="group__krb5__keytab.html">Heimdal Kerberos 5 keytab handling functions</a> .<h3><a class="anchor" name="intro_krb5_crypto">
51ae771770SStanislav SedovKerberos crypto</a></h3>
52ae771770SStanislav SedovHeimdal includes a implementation of the Kerberos crypto framework, all crypto operations. To create a crypto context call <a class="el" href="group__krb5__crypto.html#gd7003a8a81cef633cc0a2cc07c93dd32">krb5_crypto_init()</a>.<p>
53ae771770SStanislav SedovSee also module <a class="el" href="group__krb5__crypto.html">Heimdal Kerberos 5 cryptography functions</a> .<h2><a class="anchor" name="kerberos5_client">
54ae771770SStanislav SedovWalkthrough of a sample Kerberos 5 client</a></h2>
55ae771770SStanislav SedovThis example contains parts of a sample TCP Kerberos 5 clients, if you want a real working client, please look in appl/test directory in the Heimdal distribution.<p>
56ae771770SStanislav SedovAll Kerberos error-codes that are returned from kerberos functions in this program are passed to krb5_err, that will print a descriptive text of the error code and exit. Graphical programs can convert error-code to a human readable error-string with the krb5_get_error_message() function.<p>
57ae771770SStanislav SedovNote that you should not use any Kerberos function before <a class="el" href="group__krb5.html#gbd94206e186c58a093975424a4a567a8">krb5_init_context()</a> have completed successfully. That is the reason err() is used when <a class="el" href="group__krb5.html#gbd94206e186c58a093975424a4a567a8">krb5_init_context()</a> fails.<p>
58ae771770SStanislav SedovFirst the client needs to call krb5_init_context to initialise the Kerberos 5 library. This is only needed once per thread in the program. If the function returns a non-zero value it indicates that either the Kerberos implementation is failing or it's disabled on this host.<p>
59ae771770SStanislav Sedov<div class="fragment"><pre class="fragment"><span class="preprocessor"> #include &lt;krb5.h&gt;</span>
60ae771770SStanislav Sedov
61ae771770SStanislav Sedov <span class="keywordtype">int</span>
62ae771770SStanislav Sedov main(<span class="keywordtype">int</span> argc, <span class="keywordtype">char</span> **argv)
63ae771770SStanislav Sedov {
64ae771770SStanislav Sedov         krb5_context context;
65ae771770SStanislav Sedov
66ae771770SStanislav Sedov         <span class="keywordflow">if</span> (<a class="code" href="group__krb5.html#gbd94206e186c58a093975424a4a567a8">krb5_init_context</a>(&amp;context))
67ae771770SStanislav Sedov                 errx (1, <span class="stringliteral">"krb5_context"</span>);
68ae771770SStanislav Sedov</pre></div><p>
69ae771770SStanislav SedovNow the client wants to connect to the host at the other end. The preferred way of doing this is using getaddrinfo (for operating system that have this function implemented), since getaddrinfo is neutral to the address type and can use any protocol that is available.<p>
70ae771770SStanislav Sedov<div class="fragment"><pre class="fragment">         <span class="keyword">struct </span>addrinfo *ai, *a;
71ae771770SStanislav Sedov         <span class="keyword">struct </span>addrinfo hints;
72ae771770SStanislav Sedov         <span class="keywordtype">int</span> error;
73ae771770SStanislav Sedov
74ae771770SStanislav Sedov         memset (&amp;hints, 0, <span class="keyword">sizeof</span>(hints));
75ae771770SStanislav Sedov         hints.ai_socktype = SOCK_STREAM;
76ae771770SStanislav Sedov         hints.ai_protocol = IPPROTO_TCP;
77ae771770SStanislav Sedov
78ae771770SStanislav Sedov         error = getaddrinfo (hostname, <span class="stringliteral">"pop3"</span>, &amp;hints, &amp;ai);
79ae771770SStanislav Sedov         <span class="keywordflow">if</span> (error)
80ae771770SStanislav Sedov                 errx (1, <span class="stringliteral">"%s: %s"</span>, hostname, gai_strerror(error));
81ae771770SStanislav Sedov
82ae771770SStanislav Sedov         <span class="keywordflow">for</span> (a = ai; a != NULL; a = a-&gt;ai_next) {
83ae771770SStanislav Sedov                 <span class="keywordtype">int</span> s;
84ae771770SStanislav Sedov
85ae771770SStanislav Sedov                 s = socket (a-&gt;ai_family, a-&gt;ai_socktype, a-&gt;ai_protocol);
86ae771770SStanislav Sedov                 <span class="keywordflow">if</span> (s &lt; 0)
87ae771770SStanislav Sedov                         <span class="keywordflow">continue</span>;
88ae771770SStanislav Sedov                 <span class="keywordflow">if</span> (connect (s, a-&gt;ai_addr, a-&gt;ai_addrlen) &lt; 0) {
89ae771770SStanislav Sedov                         warn (<span class="stringliteral">"connect(%s)"</span>, hostname);
90ae771770SStanislav Sedov                             close (s);
91ae771770SStanislav Sedov                             <span class="keywordflow">continue</span>;
92ae771770SStanislav Sedov                 }
93ae771770SStanislav Sedov                 freeaddrinfo (ai);
94ae771770SStanislav Sedov                 ai = NULL;
95ae771770SStanislav Sedov         }
96ae771770SStanislav Sedov         <span class="keywordflow">if</span> (ai) {
97ae771770SStanislav Sedov                     freeaddrinfo (ai);
98ae771770SStanislav Sedov                     errx (<span class="stringliteral">"failed to contact %s"</span>, hostname);
99ae771770SStanislav Sedov         }
100ae771770SStanislav Sedov</pre></div><p>
101ae771770SStanislav SedovBefore authenticating, an authentication context needs to be created. This context keeps all information for one (to be) authenticated connection (see krb5_auth_context).<p>
102ae771770SStanislav Sedov<div class="fragment"><pre class="fragment">         status = krb5_auth_con_init (context, &amp;auth_context);
103ae771770SStanislav Sedov         <span class="keywordflow">if</span> (status)
104ae771770SStanislav Sedov                 krb5_err (context, 1, status, <span class="stringliteral">"krb5_auth_con_init"</span>);
105ae771770SStanislav Sedov</pre></div><p>
106ae771770SStanislav SedovFor setting the address in the authentication there is a help function krb5_auth_con_setaddrs_from_fd() that does everything that is needed when given a connected file descriptor to the socket.<p>
107ae771770SStanislav Sedov<div class="fragment"><pre class="fragment">         status = krb5_auth_con_setaddrs_from_fd (context,
108ae771770SStanislav Sedov                                                  auth_context,
109ae771770SStanislav Sedov                                                  &amp;sock);
110ae771770SStanislav Sedov         <span class="keywordflow">if</span> (status)
111ae771770SStanislav Sedov                 krb5_err (context, 1, status,
112ae771770SStanislav Sedov                           <span class="stringliteral">"krb5_auth_con_setaddrs_from_fd"</span>);
113ae771770SStanislav Sedov</pre></div><p>
114ae771770SStanislav SedovThe next step is to build a server principal for the service we want to connect to. (See also <a class="el" href="group__krb5__principal.html#g8be0f5000da6ee0d4bd5dcaf3cb01d08">krb5_sname_to_principal()</a>.)<p>
115ae771770SStanislav Sedov<div class="fragment"><pre class="fragment">         status = <a class="code" href="group__krb5__principal.html#g8be0f5000da6ee0d4bd5dcaf3cb01d08">krb5_sname_to_principal</a> (context,
116ae771770SStanislav Sedov                                           hostname,
117ae771770SStanislav Sedov                                           service,
118ae771770SStanislav Sedov                                           KRB5_NT_SRV_HST,
119ae771770SStanislav Sedov                                           &amp;server);
120ae771770SStanislav Sedov         <span class="keywordflow">if</span> (status)
121ae771770SStanislav Sedov                 krb5_err (context, 1, status, <span class="stringliteral">"krb5_sname_to_principal"</span>);
122ae771770SStanislav Sedov</pre></div><p>
123ae771770SStanislav SedovThe client principal is not passed to krb5_sendauth() function, this causes the krb5_sendauth() function to try to figure it out itself.<p>
124ae771770SStanislav SedovThe server program is using the function krb5_recvauth() to receive the Kerberos 5 authenticator.<p>
125ae771770SStanislav SedovIn this case, mutual authentication will be tried. That means that the server will authenticate to the client. Using mutual authentication is good since it enables the user to verify that they are talking to the right server (a server that knows the key).<p>
126ae771770SStanislav SedovIf you are using a non-blocking socket you will need to do all work of krb5_sendauth() yourself. Basically you need to send over the authenticator from krb5_mk_req() and, in case of mutual authentication, verifying the result from the server with krb5_rd_rep().<p>
127ae771770SStanislav Sedov<div class="fragment"><pre class="fragment">         status = krb5_sendauth (context,
128ae771770SStanislav Sedov                                 &amp;auth_context,
129ae771770SStanislav Sedov                                 &amp;sock,
130ae771770SStanislav Sedov                                 VERSION,
131ae771770SStanislav Sedov                                 NULL,
132ae771770SStanislav Sedov                                 server,
133ae771770SStanislav Sedov                                 AP_OPTS_MUTUAL_REQUIRED,
134ae771770SStanislav Sedov                                 NULL,
135ae771770SStanislav Sedov                                 NULL,
136ae771770SStanislav Sedov                                 NULL,
137ae771770SStanislav Sedov                                 NULL,
138ae771770SStanislav Sedov                                 NULL,
139ae771770SStanislav Sedov                                 NULL);
140ae771770SStanislav Sedov         <span class="keywordflow">if</span> (status)
141ae771770SStanislav Sedov                 krb5_err (context, 1, status, <span class="stringliteral">"krb5_sendauth"</span>);
142ae771770SStanislav Sedov</pre></div><p>
143ae771770SStanislav SedovOnce authentication has been performed, it is time to send some data. First we create a krb5_data structure, then we sign it with krb5_mk_safe() using the auth_context that contains the session-key that was exchanged in the krb5_sendauth()/krb5_recvauth() authentication sequence.<p>
144ae771770SStanislav Sedov<div class="fragment"><pre class="fragment">         data.data   = <span class="stringliteral">"hej"</span>;
145ae771770SStanislav Sedov         data.length = 3;
146ae771770SStanislav Sedov
147ae771770SStanislav Sedov         <a class="code" href="group__krb5.html#ga059e96dde4e0b8c082eb6f3d570b7bc">krb5_data_zero</a> (&amp;packet);
148ae771770SStanislav Sedov
149ae771770SStanislav Sedov         status = krb5_mk_safe (context,
150ae771770SStanislav Sedov                                auth_context,
151ae771770SStanislav Sedov                                &amp;data,
152ae771770SStanislav Sedov                                &amp;packet,
153ae771770SStanislav Sedov                                NULL);
154ae771770SStanislav Sedov         <span class="keywordflow">if</span> (status)
155ae771770SStanislav Sedov                 krb5_err (context, 1, status, <span class="stringliteral">"krb5_mk_safe"</span>);
156ae771770SStanislav Sedov</pre></div><p>
157ae771770SStanislav SedovAnd send it over the network.<p>
158ae771770SStanislav Sedov<div class="fragment"><pre class="fragment">         len = packet.length;
159ae771770SStanislav Sedov         net_len = htonl(len);
160ae771770SStanislav Sedov
161ae771770SStanislav Sedov         <span class="keywordflow">if</span> (krb5_net_write (context, &amp;sock, &amp;net_len, 4) != 4)
162ae771770SStanislav Sedov                 err (1, <span class="stringliteral">"krb5_net_write"</span>);
163ae771770SStanislav Sedov         <span class="keywordflow">if</span> (krb5_net_write (context, &amp;sock, packet.data, len) != len)
164ae771770SStanislav Sedov                 err (1, <span class="stringliteral">"krb5_net_write"</span>);
165ae771770SStanislav Sedov</pre></div><p>
166ae771770SStanislav SedovTo send encrypted (and signed) data krb5_mk_priv() should be used instead. krb5_mk_priv() works the same way as krb5_mk_safe(), with the exception that it encrypts the data in addition to signing it.<p>
167ae771770SStanislav Sedov<div class="fragment"><pre class="fragment">         data.data   = <span class="stringliteral">"hemligt"</span>;
168ae771770SStanislav Sedov         data.length = 7;
169ae771770SStanislav Sedov
170ae771770SStanislav Sedov         <a class="code" href="group__krb5.html#gb4b80ac7a8bbab89fe947ae1c7828ea8">krb5_data_free</a> (&amp;packet);
171ae771770SStanislav Sedov
172ae771770SStanislav Sedov         status = krb5_mk_priv (context,
173ae771770SStanislav Sedov                                auth_context,
174ae771770SStanislav Sedov                                &amp;data,
175ae771770SStanislav Sedov                                &amp;packet,
176ae771770SStanislav Sedov                                NULL);
177ae771770SStanislav Sedov         <span class="keywordflow">if</span> (status)
178ae771770SStanislav Sedov                 krb5_err (context, 1, status, <span class="stringliteral">"krb5_mk_priv"</span>);
179ae771770SStanislav Sedov</pre></div><p>
180ae771770SStanislav SedovAnd send it over the network.<p>
181ae771770SStanislav Sedov<div class="fragment"><pre class="fragment">         len = packet.length;
182ae771770SStanislav Sedov         net_len = htonl(len);
183ae771770SStanislav Sedov
184ae771770SStanislav Sedov         <span class="keywordflow">if</span> (krb5_net_write (context, &amp;sock, &amp;net_len, 4) != 4)
185ae771770SStanislav Sedov                 err (1, <span class="stringliteral">"krb5_net_write"</span>);
186ae771770SStanislav Sedov         <span class="keywordflow">if</span> (krb5_net_write (context, &amp;sock, packet.data, len) != len)
187ae771770SStanislav Sedov                 err (1, <span class="stringliteral">"krb5_net_write"</span>);
188ae771770SStanislav Sedov</pre></div><p>
189ae771770SStanislav SedovThe server is using krb5_rd_safe() and krb5_rd_priv() to verify the signature and decrypt the packet.<h2><a class="anchor" name="intro_krb5_verify_user">
190ae771770SStanislav SedovValidating a password in an application</a></h2>
191ae771770SStanislav SedovSee the manual page for krb5_verify_user().<h2><a class="anchor" name="mit_differences">
192ae771770SStanislav SedovAPI differences to MIT Kerberos</a></h2>
193ae771770SStanislav SedovThis section is somewhat disorganised, but so far there is no overall structure to the differences, though some of the have their root in that Heimdal uses an ASN.1 compiler and MIT doesn't.<h3><a class="anchor" name="mit_krb5_principal">
194ae771770SStanislav SedovPrincipal and realms</a></h3>
195ae771770SStanislav SedovHeimdal stores the realm as a krb5_realm, that is a char *. MIT Kerberos uses a krb5_data to store a realm.<p>
196ae771770SStanislav SedovIn Heimdal krb5_principal doesn't contain the component name_type; it's instead stored in component name.name_type. To get and set the nametype in Heimdal, use <a class="el" href="group__krb5__principal.html#gf4a599c42592ff7485753e80b8de67b7">krb5_principal_get_type()</a> and <a class="el" href="group__krb5__principal.html#g28b750b990452f02922bc74a6cac0313">krb5_principal_set_type()</a>.<p>
197ae771770SStanislav SedovFor more information about principal and realms, see krb5_principal.<h3><a class="anchor" name="mit_krb5_error_code">
198ae771770SStanislav SedovError messages</a></h3>
199ae771770SStanislav SedovTo get the error string, Heimdal uses krb5_get_error_message(). This is to return custom error messages (like ``Can't find host/datan.example.com@CODE.COM in /etc/krb5.conf.'' instead of a ``Key table entry not found'' that error_message returns.<p>
200ae771770SStanislav SedovHeimdal uses a threadsafe(r) version of the com_err interface; the global com_err table isn't initialised. Then error_message returns quite a boring error string (just the error code itself). </div>
201ae771770SStanislav Sedov<hr size="1"><address style="text-align: right;"><small>
202*cf771f22SStanislav SedovGenerated on Wed Jan 11 14:07:47 2012 for HeimdalKerberos5library by&nbsp;<a href="http://www.doxygen.org/index.html"><img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.6</small></address>
203ae771770SStanislav Sedov</body>
204ae771770SStanislav Sedov</html>
205