remove gcc34
[dragonfly.git] / crypto / heimdal-0.6.3 / doc / programming.texi
1 @c $Id: programming.texi,v 1.2.8.1 2003/04/24 11:55:45 lha Exp $
2
3 @node Programming with Kerberos
4 @chapter Programming with Kerberos
5
6 First you need to know how the Kerberos model works, go read the
7 introduction text (@pxref{What is Kerberos?}).
8
9 @macro manpage{man, section}
10 @cite{\man\(\section\)}
11 @end macro
12
13 @menu
14 * Kerberos 5 API Overview::     
15 * Walkthru a sample Kerberos 5 client::  
16 * Validating a password in a server application::  
17 @end menu
18
19 @node Kerberos 5 API Overview, Walkthru a sample Kerberos 5 client, Programming with Kerberos, Programming with Kerberos
20 @section Kerberos 5 API Overview
21
22 Most functions are documenteded in manual pages.  This overview only
23 tries to point to where to look for a specific function.
24
25 @subsection Kerberos context
26
27 A kerberos context (@code{krb5_context}) holds all per thread state. All global variables that
28 are context specific are stored in this struture, including default
29 encryption types, credential-cache (ticket file), and default realms.
30
31 See the manual pages for @manpage{krb5_context,3} and
32 @manpage{krb5_init_context,3}.
33
34 @subsection Kerberos authenication context
35
36 Kerberos authentication context (@code{krb5_auth_context}) holds all
37 context related to an authenticated connection, in a similar way to the
38 kerberos context that holds the context for the thread or process.
39
40 The @code{krb5_auth_context} is used by various functions that are
41 directly related to authentication between the server/client. Example of
42 data that this structure contains are various flags, addresses of client
43 and server, port numbers, keyblocks (and subkeys), sequence numbers,
44 replay cache, and checksum types.
45
46 See the manual page for @manpage{krb5_auth_context,3}.
47
48 @subsection Keytab management
49
50 A keytab is a storage for locally stored keys. Heimdal includes keytab
51 support for Kerberos 5 keytabs, Kerberos 4 srvtab, AFS-KeyFile's,
52 and for storing keys in memory.
53
54 See also manual page for @manpage{krb5_keytab,3}
55
56 @node Walkthru a sample Kerberos 5 client, Validating a password in a server application, Kerberos 5 API Overview, Programming with Kerberos
57 @section Walkthru a sample Kerberos 5 client
58
59 This example contains parts of a sample TCP Kerberos 5 clients, if you
60 want a real working client, please look in @file{appl/test} directory in
61 the Heimdal distribution.
62
63 All Kerberos error-codes that are returned from kerberos functions in
64 this program are passed to @code{krb5_err}, that will print a
65 descriptive text of the error code and exit. Graphical programs can
66 convert error-code to a humal readable error-string with the
67 @manpage{krb5_get_err_text,3} function.
68
69 Note that you should not use any Kerberos function before
70 @code{krb5_init_context()} have completed successfully. That is the
71 reson @code{err()} is used when @code{krb5_init_context()} fails.
72
73 First the client needs to call @code{krb5_init_context} to initialize
74 the Kerberos 5 library. This is only needed once per thread
75 in the program. If the function returns a non-zero value it indicates
76 that either the Kerberos implemtation is failing or its disabled on
77 this host.
78
79 @example
80 #include <krb5.h>
81
82 int
83 main(int argc, char **argv)
84 @{
85         krb5_context context;
86
87         if (krb5_context(&context))
88                 errx (1, "krb5_context");
89 @end example
90
91 Now the client wants to connect to the host at the other end. The
92 preferred way of doing this is using @manpage{getaddrinfo,3} (for
93 operating system that have this function implemented), since getaddrinfo
94 is neutral to the address type and can use any protocol that is available.
95
96 @example
97         struct addrinfo *ai, *a;
98         struct addrinfo hints;
99         int error;
100
101         memset (&hints, 0, sizeof(hints));
102         hints.ai_socktype = SOCK_STREAM;
103         hints.ai_protocol = IPPROTO_TCP;
104
105         error = getaddrinfo (hostname, "pop3", &hints, &ai);
106         if (error)
107                 errx (1, "%s: %s", hostname, gai_strerror(error));
108
109         for (a = ai; a != NULL; a = a->ai_next) @{
110                 int s;
111
112                 s = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
113                 if (s < 0)
114                         continue;
115                 if (connect (s, a->ai_addr, a->ai_addrlen) < 0) @{
116                         warn ("connect(%s)", hostname);
117                             close (s);
118                             continue;
119                 @}
120                 freeaddrinfo (ai);
121                 ai = NULL;
122         @}
123         if (ai) @{
124                     freeaddrinfo (ai);
125                     errx ("failed to contact %s", hostname);
126         @}
127 @end example
128
129 Before authenticating, an authentication context needs to be
130 created. This context keeps all information for one (to be) authenticated
131 connection (see @manpage{krb5_auth_context,3}).
132
133 @example
134         status = krb5_auth_con_init (context, &auth_context);
135         if (status)
136                 krb5_err (context, 1, status, "krb5_auth_con_init");
137 @end example
138
139 For setting the address in the authentication there is a help function
140 @code{krb5_auth_con_setaddrs_from_fd} that does everthing that is needed
141 when given a connected file descriptor to the socket.
142
143 @example
144         status = krb5_auth_con_setaddrs_from_fd (context,
145                                                  auth_context,
146                                                  &sock);
147         if (status)
148                 krb5_err (context, 1, status, 
149                           "krb5_auth_con_setaddrs_from_fd");
150 @end example
151
152 The next step is to build a server principal for the service we want
153 to connect to. (See also @manpage{krb5_sname_to_principal,3}.)
154
155 @example
156         status = krb5_sname_to_principal (context,
157                                           hostname,
158                                           service,
159                                           KRB5_NT_SRV_HST,
160                                           &server);
161         if (status)
162                 krb5_err (context, 1, status, "krb5_sname_to_principal");
163 @end example
164
165 The client principal is not passed to @manpage{krb5_sendauth,3}
166 function, this causes the @code{krb5_sendauth} function to try to figure it
167 out itself.
168
169 The server program is using the function @manpage{krb5_recvauth,3} to
170 receive the Kerberos 5 authenticator.
171
172 In this case, mutual authenication will be tried. That means that the server
173 will authenticate to the client. Using mutual authenication
174 is good since it enables the user to verify that they are talking to the
175 right server (a server that knows the key).
176
177 If you are using a non-blocking socket you will need to do all work of
178 @code{krb5_sendauth} yourself. Basically you need to send over the
179 authenticator from @manpage{krb5_mk_req,3} and, in case of mutual
180 authentication, verifying the result from the server with
181 @manpage{krb5_rd_rep,3}.
182
183 @example
184         status = krb5_sendauth (context,
185                                 &auth_context,
186                                 &sock,
187                                 VERSION,
188                                 NULL,
189                                 server,
190                                 AP_OPTS_MUTUAL_REQUIRED,
191                                 NULL,
192                                 NULL,
193                                 NULL,
194                                 NULL,
195                                 NULL,
196                                 NULL);
197         if (status)
198                 krb5_err (context, 1, status, "krb5_sendauth");
199 @end example
200
201 Once authentication has been performed, it is time to send some
202 data. First we create a krb5_data structure, then we sign it with
203 @manpage{krb5_mk_safe,3} using the @code{auth_context} that contains the
204 session-key that was exchanged in the
205 @manpage{krb5_sendauth,3}/@manpage{krb5_recvauth,3} authentication
206 sequence.
207
208 @example
209         data.data   = "hej";
210         data.length = 3;
211
212         krb5_data_zero (&packet);
213
214         status = krb5_mk_safe (context,
215                                auth_context,
216                                &data,
217                                &packet,
218                                NULL);
219         if (status)
220                 krb5_err (context, 1, status, "krb5_mk_safe");
221 @end example
222
223 And send it over the network.
224
225 @example
226         len = packet.length;
227         net_len = htonl(len);
228
229         if (krb5_net_write (context, &sock, &net_len, 4) != 4)
230                 err (1, "krb5_net_write");
231         if (krb5_net_write (context, &sock, packet.data, len) != len)
232                 err (1, "krb5_net_write");
233 @end example
234
235 To send encrypted (and signed) data @manpage{krb5_mk_priv,3} should be
236 used instead. @manpage{krb5_mk_priv,3} works the same way as
237 @manpage{krb5_mk_safe,3}, with the exception that it encrypts the data
238 in addition to signing it.
239
240 @example
241         data.data   = "hemligt";
242         data.length = 7;
243
244         krb5_data_free (&packet);
245
246         status = krb5_mk_priv (context,
247                                auth_context,
248                                &data,
249                                &packet,
250                                NULL);
251         if (status)
252                 krb5_err (context, 1, status, "krb5_mk_priv");
253 @end example
254
255 And send it over the network.
256
257 @example
258         len = packet.length;
259         net_len = htonl(len);
260
261         if (krb5_net_write (context, &sock, &net_len, 4) != 4)
262                 err (1, "krb5_net_write");
263         if (krb5_net_write (context, &sock, packet.data, len) != len)
264                 err (1, "krb5_net_write");
265
266 @end example
267
268 The server is using @manpage{krb5_rd_safe,3} and
269 @manpage{krb5_rd_priv,3} to verify the signature and decrypt the packet.
270
271 @node Validating a password in a server application,  , Walkthru a sample Kerberos 5 client, Programming with Kerberos
272 @section Validating a password in an application
273
274 See the manual page for @manpage{krb5_verify_user,3}.
275
276 @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
277 @c @section Why you should use GSS-API for new applications
278 @c 
279 @c SSPI, bah, bah, microsoft, bah, bah, almost GSS-API.
280 @c 
281 @c It would also be possible for other mechanisms then Kerberos, but that
282 @c doesn't exist any other GSS-API implementations today.
283 @c 
284 @c @node Walkthru a sample GSS-API client, , Why you should use GSS-API for new applications, Programming with Kerberos
285 @c @section Walkthru a sample GSS-API client
286 @c 
287 @c Write about how gssapi_clent.c works.