summaryrefslogtreecommitdiffstats
path: root/src/kdc/do_tgs_req.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/kdc/do_tgs_req.c')
-rw-r--r--src/kdc/do_tgs_req.c172
1 files changed, 145 insertions, 27 deletions
diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c
index 9c96734e6a..5a349c8642 100644
--- a/src/kdc/do_tgs_req.c
+++ b/src/kdc/do_tgs_req.c
@@ -71,7 +71,6 @@
#include "extern.h"
#include "adm_proto.h"
-
static void find_alternate_tgs (krb5_kdc_req *, krb5_db_entry *,
krb5_boolean *, int *);
@@ -79,6 +78,9 @@ static krb5_error_code prepare_error_tgs (krb5_kdc_req *, krb5_ticket *,
int, krb5_principal,
krb5_data **, const char *);
+static krb5_boolean
+is_substr ( char *, krb5_data *);
+
/*ARGSUSED*/
krb5_error_code
process_tgs_req(krb5_data *pkt, const krb5_fulladdr *from,
@@ -104,10 +106,10 @@ process_tgs_req(krb5_data *pkt, const krb5_fulladdr *from,
krb5_key_data *server_key;
char *cname = 0, *sname = 0, *altcname = 0;
krb5_last_req_entry *nolrarray[2], nolrentry;
-/* krb5_address *noaddrarray[1]; */
krb5_enctype useenctype;
int errcode, errcode2;
register int i;
+ size_t len;
int firstpass = 1;
const char *status = 0;
krb5_enc_tkt_part *header_enc_tkt = NULL; /* ticket granting or evidence ticket */
@@ -117,8 +119,12 @@ process_tgs_req(krb5_data *pkt, const krb5_fulladdr *from,
krb5_authdata **kdc_issued_auth_data = NULL; /* auth data issued by KDC */
unsigned int c_flags = 0, s_flags = 0; /* client/server KDB flags */
char *s4u_name = NULL;
- krb5_boolean is_referral;
+ krb5_boolean is_referral, db_ref_done = FALSE;
const char *emsg = NULL;
+ char **realms, **cpp, *temp_buf=NULL;
+ krb5_data *comp1 = NULL, *comp2 = NULL;
+ krb5_data *tgs_1 =NULL, *server_1 = NULL;
+ krb5_principal krbtgt_princ;
session_key.contents = NULL;
@@ -133,14 +139,6 @@ process_tgs_req(krb5_data *pkt, const krb5_fulladdr *from,
krb5_free_kdc_req(kdc_context, request);
return retval;
}
-
- if ((errcode = krb5_unparse_name(kdc_context, request->server, &sname))) {
- status = "UNPARSING SERVER";
- goto cleanup;
- }
- limit_string(sname);
-
- /* errcode = kdc_process_tgs_req(request, from, pkt, &req_authdat); */
errcode = kdc_process_tgs_req(request, from, pkt, &header_ticket,
&krbtgt, &k_nprincs, &subkey);
if (header_ticket && header_ticket->enc_part2 &&
@@ -181,12 +179,21 @@ process_tgs_req(krb5_data *pkt, const krb5_fulladdr *from,
/* XXX make sure server here has the proper realm...taken from AP_REQ
header? */
- nprincs = 1;
if (isflagset(request->kdc_options, KDC_OPT_CANONICALIZE)) {
setflag(c_flags, KRB5_KDB_FLAG_CANONICALIZE);
setflag(s_flags, KRB5_KDB_FLAG_CANONICALIZE);
}
+ db_ref_done = FALSE;
+
+ref_tgt_again:
+ nprincs = 1;
+ if ((errcode = krb5_unparse_name(kdc_context, request->server, &sname))) {
+ status = "UNPARSING SERVER";
+ goto cleanup;
+ }
+ limit_string(sname);
+
errcode = krb5_db_get_principal_ext(kdc_context,
request->server,
s_flags,
@@ -208,21 +215,109 @@ tgt_again:
* might be a request for a TGT for some other realm; we
* should do our best to find such a TGS in this db
*/
- if (firstpass && krb5_is_tgs_principal(request->server) == TRUE) {
- if (krb5_princ_size(kdc_context, request->server) == 2) {
- krb5_data *server_1 =
- krb5_princ_component(kdc_context, request->server, 1);
- krb5_data *tgs_1 =
- krb5_princ_component(kdc_context, tgs_server, 1);
-
- if (!tgs_1 || !data_eq(*server_1, *tgs_1)) {
- krb5_db_free_principal(kdc_context, &server, nprincs);
- find_alternate_tgs(request, &server, &more, &nprincs);
- firstpass = 0;
- goto tgt_again;
- }
- }
- }
+ if (firstpass ) {
+
+ if ( krb5_is_tgs_principal(request->server) == TRUE) { /* Principal is a name of krb ticket service */
+ if (krb5_princ_size(kdc_context, request->server) == 2) {
+
+ server_1 = krb5_princ_component(kdc_context, request->server, 1);
+ tgs_1 = krb5_princ_component(kdc_context, tgs_server, 1);
+
+ if (!tgs_1 || !data_eq(*server_1, *tgs_1)) {
+ krb5_db_free_principal(kdc_context, &server, nprincs);
+ find_alternate_tgs(request, &server, &more, &nprincs);
+ firstpass = 0;
+ goto tgt_again;
+ }
+ }
+ krb5_db_free_principal(kdc_context, &server, nprincs);
+ status = "UNKNOWN_SERVER";
+ errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
+ goto cleanup;
+
+ } else if ( db_ref_done == FALSE) {
+
+ /* By now we know that server principal name is unknown <== nprincs!=1 from get_principal
+ * If CANONICALIZE flag is set in the request (1)
+ * If req is not U2U authn. req (2)
+ * the requested server princ. has exactly two components (3)
+ * either
+ * the name type is NT-SRV-HST (4.a)
+ * or name type is NT-UNKNOWN and
+ * the 1st component is listed in conf file under host_based_services (4.b)
+ * the 1st component is not in a list in conf under "no_host_referral" (5)
+ * the 2d component looks like fully-qualified domain name (FQDN) (6)
+ * If all of these conditions are satisfied - try mapping the FQDN and
+ * re-process the request as if client had asked for cross-realm TGT.
+ */
+
+ if (isflagset(request->kdc_options, KDC_OPT_CANONICALIZE) == TRUE && /* (1) */
+ !isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY) && /* (2) */
+ krb5_princ_size(kdc_context, request->server) == 2) { /* (3) */
+
+ comp1 = krb5_princ_component(kdc_context, request->server, 0);
+ comp2 = krb5_princ_component(kdc_context, request->server, 1);
+
+ if ((krb5_princ_type(kdc_context, request->server) == KRB5_NT_SRV_HST || /* (4.a) */
+ (krb5_princ_type(kdc_context, request->server) == KRB5_NT_UNKNOWN && /* (4.b) */
+ (is_substr(kdc_active_realm->realm_host_based_services, comp1)==TRUE ||
+ strchr(kdc_active_realm->realm_host_based_services, '*')))) &&
+ (kdc_active_realm->realm_no_host_referral == NULL ||
+ (!strchr(kdc_active_realm->realm_host_based_services, '*') &&
+ is_substr(kdc_active_realm->realm_no_host_referral,comp1)==FALSE))) { /* (5) */
+
+ for ( len=0; len < comp2->length; len++) {
+ if ( comp2->data[len] == '.' ) break;
+ }
+ if ( len == comp2->length) /* (6) */
+ goto cleanup;
+
+ /* try mapping FQDN or the containing domains */
+ temp_buf = calloc(1, comp2->length+1);
+ if ( !temp_buf){
+ retval = ENOMEM;
+ goto cleanup;
+ }
+ strncpy(temp_buf, comp2->data,comp2->length);
+ retval = krb5int_get_domain_realm_mapping(kdc_context, temp_buf, &realms);
+ free(temp_buf);
+ if (retval) {
+ /* no match found */
+ com_err("krb5_get_domain_realm_mapping", retval, 0);
+ goto cleanup;
+ }
+ if (realms == 0) {
+ printf(" (null)\n");
+ goto cleanup;
+ }
+ if (realms[0] == 0) {
+ printf(" (none)\n");
+ free(realms);
+ goto cleanup;
+ }
+ /* Modify request.
+ * Construct cross-realm tgt : krbtgt/REMOTE_REALM@LOCAL_REALM
+ * and use it as a principal in this req.
+ */
+ retval = krb5_build_principal(kdc_context, &krbtgt_princ,
+ (*request->server).realm.length,
+ (*request->server).realm.data,
+ "krbtgt", realms[0], (char *)0);
+
+ for (cpp = realms; *cpp; cpp++) free(*cpp);
+ krb5_free_principal(kdc_context, request->server);
+
+ retval = krb5_copy_principal(kdc_context, krbtgt_princ, &(request->server));
+ if ( retval == 0 ) {
+ db_ref_done = TRUE;
+ goto ref_tgt_again;
+ }
+ }
+ }
+ }
+ }
+
+
krb5_db_free_principal(kdc_context, &server, nprincs);
status = "UNKNOWN_SERVER";
errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
@@ -1015,3 +1110,26 @@ find_alternate_tgs(krb5_kdc_req *request, krb5_db_entry *server,
krb5_free_realm_tree(kdc_context, plist);
return;
}
+
+/* is_substr - verfies if d1 contains d2->data with head/trail-ing whitespaces
+ */
+static krb5_boolean
+is_substr ( char *d1, krb5_data *d2)
+{
+ krb5_boolean ret = FALSE;
+ char *new_d2 = 0, *d2_formated = 0;
+ if ( d1 && d2 && d2->data && (d2->length+2 <= strlen(d1))){
+ if ((new_d2 = calloc(1,d2->length+1))) {
+ strncpy(new_d2,d2->data,d2->length);
+ asprintf( &d2_formated, "%c%s%c", ' ', new_d2, ' ');
+ if ( d2_formated != 0 && strstr( d1, d2_formated) != NULL)
+ ret = TRUE;
+ free(new_d2);
+ free(d2_formated);
+ }
+ }
+ return ret;
+}
+
+
+