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
krb5_cc_copy_creds_except(krb5_context context,krb5_ccache incc,krb5_ccache outcc,krb5_principal princ)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
krb5_verify_init_creds(krb5_context context,krb5_creds * creds,krb5_principal server_arg,krb5_keytab keytab_arg,krb5_ccache * ccache_arg,krb5_verify_init_creds_opt * options)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