Пример #1
0
/*
 * Walk through the components of a domain.  At each stage determine
 * if a KDC can be located for that domain.  Return a realm
 * corresponding to the upper-cased domain name for which a KDC was
 * found or NULL if no KDC was found.  Stop searching after limit
 * labels have been removed from the domain (-1 means don't search at
 * all, 0 means try only the full domain itself, 1 means also try the
 * parent domain, etc.) or when we reach a parent with only one label.
 */
static krb5_error_code
domain_heuristic(krb5_context context, const char *domain,
		 char **realm, int limit)
{
    krb5_error_code retval = 0, r;
    struct addrlist alist;
    krb5_data drealm;
    char *cp = NULL;
    char *fqdn = NULL;

    *realm = NULL;
    if (limit < 0)
	return 0;

    memset(&drealm, 0, sizeof (drealm));
    if (!(fqdn = strdup(domain))) {
	retval = ENOMEM;
	goto cleanup;
    }

    /* Upper case the domain (for use as a realm) */
    for (cp = fqdn; *cp; cp++)
	if (islower((int)(*cp)))
	    *cp = toupper((int)*cp);

    /* Search up to limit parents, as long as we have multiple labels. */
    cp = fqdn;
    while (limit-- >= 0 && strchr(cp, '.') != NULL) {

	drealm.length = strlen(cp);
	drealm.data = cp;

	/* Find a kdc based on this part of the domain name. */
	r = krb5_locate_kdc(context, &drealm, &alist, 0, SOCK_DGRAM, 0);
	if (!r) { /* Found a KDC! */
	    krb5int_free_addrlist(&alist);
	    if (!(*realm = strdup(cp))) {
		retval = ENOMEM;
		goto cleanup;
	    }
	    break;
	}

	cp = strchr(cp, '.');
	cp++;
    }

cleanup:
    if (fqdn)
	free(fqdn);
    return retval;
}
int
main (int argc, char *argv[])
{
    char *p, *realmname;
    krb5_data realm;
    krb5_context ctx;
    krb5_error_code err;
    int master = 0;

    p = strrchr (argv[0], '/');
    if (p)
        prog = p+1;
    else
        prog = argv[0];

    switch (argc) {
    case 2:
        /* foo $realm */
        realmname = argv[1];
        break;
    case 3:
        if (!strcmp (argv[1], "-c"))
            how = LOOKUP_CONF;
        else if (!strcmp (argv[1], "-d"))
            how = LOOKUP_DNS;
        else if (!strcmp (argv[1], "-m"))
            master = 1;
        else
            goto usage;
        realmname = argv[2];
        break;
    default:
    usage:
        fprintf (stderr, "%s: usage: %s [-c | -d | -m] realm\n", prog, prog);
        return 1;
    }

    err = krb5_init_context (&ctx);
    if (err)
        kfatal (err);

    realm.data = realmname;
    realm.length = strlen (realmname);

    switch (how) {
    case LOOKUP_CONF:
        err = krb5_locate_srv_conf (ctx, &realm, "kdc", &al, 0,
                                    htons (88), htons (750));
        break;

    case LOOKUP_DNS:
        err = krb5_locate_srv_dns_1 (&realm, "_kerberos", "_udp", &al, 0);
        break;

    case LOOKUP_WHATEVER:
        err = krb5_locate_kdc (ctx, &realm, &al, master, 0, 0);
        break;
    }
    if (err) kfatal (err);
    print_addrs ();

    krb5int_free_addrlist (&al);
    krb5_free_context (ctx);
    return 0;
}
Пример #3
0
/*
 * Solaris Kerberos
 * Same as krb5_sendto_kdc plus an extra arg to return the FQDN
 * of the KDC sent the request.
 * Caller (at top of stack) needs to free hostname_used.
 */
