Imported Upstream version 1.15.1
[platform/upstream/krb5.git] / doc / html / _sources / appdev / init_creds.txt
1 Initial credentials
2 ===================
3
4 Software that performs tasks such as logging users into a computer
5 when they type their Kerberos password needs to get initial
6 credentials (usually ticket granting tickets) from Kerberos.  Such
7 software shares some behavior with the :ref:`kinit(1)` program.
8
9 Whenever a program grants access to a resource (such as a local login
10 session on a desktop computer) based on a user successfully getting
11 initial Kerberos credentials, it must verify those credentials against
12 a secure shared secret (e.g., a host keytab) to ensure that the user
13 credentials actually originate from a legitimate KDC.  Failure to
14 perform this verification is a critical vulnerability, because a
15 malicious user can execute the "Zanarotti attack": the user constructs
16 a fake response that appears to come from the legitimate KDC, but
17 whose contents come from an attacker-controlled KDC.
18
19 Some applications read a Kerberos password over the network (ideally
20 over a secure channel), which they then verify against the KDC.  While
21 this technique may be the only practical way to integrate Kerberos
22 into some existing legacy systems, its use is contrary to the original
23 design goals of Kerberos.
24
25 The function :c:func:`krb5_get_init_creds_password` will get initial
26 credentials for a client using a password.  An application that needs
27 to verify the credentials can call :c:func:`krb5_verify_init_creds`.
28 Here is an example of code to obtain and verify TGT credentials, given
29 strings *princname* and *password* for the client principal name and
30 password::
31
32     krb5_error_code ret;
33     krb5_creds creds;
34     krb5_principal client_princ = NULL;
35
36     memset(&creds, 0, sizeof(creds));
37     ret = krb5_parse_name(context, princname, &client_princ);
38     if (ret)
39         goto cleanup;
40     ret = krb5_get_init_creds_password(context, &creds, client_princ,
41                                        password, NULL, NULL, 0, NULL, NULL);
42     if (ret)
43         goto cleanup;
44     ret = krb5_verify_init_creds(context, &creds, NULL, NULL, NULL, NULL);
45
46     cleanup:
47     krb5_free_principal(context, client_princ);
48     krb5_free_cred_contents(context, &creds);
49     return ret;
50
51 Options for get_init_creds
52 --------------------------
53
54 The function :c:func:`krb5_get_init_creds_password` takes an options
55 parameter (which can be a null pointer).  Use the function
56 :c:func:`krb5_get_init_creds_opt_alloc` to allocate an options
57 structure, and :c:func:`krb5_get_init_creds_opt_free` to free it.  For
58 example::
59
60     krb5_error_code ret;
61     krb5_get_init_creds_opt *opt = NULL;
62     krb5_creds creds;
63
64     memset(&creds, 0, sizeof(creds));
65     ret = krb5_get_init_creds_opt_alloc(context, &opt);
66     if (ret)
67         goto cleanup;
68     krb5_get_init_creds_opt_set_tkt_life(opt, 24 * 60 * 60);
69     ret = krb5_get_init_creds_password(context, &creds, client_princ,
70                                        password, NULL, NULL, 0, NULL, opt);
71     if (ret)
72         goto cleanup;
73
74     cleanup:
75     krb5_get_init_creds_opt_free(context, opt);
76     krb5_free_cred_contents(context, &creds);
77     return ret;
78
79 Getting anonymous credentials
80 -----------------------------
81
82 As of release 1.8, it is possible to obtain fully anonymous or
83 partially anonymous (realm-exposed) credentials, if the KDC supports
84 it.  The MIT KDC supports issuing fully anonymous credentials as of
85 release 1.8 if configured appropriately (see :ref:`anonymous_pkinit`),
86 but does not support issuing realm-exposed anonymous credentials at
87 this time.
88
89 To obtain fully anonymous credentials, call
90 :c:func:`krb5_get_init_creds_opt_set_anonymous` on the options
91 structure to set the anonymous flag, and specify a client principal
92 with the KDC's realm and a single empty data component (the principal
93 obtained by parsing ``@``\ *realmname*).  Authentication will take
94 place using anonymous PKINIT; if successful, the client principal of
95 the resulting tickets will be
96 ``WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS``.  Here is an example::
97
98     krb5_get_init_creds_opt_set_anonymous(opt, 1);
99     ret = krb5_build_principal(context, &client_princ, strlen(myrealm),
100                                myrealm, "", (char *)NULL);
101     if (ret)
102         goto cleanup;
103     ret = krb5_get_init_creds_password(context, &creds, client_princ,
104                                        password, NULL, NULL, 0, NULL, opt);
105     if (ret)
106         goto cleanup;
107
108 To obtain realm-exposed anonymous credentials, set the anonymous flag
109 on the options structure as above, but specify a normal client
110 principal in order to prove membership in the realm.  Authentication
111 will take place as it normally does; if successful, the client
112 principal of the resulting tickets will be ``WELLKNOWN/ANONYMOUS@``\
113 *realmname*.
114
115 User interaction
116 ----------------
117
118 Authenticating a user usually requires the entry of secret
119 information, such as a password.  A password can be supplied directly
120 to :c:func:`krb5_get_init_creds_password` via the *password*
121 parameter, or the application can supply prompter and/or responder
122 callbacks instead.  If callbacks are used, the user can also be
123 queried for other secret information such as a PIN, informed of
124 impending password expiration, or prompted to change a password which
125 has expired.
126
127 Prompter callback
128 ~~~~~~~~~~~~~~~~~
129
130 A prompter callback can be specified via the *prompter* and *data*
131 parameters to :c:func:`krb5_get_init_creds_password`.  The prompter
132 will be invoked each time the krb5 library has a question to ask or
133 information to present.  When the prompter callback is invoked, the
134 *banner* argument (if not null) is intended to be displayed to the
135 user, and the questions to be answered are specified in the *prompts*
136 array.  Each prompt contains a text question in the *prompt* field, a
137 *hidden* bit to indicate whether the answer should be hidden from
138 display, and a storage area for the answer in the *reply* field.  The
139 callback should fill in each question's ``reply->data`` with the
140 answer, up to a maximum number of ``reply->length`` bytes, and then
141 reset ``reply->length`` to the length of the answer.
142
143 A prompter callback can call :c:func:`krb5_get_prompt_types` to get an
144 array of type constants corresponding to the prompts, to get
145 programmatic information about the semantic meaning of the questions.
146 :c:func:`krb5_get_prompt_types` may return a null pointer if no prompt
147 type information is available.
148
149 Text-based applications can use a built-in text prompter
150 implementation by supplying :c:func:`krb5_prompter_posix` as the
151 *prompter* parameter and a null pointer as the *data* parameter.  For
152 example::
153
154     ret = krb5_get_init_creds_password(context, &creds, client_princ,
155                                        NULL, krb5_prompter_posix, NULL, 0,
156                                        NULL, NULL);
157
158 Responder callback
159 ~~~~~~~~~~~~~~~~~~
160
161 A responder callback can be specified through the init_creds options
162 using the :c:func:`krb5_get_init_creds_opt_set_responder` function.
163 Responder callbacks can present a more sophisticated user interface
164 for authentication secrets.  The responder callback is usually invoked
165 only once per authentication, with a list of questions produced by all
166 of the allowed preauthentication mechanisms.
167
168 When the responder callback is invoked, the *rctx* argument can be
169 accessed to obtain the list of questions and to answer them.  The
170 :c:func:`krb5_responder_list_questions` function retrieves an array of
171 question types.  For each question type, the
172 :c:func:`krb5_responder_get_challenge` function retrieves additional
173 information about the question, if applicable, and the
174 :c:func:`krb5_responder_set_answer` function sets the answer.
175
176 Responder question types, challenges, and answers are UTF-8 strings.
177 The question type is a well-known string; the meaning of the challenge
178 and answer depend on the question type.  If an application does not
179 understand a question type, it cannot interpret the challenge or
180 provide an answer.  Failing to answer a question typically results in
181 the prompter callback being used as a fallback.
182
183 Password question
184 #################
185
186 The :c:macro:`KRB5_RESPONDER_QUESTION_PASSWORD` (or ``"password"``)
187 question type requests the user's password.  This question does not
188 have a challenge, and the response is simply the password string.
189
190 One-time password question
191 ##########################
192
193 The :c:macro:`KRB5_RESPONDER_QUESTION_OTP` (or ``"otp"``) question
194 type requests a choice among one-time password tokens and the PIN and
195 value for the chosen token.  The challenge and answer are JSON-encoded
196 strings, but an application can use convenience functions to avoid
197 doing any JSON processing itself.
198
199 The :c:func:`krb5_responder_otp_get_challenge` function decodes the
200 challenge into a krb5_responder_otp_challenge structure.  The
201 :c:func:`krb5_responder_otp_set_answer` function selects one of the
202 token information elements from the challenge and supplies the value
203 and pin for that token.
204
205 PKINIT password or PIN question
206 ###############################
207
208 The :c:macro:`KRB5_RESPONDER_QUESTION_PKINIT` (or ``"pkinit"``) question
209 type requests PINs for hardware devices and/or passwords for encrypted
210 credentials which are stored on disk, potentially also supplying
211 information about the state of the hardware devices.  The challenge and
212 answer are JSON-encoded strings, but an application can use convenience
213 functions to avoid doing any JSON processing itself.
214
215 The :c:func:`krb5_responder_pkinit_get_challenge` function decodes the
216 challenges into a krb5_responder_pkinit_challenge structure.  The
217 :c:func:`krb5_responder_pkinit_set_answer` function can be used to
218 supply the PIN or password for a particular client credential, and can
219 be called multiple times.
220
221 Example
222 #######
223
224 Here is an example of using a responder callback::
225
226     static krb5_error_code
227     my_responder(krb5_context context, void *data,
228                  krb5_responder_context rctx)
229     {
230         krb5_error_code ret;
231         krb5_responder_otp_challenge *chl;
232
233         if (krb5_responder_get_challenge(context, rctx,
234                                          KRB5_RESPONDER_QUESTION_PASSWORD)) {
235             ret = krb5_responder_set_answer(context, rctx,
236                                             KRB5_RESPONDER_QUESTION_PASSWORD,
237                                             "open sesame");
238             if (ret)
239                 return ret;
240         }
241         ret = krb5_responder_otp_get_challenge(context, rctx, &chl);
242         if (ret == 0 && chl != NULL) {
243             ret = krb5_responder_otp_set_answer(context, rctx, 0, "1234",
244                                                 NULL);
245             krb5_responder_otp_challenge_free(context, rctx, chl);
246             if (ret)
247                 return ret;
248         }
249         return 0;
250     }
251
252     static krb5_error_code
253     get_creds(krb5_context context, krb5_principal client_princ)
254     {
255         krb5_error_code ret;
256         krb5_get_init_creds_opt *opt = NULL;
257         krb5_creds creds;
258
259         memset(&creds, 0, sizeof(creds));
260         ret = krb5_get_init_creds_opt_alloc(context, &opt);
261         if (ret)
262             goto cleanup;
263         ret = krb5_get_init_creds_opt_set_responder(context, opt, my_responder,
264                                                     NULL);
265         if (ret)
266             goto cleanup;
267         ret = krb5_get_init_creds_password(context, &creds, client_princ,
268                                            NULL, NULL, NULL, 0, NULL, opt);
269
270     cleanup:
271         krb5_get_init_creds_opt_free(context, opt);
272         krb5_free_cred_contents(context, &creds);
273         return ret;
274     }
275
276 Verifying initial credentials
277 -----------------------------
278
279 Use the function :c:func:`krb5_verify_init_creds` to verify initial
280 credentials.  It takes an options structure (which can be a null
281 pointer).  Use :c:func:`krb5_verify_init_creds_opt_init` to initialize
282 the caller-allocated options structure, and
283 :c:func:`krb5_verify_init_creds_opt_set_ap_req_nofail` to set the
284 "nofail" option.  For example::
285
286     krb5_verify_init_creds_opt vopt;
287
288     krb5_verify_init_creds_opt_init(&vopt);
289     krb5_verify_init_creds_opt_set_ap_req_nofail(&vopt, 1);
290     ret = krb5_verify_init_creds(context, &creds, NULL, NULL, NULL, &vopt);
291
292 The confusingly named "nofail" option, when set, means that the
293 verification must actually succeed in order for
294 :c:func:`krb5_verify_init_creds` to indicate success.  The default
295 state of this option (cleared) means that if there is no key material
296 available to verify the user credentials, the verification will
297 succeed anyway.  (The default can be changed by a configuration file
298 setting.)
299
300 This accommodates a use case where a large number of unkeyed shared
301 desktop workstations need to allow users to log in using Kerberos.
302 The security risks from this practice are mitigated by the absence of
303 valuable state on the shared workstations---any valuable resources
304 that the users would access reside on networked servers.