17c478bd9Sstevel@tonic-gate /* 2159d09a2SMark Phalan * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 37c478bd9Sstevel@tonic-gate * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate */ 57c478bd9Sstevel@tonic-gate 6159d09a2SMark Phalan #include "k5-int.h" 7505d05c7Sgtb #include "int-proto.h" 87c478bd9Sstevel@tonic-gate 9159d09a2SMark Phalan /* Solaris Kerberos */ 107c478bd9Sstevel@tonic-gate extern krb5_error_code krb5_libdefault_boolean(); 117c478bd9Sstevel@tonic-gate 127c478bd9Sstevel@tonic-gate static krb5_error_code 13505d05c7Sgtb krb5_cc_copy_creds_except(krb5_context context, krb5_ccache incc, krb5_ccache outcc, krb5_principal princ) 147c478bd9Sstevel@tonic-gate { 157c478bd9Sstevel@tonic-gate krb5_error_code code; 167c478bd9Sstevel@tonic-gate krb5_flags flags; 177c478bd9Sstevel@tonic-gate krb5_cc_cursor cur; 187c478bd9Sstevel@tonic-gate krb5_creds creds; 197c478bd9Sstevel@tonic-gate 207c478bd9Sstevel@tonic-gate flags = 0; /* turns off OPENCLOSE mode */ 21159d09a2SMark Phalan /* Solaris Kerberos */ 22*940daf74SToomas Soome if ((code = krb5_cc_set_flags(context, incc, flags)) != 0) 237c478bd9Sstevel@tonic-gate return(code); 24159d09a2SMark Phalan /* Solaris Kerberos */ 25*940daf74SToomas Soome if ((code = krb5_cc_set_flags(context, outcc, flags)) != 0) 267c478bd9Sstevel@tonic-gate return(code); 277c478bd9Sstevel@tonic-gate 28159d09a2SMark Phalan /* Solaris Kerberos */ 29*940daf74SToomas Soome if ((code = krb5_cc_start_seq_get(context, incc, &cur)) != 0) 307c478bd9Sstevel@tonic-gate goto cleanup; 317c478bd9Sstevel@tonic-gate 32159d09a2SMark Phalan /* Solaris Kerberos */ 33*940daf74SToomas Soome while ((code = krb5_cc_next_cred(context, incc, &cur, &creds)) == 0) { 347c478bd9Sstevel@tonic-gate if (krb5_principal_compare(context, princ, creds.server)) 357c478bd9Sstevel@tonic-gate continue; 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate code = krb5_cc_store_cred(context, outcc, &creds); 387c478bd9Sstevel@tonic-gate krb5_free_cred_contents(context, &creds); 397c478bd9Sstevel@tonic-gate if (code) 407c478bd9Sstevel@tonic-gate goto cleanup; 417c478bd9Sstevel@tonic-gate } 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate if (code != KRB5_CC_END) 447c478bd9Sstevel@tonic-gate goto cleanup; 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate code = 0; 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate cleanup: 497c478bd9Sstevel@tonic-gate flags = KRB5_TC_OPENCLOSE; 507c478bd9Sstevel@tonic-gate 51159d09a2SMark Phalan /* Solaris Kerberos */ 527c478bd9Sstevel@tonic-gate if (code) 537c478bd9Sstevel@tonic-gate (void) krb5_cc_set_flags(context, incc, flags); 547c478bd9Sstevel@tonic-gate else 557c478bd9Sstevel@tonic-gate code = krb5_cc_set_flags(context, incc, flags); 567c478bd9Sstevel@tonic-gate 57159d09a2SMark Phalan /* Solaris Kerberos */ 587c478bd9Sstevel@tonic-gate if (code) 597c478bd9Sstevel@tonic-gate (void) krb5_cc_set_flags(context, outcc, flags); 607c478bd9Sstevel@tonic-gate else 617c478bd9Sstevel@tonic-gate code = krb5_cc_set_flags(context, outcc, flags); 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate return(code); 647c478bd9Sstevel@tonic-gate } 657c478bd9Sstevel@tonic-gate 66505d05c7Sgtb krb5_error_code KRB5_CALLCONV 677c478bd9Sstevel@tonic-gate krb5_verify_init_creds(krb5_context context, 687c478bd9Sstevel@tonic-gate krb5_creds *creds, 697c478bd9Sstevel@tonic-gate krb5_principal server_arg, 707c478bd9Sstevel@tonic-gate krb5_keytab keytab_arg, 717c478bd9Sstevel@tonic-gate krb5_ccache *ccache_arg, 727c478bd9Sstevel@tonic-gate krb5_verify_init_creds_opt *options) 737c478bd9Sstevel@tonic-gate { 747c478bd9Sstevel@tonic-gate krb5_error_code ret; 757c478bd9Sstevel@tonic-gate krb5_principal server; 767c478bd9Sstevel@tonic-gate krb5_keytab keytab; 777c478bd9Sstevel@tonic-gate krb5_ccache ccache; 787c478bd9Sstevel@tonic-gate krb5_keytab_entry kte; 797c478bd9Sstevel@tonic-gate krb5_creds in_creds, *out_creds; 807c478bd9Sstevel@tonic-gate krb5_auth_context authcon; 817c478bd9Sstevel@tonic-gate krb5_data ap_req; 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate /* KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN */ 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate server = NULL; 867c478bd9Sstevel@tonic-gate keytab = NULL; 877c478bd9Sstevel@tonic-gate ccache = NULL; 887c478bd9Sstevel@tonic-gate out_creds = NULL; 897c478bd9Sstevel@tonic-gate authcon = NULL; 907c478bd9Sstevel@tonic-gate ap_req.data = NULL; 917c478bd9Sstevel@tonic-gate 92159d09a2SMark Phalan /* Solaris Kerberos */ 935d01ff85Swillf if (server_arg) 947c478bd9Sstevel@tonic-gate server = server_arg; 955d01ff85Swillf else if (ret = krb5_sname_to_principal(context, NULL, NULL, 965d01ff85Swillf KRB5_NT_SRV_HST, &server)) 977c478bd9Sstevel@tonic-gate goto cleanup; 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate /* first, check if the server is in the keytab. If not, there's 1007c478bd9Sstevel@tonic-gate no reason to continue. rd_req does all this, but there's 1017c478bd9Sstevel@tonic-gate no way to know that a given error is caused by a missing 1027c478bd9Sstevel@tonic-gate keytab or key, and not by some other problem. */ 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate if (keytab_arg) { 1057c478bd9Sstevel@tonic-gate keytab = keytab_arg; 1067c478bd9Sstevel@tonic-gate } else { 1075d01ff85Swillf /* Solaris Kerberos: ignore errors here, deal with below */ 1085d01ff85Swillf ret = krb5_kt_default(context, &keytab); 1097c478bd9Sstevel@tonic-gate } 1107c478bd9Sstevel@tonic-gate 111159d09a2SMark Phalan /* 112159d09a2SMark Phalan * Solaris Kerberos: 113159d09a2SMark Phalan * Warning: be very, very careful when modifying the logic here 114159d09a2SMark Phalan */ 1155d01ff85Swillf if (keytab == NULL || 1165d01ff85Swillf (ret = krb5_kt_get_entry(context, keytab, server, 0, 0, &kte))) { 1177c478bd9Sstevel@tonic-gate /* this means there is no keying material. This is ok, as long as 1187c478bd9Sstevel@tonic-gate it is not prohibited by the configuration */ 119159d09a2SMark Phalan /* Solaris Kerberos */ 1205d01ff85Swillf int nofail = 1; /* Solaris Kerberos: default return error if keytab problems */ 1215d01ff85Swillf 1227c478bd9Sstevel@tonic-gate if (options && 1237c478bd9Sstevel@tonic-gate (options->flags & KRB5_VERIFY_INIT_CREDS_OPT_AP_REQ_NOFAIL)) { 1245d01ff85Swillf /* first, if options are set then use the option value to set nofail */ 1255d01ff85Swillf nofail = options->ap_req_nofail; 1265d01ff85Swillf } else { 1275d01ff85Swillf /* 128159d09a2SMark Phalan * Solaris Kerberos: 1295d01ff85Swillf * Check verify_ap_req_nofail if set in config file. Note this logic 1305d01ff85Swillf * assumes that krb5_libdefault_boolean will not set nofail to a 1315d01ff85Swillf * default value if verify_ap_req_nofail is not explictly set in 1325d01ff85Swillf * config file. Don't care about the return code. 1335d01ff85Swillf */ 1345d01ff85Swillf (void) krb5_libdefault_boolean(context, &creds->client->realm, 1355d01ff85Swillf "verify_ap_req_nofail", 1365d01ff85Swillf &nofail); 1377c478bd9Sstevel@tonic-gate } 1385d01ff85Swillf /* Solaris Kerberos: exit without an error ONLY if nofail is false */ 1395d01ff85Swillf if (!nofail) 1405d01ff85Swillf ret = 0; 1415d01ff85Swillf 1425d01ff85Swillf goto cleanup; 1437c478bd9Sstevel@tonic-gate } 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate krb5_kt_free_entry(context, &kte); 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate /* If the creds are for the server principal, we're set, just do 1487c478bd9Sstevel@tonic-gate a mk_req. Otherwise, do a get_credentials first. */ 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate if (krb5_principal_compare(context, server, creds->server)) { 1517c478bd9Sstevel@tonic-gate /* make an ap_req */ 152505d05c7Sgtb if ((ret = krb5_mk_req_extended(context, &authcon, 0, NULL, creds, 153505d05c7Sgtb &ap_req))) 1547c478bd9Sstevel@tonic-gate goto cleanup; 1557c478bd9Sstevel@tonic-gate } else { 1567c478bd9Sstevel@tonic-gate /* this is unclean, but it's the easiest way without ripping the 1577c478bd9Sstevel@tonic-gate library into very small pieces. store the client's initial cred 1587c478bd9Sstevel@tonic-gate in a memory ccache, then call the library. Later, we'll copy 1597c478bd9Sstevel@tonic-gate everything except the initial cred into the ccache we return to 1607c478bd9Sstevel@tonic-gate the user. A clean implementation would involve library 1617c478bd9Sstevel@tonic-gate internals with a coherent idea of "in" and "out". */ 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate /* insert the initial cred into the ccache */ 1647c478bd9Sstevel@tonic-gate 165505d05c7Sgtb if ((ret = krb5_cc_resolve(context, "MEMORY:rd_req", &ccache))) 1667c478bd9Sstevel@tonic-gate goto cleanup; 167159d09a2SMark Phalan /* Solaris Kerberos */ 168*940daf74SToomas Soome if ((ret = krb5_cc_initialize(context, ccache, creds->client)) != 0) 1697c478bd9Sstevel@tonic-gate goto cleanup; 1707c478bd9Sstevel@tonic-gate 171159d09a2SMark Phalan /* Solaris Kerberos */ 172*940daf74SToomas Soome if ((ret = krb5_cc_store_cred(context, ccache, creds)) != 0) 1737c478bd9Sstevel@tonic-gate goto cleanup; 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate /* set up for get_creds */ 1767c478bd9Sstevel@tonic-gate memset(&in_creds, 0, sizeof(in_creds)); 1777c478bd9Sstevel@tonic-gate in_creds.client = creds->client; 1787c478bd9Sstevel@tonic-gate in_creds.server = server; 179505d05c7Sgtb if ((ret = krb5_timeofday(context, &in_creds.times.endtime))) 1807c478bd9Sstevel@tonic-gate goto cleanup; 1817c478bd9Sstevel@tonic-gate in_creds.times.endtime += 5*60; 1827c478bd9Sstevel@tonic-gate 183505d05c7Sgtb if ((ret = krb5_get_credentials(context, 0, ccache, &in_creds, 184505d05c7Sgtb &out_creds))) 1857c478bd9Sstevel@tonic-gate goto cleanup; 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate /* make an ap_req */ 188505d05c7Sgtb if ((ret = krb5_mk_req_extended(context, &authcon, 0, NULL, out_creds, 189505d05c7Sgtb &ap_req))) 1907c478bd9Sstevel@tonic-gate goto cleanup; 1917c478bd9Sstevel@tonic-gate } 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate /* wipe the auth context for mk_req */ 1947c478bd9Sstevel@tonic-gate if (authcon) { 1957c478bd9Sstevel@tonic-gate krb5_auth_con_free(context, authcon); 1967c478bd9Sstevel@tonic-gate authcon = NULL; 1977c478bd9Sstevel@tonic-gate } 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate /* verify the ap_req */ 2007c478bd9Sstevel@tonic-gate 201505d05c7Sgtb if ((ret = krb5_rd_req(context, &authcon, &ap_req, server, keytab, 202505d05c7Sgtb NULL, NULL))) 2037c478bd9Sstevel@tonic-gate goto cleanup; 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate /* if we get this far, then the verification succeeded. We can 2067c478bd9Sstevel@tonic-gate still fail if the library stuff here fails, but that's it */ 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate if (ccache_arg && ccache) { 2097c478bd9Sstevel@tonic-gate if (*ccache_arg == NULL) { 2107c478bd9Sstevel@tonic-gate krb5_ccache retcc; 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate retcc = NULL; 2137c478bd9Sstevel@tonic-gate 214159d09a2SMark Phalan /* Solaris Kerberos */ 215*940daf74SToomas Soome if (((ret = krb5_cc_resolve(context, "MEMORY:rd_req2", &retcc)) != 0) || 216*940daf74SToomas Soome ((ret = krb5_cc_initialize(context, retcc, creds->client)) != 0) || 2177c478bd9Sstevel@tonic-gate ((ret = krb5_cc_copy_creds_except(context, ccache, retcc, 218*940daf74SToomas Soome creds->server)) != 0)) { 219159d09a2SMark Phalan /* Solaris Kerberos */ 2207c478bd9Sstevel@tonic-gate if (retcc) 2217c478bd9Sstevel@tonic-gate (void) krb5_cc_destroy(context, retcc); 2227c478bd9Sstevel@tonic-gate } else { 2237c478bd9Sstevel@tonic-gate *ccache_arg = retcc; 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate } else { 2267c478bd9Sstevel@tonic-gate ret = krb5_cc_copy_creds_except(context, ccache, *ccache_arg, 2277c478bd9Sstevel@tonic-gate server); 2287c478bd9Sstevel@tonic-gate } 2297c478bd9Sstevel@tonic-gate } 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate /* if any of the above paths returned an errors, then ret is set 2327c478bd9Sstevel@tonic-gate accordingly. either that, or it's zero, which is fine, too */ 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate cleanup: 2357c478bd9Sstevel@tonic-gate if (!server_arg && server) 2367c478bd9Sstevel@tonic-gate krb5_free_principal(context, server); 237159d09a2SMark Phalan /* Solaris Kerberos */ 2387c478bd9Sstevel@tonic-gate if (!keytab_arg && keytab) 2397c478bd9Sstevel@tonic-gate (void) krb5_kt_close(context, keytab); 240159d09a2SMark Phalan /* Solaris Kerberos */ 2417c478bd9Sstevel@tonic-gate if (ccache) 2427c478bd9Sstevel@tonic-gate (void) krb5_cc_destroy(context, ccache); 2437c478bd9Sstevel@tonic-gate if (out_creds) 2447c478bd9Sstevel@tonic-gate krb5_free_creds(context, out_creds); 2457c478bd9Sstevel@tonic-gate if (authcon) 2467c478bd9Sstevel@tonic-gate krb5_auth_con_free(context, authcon); 2477c478bd9Sstevel@tonic-gate if (ap_req.data) 2487c478bd9Sstevel@tonic-gate krb5_xfree(ap_req.data); 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate return(ret); 2517c478bd9Sstevel@tonic-gate } 252