Ejemplo n.º 1
0
static krb5_error_code
check_reply_server(krb5_context context, krb5_flags kdcoptions,
                   krb5_creds *in_cred, krb5_kdc_rep *dec_rep)
{

    if (!krb5_principal_compare(context, dec_rep->ticket->server,
                                dec_rep->enc_part2->server))
        return KRB5_KDCREP_MODIFIED;

    /* Reply is self-consistent. */

    if (krb5_principal_compare(context, dec_rep->ticket->server,
                               in_cred->server))
        return 0;

    /* Server in reply differs from what we requested. */

    if (kdcoptions & KDC_OPT_CANONICALIZE) {
        /* in_cred server differs from ticket returned, but ticket
           returned is consistent and we requested canonicalization. */
#if 0
#ifdef DEBUG_REFERRALS
        printf("gc_via_tkt: in_cred and encoding don't match but referrals requested\n");
        krb5int_dbgref_dump_principal("gc_via_tkt: in_cred",in_cred->server);
        krb5int_dbgref_dump_principal("gc_via_tkt: encoded server",dec_rep->enc_part2->server);
#endif
#endif
        return 0;
    }

    /* We didn't request canonicalization. */

    if (!IS_TGS_PRINC(context, in_cred->server) ||
        !IS_TGS_PRINC(context, dec_rep->ticket->server)) {
        /* Canonicalization not requested, and not a TGS referral. */
        return KRB5_KDCREP_MODIFIED;
    }
#if 0
    /*
     * Is this check needed?  find_nxt_kdc() in gc_frm_kdc.c already
     * effectively checks this.
     */
    if (krb5_realm_compare(context, in_cred->client, in_cred->server) &&
        data_eq(*in_cred->server->data[1], *in_cred->client->realm)) {
        /* Attempted to rewrite local TGS. */
        return KRB5_KDCREP_MODIFIED;
    }
#endif
    return 0;
}
Ejemplo n.º 2
0
krb5_error_code
krb5_walk_realm_tree(krb5_context context, const krb5_data *client, const krb5_data *server, krb5_principal **tree, int realm_branch_char)
{
    krb5_error_code retval;
    krb5_principal *rettree;
    register char *ccp, *scp;
    register char *prevccp = 0, *prevscp = 0;
    char *com_sdot = 0, *com_cdot = 0;
    register int i, links = 0;
    int clen, slen = -1;
    krb5_data tmpcrealm, tmpsrealm;
    int nocommon = 1;

#ifdef CONFIGURABLE_AUTHENTICATION_PATH
    const char *cap_names[4];
    char *cap_client, *cap_server;
    char **cap_nodes;
    krb5_error_code cap_code;
#endif

#ifdef DEBUG_REFERRALS
    printf("krb5_walk_realm_tree starting\n");
    printf("  client is %s\n",client->data);
    printf("  server is %s\n",server->data);
#endif

    if (!(client->data && server->data)) {
	/* Solaris Kerberos - enhance error message */
	if (!client->data && !server->data) {
	    krb5_set_error_message(context, KRB5_NO_TKT_IN_RLM,
				dgettext(TEXT_DOMAIN,
					"Cannot find ticket for requested realm: unknown client and server"));
	} else {
	    if (!client->data) {
		krb5_set_error_message(context, KRB5_NO_TKT_IN_RLM,
				    dgettext(TEXT_DOMAIN,
					    "Cannot find ticket for requested realm: unknown client"));
	    } else {
	       krb5_set_error_message(context, KRB5_NO_TKT_IN_RLM,
				    dgettext(TEXT_DOMAIN,
					    "Cannot find ticket for requested realm: unknown server"));
	    }
	}
	return KRB5_NO_TKT_IN_RLM;
    }
#ifdef CONFIGURABLE_AUTHENTICATION_PATH
    if ((cap_client = (char *)malloc(client->length + 1)) == NULL)
	return ENOMEM;
    strncpy(cap_client, client->data, client->length);
    cap_client[client->length] = '\0';
    if ((cap_server = (char *)malloc(server->length + 1)) == NULL) {
	krb5_xfree(cap_client);
	return ENOMEM;
    }
    strncpy(cap_server, server->data, server->length);
    cap_server[server->length] = '\0';
    cap_names[0] = "capaths";
    cap_names[1] = cap_client;
    cap_names[2] = cap_server;
    cap_names[3] = 0;
    cap_code = profile_get_values(context->profile, cap_names, &cap_nodes);
    krb5_xfree(cap_client);  /* done with client string */
    cap_names[1] = 0;
    if (cap_code == 0) {     /* found a path, so lets use it */
	links = 0;
	if (*cap_nodes[0] != '.') { /* a link of . means direct */
	    while(cap_nodes[links]) {
		links++;
	    }
	}
	if (cap_nodes[links] != NULL)
	    krb5_xfree(cap_nodes[links]);

	cap_nodes[links] = cap_server; /* put server on end of list */
	/* this simplifies the code later and make */
	/* cleanup eaiser as well */
	links++;		/* count the null entry at end */
    } else {			/* no path use hierarchical method */
	krb5_xfree(cap_server); /* failed, don't need server string */
	cap_names[2] = 0;
#endif
	clen = client->length;
	slen = server->length;

	for (com_cdot = ccp = client->data + clen - 1,
		 com_sdot = scp = server->data + slen - 1;
	     clen && slen && *ccp == *scp ;
	     ccp--, scp--, 	clen--, slen--) {
	    if (*ccp == realm_branch_char) {
		com_cdot = ccp;
		com_sdot = scp;
		nocommon = 0;
	    }
	}

	/* ccp, scp point to common root.
	   com_cdot, com_sdot point to common components. */
	/* handle case of one ran out */
	if (!clen) {
	    /* construct path from client to server, down the tree */
	    if (!slen) {
		/* in the same realm--this means there is no ticket
		   in this realm. */
	        krb5_set_error_message(context, KRB5_NO_TKT_IN_RLM,
				    dgettext(TEXT_DOMAIN,
					    "Cannot find ticket for requested realm: client is '%s', server is '%s'"),
				    client->data, server->data);
		return KRB5_NO_TKT_IN_RLM;
	    }
	    if (*scp == realm_branch_char) {
		/* one is a subdomain of the other */
		com_cdot = client->data;
		com_sdot = scp;
		nocommon = 0;
	    } /* else normal case of two sharing parents */
	}
	if (!slen) {
	    /* construct path from client to server, up the tree */
	    if (*ccp == realm_branch_char) {
		/* one is a subdomain of the other */
		com_sdot = server->data;
		com_cdot = ccp;
		nocommon = 0;
	    } /* else normal case of two sharing parents */
	}
	/* determine #links to/from common ancestor */
	if (nocommon)
	    links = 1;
	else
	    links = 2;
	/* if no common ancestor, artificially set up common root at the last
	   component, then join with special code */
	for (ccp = client->data; ccp < com_cdot; ccp++) {
	    if (*ccp == realm_branch_char) {
		links++;
		if (nocommon)
		    prevccp = ccp;
	    }
	}

	for (scp = server->data; scp < com_sdot; scp++) {
	    if (*scp == realm_branch_char) {
		links++;
		if (nocommon)
		    prevscp = scp;
	    }
	}
	if (nocommon) {
	    if (prevccp)
		com_cdot = prevccp;
	    if (prevscp)
		com_sdot = prevscp;

	    if(com_cdot == client->data + client->length -1)
		com_cdot = client->data - 1 ;
	    if(com_sdot == server->data + server->length -1)
		com_sdot = server->data - 1 ;
	}
#ifdef CONFIGURABLE_AUTHENTICATION_PATH
    }		/* end of if use hierarchical method */
#endif

    if (!(rettree = (krb5_principal *)calloc(links+2,
					     sizeof(krb5_principal)))) {
	return ENOMEM;
    }
    i = 1;
    if ((retval = krb5_tgtname(context, client, client, &rettree[0]))) {
	krb5_xfree(rettree);
	return retval;
    }
#ifdef CONFIGURABLE_AUTHENTICATION_PATH
    links--;				/* dont count the null entry on end */
    if (cap_code == 0) {    /* found a path above */
	tmpcrealm.data = client->data;
	tmpcrealm.length = client->length;
	while( i-1 <= links) {
			
	    tmpsrealm.data = cap_nodes[i-1];
	    /* don't count trailing whitespace from profile_get */
	    tmpsrealm.length = strcspn(cap_nodes[i-1],"\t ");
	    if ((retval = krb5_tgtname(context,
				       &tmpsrealm,
				       &tmpcrealm,
				       &rettree[i]))) {
		while (i) {
		    krb5_free_principal(context, rettree[i-1]);
		    i--;
		}
		krb5_xfree(rettree);
				/* cleanup the cap_nodes from profile_get */
		for (i = 0; i<=links; i++) {
		    krb5_xfree(cap_nodes[i]);
		}
		krb5_xfree((char *)cap_nodes);
		return retval;
	    }
	    tmpcrealm.data = tmpsrealm.data;	
	    tmpcrealm.length = tmpsrealm.length;
	    i++;
	}
	/* cleanup the cap_nodes from profile_get last one has server */
	for (i = 0; i<=links; i++) {
	    krb5_xfree(cap_nodes[i]);
	}
	krb5_xfree((char *)cap_nodes);
    } else {  /* if not cap then use hierarchical method */
#endif
	for (prevccp = ccp = client->data;
	     ccp <= com_cdot;
	     ccp++) {
	    if (*ccp != realm_branch_char)
		continue;
	    ++ccp;				/* advance past dot */
	    tmpcrealm.data = prevccp;
	    tmpcrealm.length = client->length -
		(prevccp - client->data);
	    tmpsrealm.data = ccp;
	    tmpsrealm.length = client->length -
		(ccp - client->data);
	    if ((retval = krb5_tgtname(context, &tmpsrealm, &tmpcrealm,
				       &rettree[i]))) {
		while (i) {
		    krb5_free_principal(context, rettree[i-1]);
		    i--;
		}
		krb5_xfree(rettree);
		return retval;
	    }
	    prevccp = ccp;
	    i++;
	}
	if (nocommon) {
	    tmpcrealm.data = com_cdot + 1;
	    tmpcrealm.length = client->length -
		(com_cdot + 1 - client->data);
	    tmpsrealm.data = com_sdot + 1;
	    tmpsrealm.length = server->length -
		(com_sdot + 1 - server->data);
	    if ((retval = krb5_tgtname(context, &tmpsrealm, &tmpcrealm,
				       &rettree[i]))) {
		while (i) {
		    krb5_free_principal(context, rettree[i-1]);
		    i--;
		}
		krb5_xfree(rettree);
		return retval;
	    }
	    i++;
	}

	for (prevscp = com_sdot + 1, scp = com_sdot - 1;
	     scp > server->data;
	     scp--) {
	    if (*scp != realm_branch_char)
		continue;
	    if (scp - 1 < server->data)
		break;			/* XXX only if . starts realm? */
	    tmpcrealm.data = prevscp;
	    tmpcrealm.length = server->length -
		(prevscp - server->data);
	    tmpsrealm.data = scp + 1;
	    tmpsrealm.length = server->length -
		(scp + 1 - server->data);
	    if ((retval = krb5_tgtname(context, &tmpsrealm, &tmpcrealm,
				       &rettree[i]))) {
		while (i) {
		    krb5_free_principal(context, rettree[i-1]);
		    i--;
		}
		krb5_xfree(rettree);
		return retval;
	    }
	    prevscp = scp + 1;
	    i++;
	}
	if (slen && com_sdot >= server->data) {
	    /* only necessary if building down tree from ancestor or client */
	    /* however, we can get here if we have only one component
	       in the server realm name, hence we make sure we found a component
	       separator there... */
	    tmpcrealm.data = prevscp;
	    tmpcrealm.length = server->length -
		(prevscp - server->data);
	    if ((retval = krb5_tgtname(context, server, &tmpcrealm,
				       &rettree[i]))) {
		while (i) {
		    krb5_free_principal(context, rettree[i-1]);
		    i--;
		}
		krb5_xfree(rettree);
		return retval;
	    }
	}
#ifdef CONFIGURABLE_AUTHENTICATION_PATH
    }
#endif
    *tree = rettree;

#ifdef DEBUG_REFERRALS
    printf("krb5_walk_realm_tree ending; tree (length %d) is:\n",links);
    for(i=0;i<links+2;i++) {
        if ((*tree)[i])
	    krb5int_dbgref_dump_principal("krb5_walk_realm_tree tree",(*tree)[i]);
	else
	    printf("tree element %i null\n");
    }
#endif
    return 0;
}
Ejemplo n.º 3
0
krb5_error_code KRB5_CALLCONV
krb5_sname_to_principal(krb5_context context, const char *hostname, const char *sname, krb5_int32 type, krb5_principal *ret_princ)
{
    char **hrealms, *realm, *remote_host;
    krb5_error_code retval;
    register char *cp;
    char localname[MAXHOSTNAMELEN];

#ifdef DEBUG_REFERRALS
    printf("krb5_sname_to_principal(host=%s, sname=%s, type=%d)\n",hostname,sname,type);
    printf("      name types: 0=unknown, 3=srv_host\n");
#endif

    if ((type == KRB5_NT_UNKNOWN) ||
            (type == KRB5_NT_SRV_HST)) {

        /* if hostname is NULL, use local hostname */
        if (! hostname) {
            if (gethostname(localname, MAXHOSTNAMELEN))
                return SOCKET_ERRNO;
            hostname = localname;
        }

        /* if sname is NULL, use "host" */
        if (! sname)
            sname = "host";

        /* copy the hostname into non-volatile storage */

        if (type == KRB5_NT_SRV_HST) {
            struct addrinfo *ai, hints;
            int err;
            char hnamebuf[NI_MAXHOST];

            /* Note that the old code would accept numeric addresses,
               and if the gethostbyaddr step could convert them to
               real hostnames, you could actually get reasonable
               results.  If the mapping failed, you'd get dotted
               triples as realm names.  *sigh*

               The latter has been fixed in hst_realm.c, but we should
               keep supporting numeric addresses if they do have
               hostnames associated.  */

            memset(&hints, 0, sizeof(hints));
            hints.ai_family = AF_INET;
            hints.ai_flags = AI_CANONNAME;
try_getaddrinfo_again:
            err = getaddrinfo(hostname, 0, &hints, &ai);
            if (err) {
#ifdef DEBUG_REFERRALS
                printf("sname_to_princ: probably punting due to bad hostname of %s\n",hostname);
#endif
                if (hints.ai_family == AF_INET) {
                    /* Just in case it's an IPv6-only name.  */
                    hints.ai_family = 0;
                    goto try_getaddrinfo_again;
                }
                return KRB5_ERR_BAD_HOSTNAME;
            }
            remote_host = strdup(ai->ai_canonname ? ai->ai_canonname : hostname);
            if (!remote_host) {
                freeaddrinfo(ai);
                return ENOMEM;
            }

            if (maybe_use_reverse_dns(context, DEFAULT_RDNS_LOOKUP)) {
                /*
                 * Do a reverse resolution to get the full name, just in
                 * case there's some funny business going on.  If there
                 * isn't an in-addr record, give up.
                 */
                /* XXX: This is *so* bogus.  There are several cases where
                   this won't get us the canonical name of the host, but
                   this is what we've trained people to expect.  We'll
                   probably fix it at some point, but let's try to
                   preserve the current behavior and only shake things up
                   once when it comes time to fix this lossage.  */
                err = getnameinfo(ai->ai_addr, ai->ai_addrlen,
                                  hnamebuf, sizeof(hnamebuf), 0, 0, NI_NAMEREQD);
                freeaddrinfo(ai);
                if (err == 0) {
                    free(remote_host);
                    remote_host = strdup(hnamebuf);
                    if (!remote_host)
                        return ENOMEM;
                }
            } else
                freeaddrinfo(ai);
        } else { /* type == KRB5_NT_UNKNOWN */
            remote_host = strdup(hostname);
        }
        if (!remote_host)
            return ENOMEM;
#ifdef DEBUG_REFERRALS
        printf("sname_to_princ: hostname <%s> after rdns processing\n",remote_host);
#endif

        if (type == KRB5_NT_SRV_HST)
            for (cp = remote_host; *cp; cp++)
                if (isupper((unsigned char) (*cp)))
                    *cp = tolower((unsigned char) (*cp));

        /*
         * Windows NT5's broken resolver gratuitously tacks on a
         * trailing period to the hostname (at least it does in
         * Beta2).  Find and remove it.
         */
        if (remote_host[0]) {
            cp = remote_host + strlen(remote_host)-1;
            if (*cp == '.')
                *cp = 0;
        }


        if ((retval = krb5_get_host_realm(context, remote_host, &hrealms))) {
            free(remote_host);
            return retval;
        }

#ifdef DEBUG_REFERRALS
        printf("sname_to_princ:  realm <%s> after krb5_get_host_realm\n",hrealms[0]);
#endif

        if (!hrealms[0]) {
            free(remote_host);
            free(hrealms);
            return KRB5_ERR_HOST_REALM_UNKNOWN;
        }
        realm = hrealms[0];

        retval = krb5_build_principal(context, ret_princ, strlen(realm),
                                      realm, sname, remote_host,
                                      (char *)0);
        if (retval == 0)
            krb5_princ_type(context, *ret_princ) = type;

#ifdef DEBUG_REFERRALS
        printf("krb5_sname_to_principal returning\n");
        printf("realm: <%s>, sname: <%s>, remote_host: <%s>\n",
               realm,sname,remote_host);
        krb5int_dbgref_dump_principal("krb5_sname_to_principal",*ret_princ);
#endif

        free(remote_host);

        krb5_free_host_realm(context, hrealms);
        return retval;
    } else {
        return KRB5_SNAME_UNSUPP_NAMETYPE;
    }
}
Ejemplo n.º 4
0
krb5_error_code
krb5_get_cred_via_tkt_ext(krb5_context context, krb5_creds *tkt,
                          krb5_flags kdcoptions, krb5_address *const *address,
                          krb5_pa_data **in_padata,
                          krb5_creds *in_cred,
                          krb5_error_code (*pacb_fct)(krb5_context,
                                                      krb5_keyblock *,
                                                      krb5_kdc_req *,
                                                      void *),
                          void *pacb_data,
                          krb5_pa_data ***out_padata,
                          krb5_pa_data ***out_enc_padata,
                          krb5_creds **out_cred,
                          krb5_keyblock **out_subkey)
{
    krb5_error_code retval;
    krb5_data request_data;
    krb5_data response_data;
    krb5_timestamp timestamp;
    krb5_int32 nonce;
    krb5_keyblock *subkey = NULL;
    int tcp_only = 0, use_master = 0;

    request_data.data = NULL;
    request_data.length = 0;
    response_data.data = NULL;
    response_data.length = 0;

#ifdef DEBUG_REFERRALS
    printf("krb5_get_cred_via_tkt starting; referral flag is %s\n", kdcoptions&KDC_OPT_CANONICALIZE?"on":"off");
    krb5int_dbgref_dump_principal("krb5_get_cred_via_tkt requested ticket", in_cred->server);
    krb5int_dbgref_dump_principal("krb5_get_cred_via_tkt TGT in use", tkt->server);
#endif

    retval = krb5int_make_tgs_request(context, tkt, kdcoptions,
                                      address, in_padata, in_cred,
                                      pacb_fct, pacb_data,
                                      &request_data, &timestamp, &nonce,
                                      &subkey);
    if (retval != 0)
        goto cleanup;

send_again:
    use_master = 0;
    retval = krb5_sendto_kdc(context, &request_data,
                             krb5_princ_realm(context, in_cred->server),
                             &response_data, &use_master, tcp_only);
    if (retval == 0) {
        if (krb5_is_krb_error(&response_data)) {
            if (!tcp_only) {
                krb5_error *err_reply;
                retval = decode_krb5_error(&response_data, &err_reply);
                if (retval != 0)
                    goto cleanup;
                if (err_reply->error == KRB_ERR_RESPONSE_TOO_BIG) {
                    tcp_only = 1;
                    krb5_free_error(context, err_reply);
                    krb5_free_data_contents(context, &response_data);
                    goto send_again;
                }
                krb5_free_error(context, err_reply);
            }
        }
    } else
        goto cleanup;

    retval = krb5int_process_tgs_reply(context, &response_data,
                                       tkt, kdcoptions, address,
                                       in_padata, in_cred,
                                       timestamp, nonce, subkey,
                                       out_padata,
                                       out_enc_padata, out_cred);
    if (retval != 0)
        goto cleanup;

cleanup:
#ifdef DEBUG_REFERRALS
    printf("krb5_get_cred_via_tkt ending; %s\n", retval?error_message(retval):"no error");
#endif

    krb5_free_data_contents(context, &request_data);
    krb5_free_data_contents(context, &response_data);

    if (subkey != NULL) {
        if (retval == 0 && out_subkey != NULL)
            *out_subkey = subkey;
        else
            krb5_free_keyblock(context, subkey);
    }

    return retval;
}