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