3 @node Programming with Kerberos
4 @chapter Programming with Kerberos
6 First you need to know how the Kerberos model works, go read the
7 introduction text (@pxref{What is Kerberos?}).
10 * Kerberos 5 API Overview::
11 * Walkthru a sample Kerberos 5 client::
12 * Validating a password in a server application::
13 * API diffrences to MIT Kerberos::
16 @node Kerberos 5 API Overview, Walkthru a sample Kerberos 5 client, Programming with Kerberos, Programming with Kerberos
17 @section Kerberos 5 API Overview
19 Most functions are documenteded in manual pages. This overview only
20 tries to point to where to look for a specific function.
22 @subsection Kerberos context
24 A kerberos context (@code{krb5_context}) holds all per thread state. All global variables that
25 are context specific are stored in this struture, including default
26 encryption types, credential-cache (ticket file), and default realms.
28 See the manual pages for @manpage{krb5_context,3} and
29 @manpage{krb5_init_context,3}.
31 @subsection Kerberos authenication context
33 Kerberos authentication context (@code{krb5_auth_context}) holds all
34 context related to an authenticated connection, in a similar way to the
35 kerberos context that holds the context for the thread or process.
37 The @code{krb5_auth_context} is used by various functions that are
38 directly related to authentication between the server/client. Example of
39 data that this structure contains are various flags, addresses of client
40 and server, port numbers, keyblocks (and subkeys), sequence numbers,
41 replay cache, and checksum types.
43 See the manual page for @manpage{krb5_auth_context,3}.
45 @subsection Keytab management
47 A keytab is a storage for locally stored keys. Heimdal includes keytab
48 support for Kerberos 5 keytabs, Kerberos 4 srvtab, AFS-KeyFile's,
49 and for storing keys in memory.
51 See also manual page for @manpage{krb5_keytab,3}
53 @subsection Kerberos principal
55 See also manual page for @manpage{krb5_principal,3}
57 @subsection Kerberos crypto
59 See also manual page for @manpage{krb5_crypto_init,3},
60 @manpage{krb5_keyblock,3}, @manpage{krb5_create_checksum,3},
61 and @manpage{krb5_encrypt,3}.
63 @node Walkthru a sample Kerberos 5 client, Validating a password in a server application, Kerberos 5 API Overview, Programming with Kerberos
64 @section Walkthru a sample Kerberos 5 client
66 This example contains parts of a sample TCP Kerberos 5 clients, if you
67 want a real working client, please look in @file{appl/test} directory in
68 the Heimdal distribution.
70 All Kerberos error-codes that are returned from kerberos functions in
71 this program are passed to @code{krb5_err}, that will print a
72 descriptive text of the error code and exit. Graphical programs can
73 convert error-code to a humal readable error-string with the
74 @manpage{krb5_get_err_text,3} function.
76 Note that you should not use any Kerberos function before
77 @code{krb5_init_context()} have completed successfully. That is the
78 reson @code{err()} is used when @code{krb5_init_context()} fails.
80 First the client needs to call @code{krb5_init_context} to initialise
81 the Kerberos 5 library. This is only needed once per thread
82 in the program. If the function returns a non-zero value it indicates
83 that either the Kerberos implemtation is failing or its disabled on
90 main(int argc, char **argv)
94 if (krb5_context(&context))
95 errx (1, "krb5_context");
98 Now the client wants to connect to the host at the other end. The
99 preferred way of doing this is using @manpage{getaddrinfo,3} (for
100 operating system that have this function implemented), since getaddrinfo
101 is neutral to the address type and can use any protocol that is available.
104 struct addrinfo *ai, *a;
105 struct addrinfo hints;
108 memset (&hints, 0, sizeof(hints));
109 hints.ai_socktype = SOCK_STREAM;
110 hints.ai_protocol = IPPROTO_TCP;
112 error = getaddrinfo (hostname, "pop3", &hints, &ai);
114 errx (1, "%s: %s", hostname, gai_strerror(error));
116 for (a = ai; a != NULL; a = a->ai_next) @{
119 s = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
122 if (connect (s, a->ai_addr, a->ai_addrlen) < 0) @{
123 warn ("connect(%s)", hostname);
132 errx ("failed to contact %s", hostname);
136 Before authenticating, an authentication context needs to be
137 created. This context keeps all information for one (to be) authenticated
138 connection (see @manpage{krb5_auth_context,3}).
141 status = krb5_auth_con_init (context, &auth_context);
143 krb5_err (context, 1, status, "krb5_auth_con_init");
146 For setting the address in the authentication there is a help function
147 @code{krb5_auth_con_setaddrs_from_fd} that does everthing that is needed
148 when given a connected file descriptor to the socket.
151 status = krb5_auth_con_setaddrs_from_fd (context,
155 krb5_err (context, 1, status,
156 "krb5_auth_con_setaddrs_from_fd");
159 The next step is to build a server principal for the service we want
160 to connect to. (See also @manpage{krb5_sname_to_principal,3}.)
163 status = krb5_sname_to_principal (context,
169 krb5_err (context, 1, status, "krb5_sname_to_principal");
172 The client principal is not passed to @manpage{krb5_sendauth,3}
173 function, this causes the @code{krb5_sendauth} function to try to figure it
176 The server program is using the function @manpage{krb5_recvauth,3} to
177 receive the Kerberos 5 authenticator.
179 In this case, mutual authenication will be tried. That means that the server
180 will authenticate to the client. Using mutual authenication
181 is good since it enables the user to verify that they are talking to the
182 right server (a server that knows the key).
184 If you are using a non-blocking socket you will need to do all work of
185 @code{krb5_sendauth} yourself. Basically you need to send over the
186 authenticator from @manpage{krb5_mk_req,3} and, in case of mutual
187 authentication, verifying the result from the server with
188 @manpage{krb5_rd_rep,3}.
191 status = krb5_sendauth (context,
197 AP_OPTS_MUTUAL_REQUIRED,
205 krb5_err (context, 1, status, "krb5_sendauth");
208 Once authentication has been performed, it is time to send some
209 data. First we create a krb5_data structure, then we sign it with
210 @manpage{krb5_mk_safe,3} using the @code{auth_context} that contains the
211 session-key that was exchanged in the
212 @manpage{krb5_sendauth,3}/@manpage{krb5_recvauth,3} authentication
219 krb5_data_zero (&packet);
221 status = krb5_mk_safe (context,
227 krb5_err (context, 1, status, "krb5_mk_safe");
230 And send it over the network.
234 net_len = htonl(len);
236 if (krb5_net_write (context, &sock, &net_len, 4) != 4)
237 err (1, "krb5_net_write");
238 if (krb5_net_write (context, &sock, packet.data, len) != len)
239 err (1, "krb5_net_write");
242 To send encrypted (and signed) data @manpage{krb5_mk_priv,3} should be
243 used instead. @manpage{krb5_mk_priv,3} works the same way as
244 @manpage{krb5_mk_safe,3}, with the exception that it encrypts the data
245 in addition to signing it.
248 data.data = "hemligt";
251 krb5_data_free (&packet);
253 status = krb5_mk_priv (context,
259 krb5_err (context, 1, status, "krb5_mk_priv");
262 And send it over the network.
266 net_len = htonl(len);
268 if (krb5_net_write (context, &sock, &net_len, 4) != 4)
269 err (1, "krb5_net_write");
270 if (krb5_net_write (context, &sock, packet.data, len) != len)
271 err (1, "krb5_net_write");
275 The server is using @manpage{krb5_rd_safe,3} and
276 @manpage{krb5_rd_priv,3} to verify the signature and decrypt the packet.
278 @node Validating a password in a server application, API diffrences to MIT Kerberos, Walkthru a sample Kerberos 5 client, Programming with Kerberos
279 @section Validating a password in an application
281 See the manual page for @manpage{krb5_verify_user,3}.
283 @node API diffrences to MIT Kerberos, , Validating a password in a server application, Programming with Kerberos
284 @section API diffrences to MIT Kerberos
286 This section is somewhat unorganised, but so far there is no overall
287 structure to the diffrecies, though some of the have their root in
288 that heimdal uses a ASN.1 compiler and MIT doesn't.
290 @subsection Principal and realms
292 Heimdal store the realm as a @code{krb5_realm} that is a @code{char *}.
293 MIT Kerberos uses a @code{krb5_data} to store a realm. See
295 In Heimdal @code{krb5_principal} doesn't contain the component
296 @code{name_type}, its instead stored in component
297 @code{name.name_type}. To get and set the nametype in Heimdal, use
298 @manpage{krb5_principal_get_type,3} and
299 @manpage{krb5_principal_set_type,3}.
301 For more information about principal and realms, see
302 @manpage{krb5_principal,3}.
304 @subsection Error messages
306 To get the error string, Heimdal users uses
307 @manpage{krb5_get_error_string,3} or if @code{NULL} is returned,
308 @manpage{krb5_get_err_text,3}. This is to return custom error messages
309 (like ''Can't find host/datan.example.com@@EXAMPLE.COM in
310 /etc/krb5.conf.'' instead of a ``Key table entry not found'' that
311 @manpage{error_message,3} returns.
313 Heimdal uses a threadsafe(er) version of the com_err interface, the
314 global com_err table isn't initialised, then @manpage{error_message,3}
315 returns quite boring error string (just the error code itself).
318 @c @node Why you should use GSS-API for new applications, Walkthru a sample GSS-API client, Validating a password in a server application, Programming with Kerberos
319 @c @section Why you should use GSS-API for new applications
321 @c SSPI, bah, bah, microsoft, bah, bah, almost GSS-API.
323 @c It would also be possible for other mechanisms then Kerberos, but that
324 @c doesn't exist any other GSS-API implementations today.
326 @c @node Walkthru a sample GSS-API client, , Why you should use GSS-API for new applications, Programming with Kerberos
327 @c @section Walkthru a sample GSS-API client
329 @c Write about how gssapi_clent.c works.