krb5_error_code
krb5_sendto_kdc2 (krb5_context context, const krb5_data *message,
		 const krb5_data *realm, krb5_data *reply,
		int *use_master, int tcp_only, char **hostname_used)
{
    krb5_error_code retval, retval2;
    struct addrlist addrs = ADDRLIST_INIT;	/* Solaris Kerberos */
    int socktype1 = 0, socktype2 = 0, addr_used;

    /*
     * find KDC location(s) for realm
     */

    /*
     * BUG: This code won't return "interesting" errors (e.g., out of mem,
     * bad config file) from locate_kdc.  KRB5_REALM_CANT_RESOLVE can be
     * ignored from one query of two, but if only one query is done, or
     * both return that error, it should be returned to the caller.  Also,
     * "interesting" errors (not KRB5_KDC_UNREACH) from sendto_{udp,tcp}
     * should probably be returned as well.
     */

    /*LINTED*/
    dprint("krb5_sendto_kdc(%d@%p, \"%D\", use_master=%d, tcp_only=%d)\n",
    /*LINTED*/
	   message->length, message->data, realm, *use_master, tcp_only);

    if (!tcp_only && context->udp_pref_limit < 0) {
	int tmp;
	retval = profile_get_integer(context->profile,
				     "libdefaults", "udp_preference_limit", 0,
				     DEFAULT_UDP_PREF_LIMIT, &tmp);
	if (retval)
	    return retval;
	if (tmp < 0)
	    tmp = DEFAULT_UDP_PREF_LIMIT;
	else if (tmp > HARD_UDP_LIMIT)
	    /* In the unlikely case that a *really* big value is
	       given, let 'em use as big as we think we can
	       support.  */
	    tmp = HARD_UDP_LIMIT;
	context->udp_pref_limit = tmp;
    }

    retval = (*use_master ? KRB5_KDC_UNREACH : KRB5_REALM_UNKNOWN);

    if (tcp_only)
	socktype1 = SOCK_STREAM, socktype2 = 0;
    else if (message->length <= context->udp_pref_limit)
	socktype1 = SOCK_DGRAM, socktype2 = SOCK_STREAM;
    else
	socktype1 = SOCK_STREAM, socktype2 = SOCK_DGRAM;

    retval = krb5_locate_kdc(context, realm, &addrs, *use_master, socktype1, 0);
    if (socktype2) {
	struct addrlist addrs2;

	retval2 = krb5_locate_kdc(context, realm, &addrs2, *use_master,
				  socktype2, 0);
#if 0
	if (retval2 == 0) {
	    (void) merge_addrlists(&addrs, &addrs2);
	    krb5int_free_addrlist(&addrs2);
	    retval = 0;
	} else if (retval == KRB5_REALM_CANT_RESOLVE) {
	    retval = retval2;
	}
#else
	retval = retval2;
	if (retval == 0) {
	    (void) merge_addrlists(&addrs, &addrs2);
	    krb5int_free_addrlist(&addrs2);
	}
#endif
    }

    if (addrs.naddrs > 0) {
	krb5_error_code err = 0;

        retval = krb5int_sendto (context, message, &addrs, 0, reply, 0, 0,
				 0, 0, &addr_used, check_for_svc_unavailable, &err);
	switch (retval) {
	case 0:
            /*
             * Set use_master to 1 if we ended up talking to a master when
             * we didn't explicitly request to
             */
            if (*use_master == 0) {
                struct addrlist addrs3;
                retval = krb5_locate_kdc(context, realm, &addrs3, 1, 
                                         addrs.addrs[addr_used].ai->ai_socktype,
                                         addrs.addrs[addr_used].ai->ai_family);
                if (retval == 0) {
		    if (in_addrlist(addrs.addrs[addr_used].ai, &addrs3))
			*use_master = 1;
                    krb5int_free_addrlist (&addrs3);
                }
            }

	    if (hostname_used) {
		struct sockaddr *sa;
		char buf[NI_MAXHOST];
		int err;

		*hostname_used = NULL;
		sa = addrs.addrs[addr_used].ai->ai_addr;
		err = getnameinfo (sa, socklen (sa), buf, sizeof (buf), 0, 0,
				AI_CANONNAME);
		if (err)
		    err = getnameinfo (sa, socklen (sa), buf,
				    sizeof (buf), 0, 0,
				    NI_NUMERICHOST);
		if (!err)
		    *hostname_used = strdup(buf);
	            /* don't sweat strdup fail */
	    }
            krb5int_free_addrlist (&addrs);
            return 0;
	default:
	    break;
	    /* Cases here are for constructing useful error messages.  */
	case KRB5_KDC_UNREACH:
	    if (err == KDC_ERR_SVC_UNAVAILABLE) {
		retval = KRB5KDC_ERR_SVC_UNAVAILABLE;
	    } else {
		krb5_set_error_message(context, retval,
				    dgettext(TEXT_DOMAIN,
				    "Cannot contact any KDC for realm '%.*s'"),
				    realm->length, realm->data);
	    }
	    break;
	}
        krb5int_free_addrlist (&addrs);
    }
    return retval;
}