1*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 2*7c478bd9Sstevel@tonic-gate /* 3*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 4*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 5*7c478bd9Sstevel@tonic-gate */ 6*7c478bd9Sstevel@tonic-gate 7*7c478bd9Sstevel@tonic-gate #include <k5-int.h> 8*7c478bd9Sstevel@tonic-gate 9*7c478bd9Sstevel@tonic-gate extern krb5_error_code krb5_libdefault_boolean(); 10*7c478bd9Sstevel@tonic-gate 11*7c478bd9Sstevel@tonic-gate static krb5_error_code 12*7c478bd9Sstevel@tonic-gate krb5_cc_copy_creds_except(context, incc, outcc, princ) 13*7c478bd9Sstevel@tonic-gate krb5_context context; 14*7c478bd9Sstevel@tonic-gate krb5_ccache incc; 15*7c478bd9Sstevel@tonic-gate krb5_ccache outcc; 16*7c478bd9Sstevel@tonic-gate krb5_principal princ; 17*7c478bd9Sstevel@tonic-gate { 18*7c478bd9Sstevel@tonic-gate krb5_error_code code; 19*7c478bd9Sstevel@tonic-gate krb5_flags flags; 20*7c478bd9Sstevel@tonic-gate krb5_cc_cursor cur; 21*7c478bd9Sstevel@tonic-gate krb5_creds creds; 22*7c478bd9Sstevel@tonic-gate 23*7c478bd9Sstevel@tonic-gate flags = 0; /* turns off OPENCLOSE mode */ 24*7c478bd9Sstevel@tonic-gate if ((code = krb5_cc_set_flags(context, incc, flags)) != NULL) 25*7c478bd9Sstevel@tonic-gate return(code); 26*7c478bd9Sstevel@tonic-gate if ((code = krb5_cc_set_flags(context, outcc, flags)) != NULL) 27*7c478bd9Sstevel@tonic-gate return(code); 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate if ((code = krb5_cc_start_seq_get(context, incc, &cur)) != NULL) 30*7c478bd9Sstevel@tonic-gate goto cleanup; 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate while ((code = krb5_cc_next_cred(context, incc, &cur, &creds)) == NULL) { 33*7c478bd9Sstevel@tonic-gate if (krb5_principal_compare(context, princ, creds.server)) 34*7c478bd9Sstevel@tonic-gate continue; 35*7c478bd9Sstevel@tonic-gate 36*7c478bd9Sstevel@tonic-gate code = krb5_cc_store_cred(context, outcc, &creds); 37*7c478bd9Sstevel@tonic-gate krb5_free_cred_contents(context, &creds); 38*7c478bd9Sstevel@tonic-gate if (code) 39*7c478bd9Sstevel@tonic-gate goto cleanup; 40*7c478bd9Sstevel@tonic-gate } 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate if (code != KRB5_CC_END) 43*7c478bd9Sstevel@tonic-gate goto cleanup; 44*7c478bd9Sstevel@tonic-gate 45*7c478bd9Sstevel@tonic-gate code = 0; 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate cleanup: 48*7c478bd9Sstevel@tonic-gate flags = KRB5_TC_OPENCLOSE; 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate if (code) 51*7c478bd9Sstevel@tonic-gate (void) krb5_cc_set_flags(context, incc, flags); 52*7c478bd9Sstevel@tonic-gate else 53*7c478bd9Sstevel@tonic-gate code = krb5_cc_set_flags(context, incc, flags); 54*7c478bd9Sstevel@tonic-gate 55*7c478bd9Sstevel@tonic-gate if (code) 56*7c478bd9Sstevel@tonic-gate (void) krb5_cc_set_flags(context, outcc, flags); 57*7c478bd9Sstevel@tonic-gate else 58*7c478bd9Sstevel@tonic-gate code = krb5_cc_set_flags(context, outcc, flags); 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate return(code); 61*7c478bd9Sstevel@tonic-gate } 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate KRB5_DLLIMP krb5_error_code KRB5_CALLCONV 64*7c478bd9Sstevel@tonic-gate krb5_verify_init_creds(krb5_context context, 65*7c478bd9Sstevel@tonic-gate krb5_creds *creds, 66*7c478bd9Sstevel@tonic-gate krb5_principal server_arg, 67*7c478bd9Sstevel@tonic-gate krb5_keytab keytab_arg, 68*7c478bd9Sstevel@tonic-gate krb5_ccache *ccache_arg, 69*7c478bd9Sstevel@tonic-gate krb5_verify_init_creds_opt *options) 70*7c478bd9Sstevel@tonic-gate { 71*7c478bd9Sstevel@tonic-gate krb5_error_code ret; 72*7c478bd9Sstevel@tonic-gate krb5_principal server; 73*7c478bd9Sstevel@tonic-gate krb5_keytab keytab; 74*7c478bd9Sstevel@tonic-gate krb5_ccache ccache; 75*7c478bd9Sstevel@tonic-gate krb5_keytab_entry kte; 76*7c478bd9Sstevel@tonic-gate krb5_creds in_creds, *out_creds; 77*7c478bd9Sstevel@tonic-gate krb5_auth_context authcon; 78*7c478bd9Sstevel@tonic-gate krb5_data ap_req; 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate /* KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN */ 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate server = NULL; 83*7c478bd9Sstevel@tonic-gate keytab = NULL; 84*7c478bd9Sstevel@tonic-gate ccache = NULL; 85*7c478bd9Sstevel@tonic-gate out_creds = NULL; 86*7c478bd9Sstevel@tonic-gate authcon = NULL; 87*7c478bd9Sstevel@tonic-gate ap_req.data = NULL; 88*7c478bd9Sstevel@tonic-gate 89*7c478bd9Sstevel@tonic-gate if (server_arg) { 90*7c478bd9Sstevel@tonic-gate server = server_arg; 91*7c478bd9Sstevel@tonic-gate } else { 92*7c478bd9Sstevel@tonic-gate if (ret = krb5_sname_to_principal(context, NULL, NULL, 93*7c478bd9Sstevel@tonic-gate KRB5_NT_SRV_HST, &server)) { 94*7c478bd9Sstevel@tonic-gate goto cleanup; 95*7c478bd9Sstevel@tonic-gate } else { 96*7c478bd9Sstevel@tonic-gate /* 97*7c478bd9Sstevel@tonic-gate * Solaris Kerberos: 98*7c478bd9Sstevel@tonic-gate * We check first up to see whether 'verify_ap_req_fail' is 99*7c478bd9Sstevel@tonic-gate * set to false, because if FALSE there is no point in 100*7c478bd9Sstevel@tonic-gate * proceeding any further with the strict TGT verification check 101*7c478bd9Sstevel@tonic-gate * for the 'host/fqdn' service principal in the local keytab. 102*7c478bd9Sstevel@tonic-gate */ 103*7c478bd9Sstevel@tonic-gate int nofail; 104*7c478bd9Sstevel@tonic-gate if (krb5_libdefault_boolean(context, 105*7c478bd9Sstevel@tonic-gate &creds->client->realm, 106*7c478bd9Sstevel@tonic-gate "verify_ap_req_nofail", 107*7c478bd9Sstevel@tonic-gate &nofail) == 0) { 108*7c478bd9Sstevel@tonic-gate /* 109*7c478bd9Sstevel@tonic-gate * Solaris Kerberos: 110*7c478bd9Sstevel@tonic-gate * If the administrator has configured the system such 111*7c478bd9Sstevel@tonic-gate * that its OK to fail this strict TGT verification check 112*7c478bd9Sstevel@tonic-gate * (i.e. verify_ap_req_nofail = false), set the 113*7c478bd9Sstevel@tonic-gate * 'ret' code to 0 and cleanup. 114*7c478bd9Sstevel@tonic-gate */ 115*7c478bd9Sstevel@tonic-gate if (!nofail) { 116*7c478bd9Sstevel@tonic-gate ret = 0; 117*7c478bd9Sstevel@tonic-gate goto cleanup; 118*7c478bd9Sstevel@tonic-gate } 119*7c478bd9Sstevel@tonic-gate } 120*7c478bd9Sstevel@tonic-gate } 121*7c478bd9Sstevel@tonic-gate } 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate /* first, check if the server is in the keytab. If not, there's 124*7c478bd9Sstevel@tonic-gate no reason to continue. rd_req does all this, but there's 125*7c478bd9Sstevel@tonic-gate no way to know that a given error is caused by a missing 126*7c478bd9Sstevel@tonic-gate keytab or key, and not by some other problem. */ 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate if (keytab_arg) { 129*7c478bd9Sstevel@tonic-gate keytab = keytab_arg; 130*7c478bd9Sstevel@tonic-gate } else { 131*7c478bd9Sstevel@tonic-gate if (ret = krb5_kt_default(context, &keytab)) 132*7c478bd9Sstevel@tonic-gate goto cleanup; 133*7c478bd9Sstevel@tonic-gate } 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate if ((ret = krb5_kt_get_entry(context, keytab, server, 0, 0, &kte)) != NULL) { 136*7c478bd9Sstevel@tonic-gate /* this means there is no keying material. This is ok, as long as 137*7c478bd9Sstevel@tonic-gate it is not prohibited by the configuration */ 138*7c478bd9Sstevel@tonic-gate if (options && 139*7c478bd9Sstevel@tonic-gate (options->flags & KRB5_VERIFY_INIT_CREDS_OPT_AP_REQ_NOFAIL)) { 140*7c478bd9Sstevel@tonic-gate if (options->ap_req_nofail) 141*7c478bd9Sstevel@tonic-gate goto cleanup; 142*7c478bd9Sstevel@tonic-gate } 143*7c478bd9Sstevel@tonic-gate } 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate krb5_kt_free_entry(context, &kte); 146*7c478bd9Sstevel@tonic-gate 147*7c478bd9Sstevel@tonic-gate /* If the creds are for the server principal, we're set, just do 148*7c478bd9Sstevel@tonic-gate a mk_req. Otherwise, do a get_credentials first. */ 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate if (krb5_principal_compare(context, server, creds->server)) { 151*7c478bd9Sstevel@tonic-gate /* make an ap_req */ 152*7c478bd9Sstevel@tonic-gate if (ret = krb5_mk_req_extended(context, &authcon, 0, NULL, creds, 153*7c478bd9Sstevel@tonic-gate &ap_req)) 154*7c478bd9Sstevel@tonic-gate goto cleanup; 155*7c478bd9Sstevel@tonic-gate } else { 156*7c478bd9Sstevel@tonic-gate /* this is unclean, but it's the easiest way without ripping the 157*7c478bd9Sstevel@tonic-gate library into very small pieces. store the client's initial cred 158*7c478bd9Sstevel@tonic-gate in a memory ccache, then call the library. Later, we'll copy 159*7c478bd9Sstevel@tonic-gate everything except the initial cred into the ccache we return to 160*7c478bd9Sstevel@tonic-gate the user. A clean implementation would involve library 161*7c478bd9Sstevel@tonic-gate internals with a coherent idea of "in" and "out". */ 162*7c478bd9Sstevel@tonic-gate 163*7c478bd9Sstevel@tonic-gate /* insert the initial cred into the ccache */ 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate if (ret = krb5_cc_resolve(context, "MEMORY:rd_req", &ccache)) 166*7c478bd9Sstevel@tonic-gate goto cleanup; 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate if ((ret = krb5_cc_initialize(context, ccache, creds->client)) != NULL) 169*7c478bd9Sstevel@tonic-gate goto cleanup; 170*7c478bd9Sstevel@tonic-gate 171*7c478bd9Sstevel@tonic-gate if ((ret = krb5_cc_store_cred(context, ccache, creds)) != NULL) 172*7c478bd9Sstevel@tonic-gate goto cleanup; 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate /* set up for get_creds */ 175*7c478bd9Sstevel@tonic-gate memset(&in_creds, 0, sizeof(in_creds)); 176*7c478bd9Sstevel@tonic-gate in_creds.client = creds->client; 177*7c478bd9Sstevel@tonic-gate in_creds.server = server; 178*7c478bd9Sstevel@tonic-gate if (ret = krb5_timeofday(context, &in_creds.times.endtime)) 179*7c478bd9Sstevel@tonic-gate goto cleanup; 180*7c478bd9Sstevel@tonic-gate in_creds.times.endtime += 5*60; 181*7c478bd9Sstevel@tonic-gate 182*7c478bd9Sstevel@tonic-gate if (ret = krb5_get_credentials(context, 0, ccache, &in_creds, 183*7c478bd9Sstevel@tonic-gate &out_creds)) 184*7c478bd9Sstevel@tonic-gate goto cleanup; 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate /* make an ap_req */ 187*7c478bd9Sstevel@tonic-gate if (ret = krb5_mk_req_extended(context, &authcon, 0, NULL, out_creds, 188*7c478bd9Sstevel@tonic-gate &ap_req)) 189*7c478bd9Sstevel@tonic-gate goto cleanup; 190*7c478bd9Sstevel@tonic-gate } 191*7c478bd9Sstevel@tonic-gate 192*7c478bd9Sstevel@tonic-gate /* wipe the auth context for mk_req */ 193*7c478bd9Sstevel@tonic-gate if (authcon) { 194*7c478bd9Sstevel@tonic-gate krb5_auth_con_free(context, authcon); 195*7c478bd9Sstevel@tonic-gate authcon = NULL; 196*7c478bd9Sstevel@tonic-gate } 197*7c478bd9Sstevel@tonic-gate 198*7c478bd9Sstevel@tonic-gate /* verify the ap_req */ 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate if (ret = krb5_rd_req(context, &authcon, &ap_req, server, keytab, 201*7c478bd9Sstevel@tonic-gate NULL, NULL)) 202*7c478bd9Sstevel@tonic-gate goto cleanup; 203*7c478bd9Sstevel@tonic-gate 204*7c478bd9Sstevel@tonic-gate /* if we get this far, then the verification succeeded. We can 205*7c478bd9Sstevel@tonic-gate still fail if the library stuff here fails, but that's it */ 206*7c478bd9Sstevel@tonic-gate 207*7c478bd9Sstevel@tonic-gate if (ccache_arg && ccache) { 208*7c478bd9Sstevel@tonic-gate if (*ccache_arg == NULL) { 209*7c478bd9Sstevel@tonic-gate krb5_ccache retcc; 210*7c478bd9Sstevel@tonic-gate 211*7c478bd9Sstevel@tonic-gate retcc = NULL; 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate if (((ret = krb5_cc_resolve(context, "MEMORY:rd_req2", &retcc)) != NULL) || 214*7c478bd9Sstevel@tonic-gate ((ret = krb5_cc_initialize(context, retcc, creds->client)) != NULL) || 215*7c478bd9Sstevel@tonic-gate ((ret = krb5_cc_copy_creds_except(context, ccache, retcc, 216*7c478bd9Sstevel@tonic-gate creds->server)) != NULL)) { 217*7c478bd9Sstevel@tonic-gate if (retcc) 218*7c478bd9Sstevel@tonic-gate (void) krb5_cc_destroy(context, retcc); 219*7c478bd9Sstevel@tonic-gate } else { 220*7c478bd9Sstevel@tonic-gate *ccache_arg = retcc; 221*7c478bd9Sstevel@tonic-gate } 222*7c478bd9Sstevel@tonic-gate } else { 223*7c478bd9Sstevel@tonic-gate ret = krb5_cc_copy_creds_except(context, ccache, *ccache_arg, 224*7c478bd9Sstevel@tonic-gate server); 225*7c478bd9Sstevel@tonic-gate } 226*7c478bd9Sstevel@tonic-gate } 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate /* if any of the above paths returned an errors, then ret is set 229*7c478bd9Sstevel@tonic-gate accordingly. either that, or it's zero, which is fine, too */ 230*7c478bd9Sstevel@tonic-gate 231*7c478bd9Sstevel@tonic-gate cleanup: 232*7c478bd9Sstevel@tonic-gate if (!server_arg && server) 233*7c478bd9Sstevel@tonic-gate krb5_free_principal(context, server); 234*7c478bd9Sstevel@tonic-gate if (!keytab_arg && keytab) 235*7c478bd9Sstevel@tonic-gate (void) krb5_kt_close(context, keytab); 236*7c478bd9Sstevel@tonic-gate if (ccache) 237*7c478bd9Sstevel@tonic-gate (void) krb5_cc_destroy(context, ccache); 238*7c478bd9Sstevel@tonic-gate if (out_creds) 239*7c478bd9Sstevel@tonic-gate krb5_free_creds(context, out_creds); 240*7c478bd9Sstevel@tonic-gate if (authcon) 241*7c478bd9Sstevel@tonic-gate krb5_auth_con_free(context, authcon); 242*7c478bd9Sstevel@tonic-gate if (ap_req.data) 243*7c478bd9Sstevel@tonic-gate krb5_xfree(ap_req.data); 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate return(ret); 246*7c478bd9Sstevel@tonic-gate } 247