static void test_locate_kdc(krb5_context ctx, char *realm) { struct serverlist servers; size_t i; int get_masters = FALSE; krb5_data rlm; krb5_error_code retval; rlm.data = realm; rlm.length = strlen(realm); retval = k5_locate_kdc(ctx, &rlm, &servers, get_masters, 0); if (retval) { com_err("krb5_locate_kdc", retval, 0); return; } printf("krb_locate_kdc(%s) returned:", realm); for (i = 0; i < servers.nservers; i++) { struct server_entry *entry = &servers.servers[i]; if (entry->hostname) { printf(" host:%s/%d", entry->hostname, ntohs(entry->port)); continue; } switch (entry->family) { case AF_INET: { struct sockaddr_in *s_sin = (struct sockaddr_in *)&entry->addr; printf(" inet:%s/%d", inet_ntoa(s_sin->sin_addr), ntohs(s_sin->sin_port)); } break; case AF_INET6: { struct sockaddr_in6 *s_sin6 = (struct sockaddr_in6 *)&entry->addr; int j; printf(" inet6"); for (j = 0; j < 8; j++) printf(":%x", (s_sin6->sin6_addr.s6_addr[2*j] * 256 + s_sin6->sin6_addr.s6_addr[2*j+1])); printf("/%d", ntohs(s_sin6->sin6_port)); break; } default: printf(" unknown-af-%d", entry->family); break; } } k5_free_serverlist(&servers); printf("\n"); }
krb5_error_code krb5_sendto_kdc(krb5_context context, const krb5_data *message, const krb5_data *realm, krb5_data *reply, int *use_master, int no_udp) { krb5_error_code retval, err; struct serverlist servers; int server_used; k5_transport_strategy strategy; /* * 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. */ TRACE_SENDTO_KDC(context, message->length, realm, *use_master, no_udp); if (!no_udp && context->udp_pref_limit < 0) { int tmp; retval = profile_get_integer(context->profile, KRB5_CONF_LIBDEFAULTS, KRB5_CONF_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; } if (no_udp) strategy = NO_UDP; else if (message->length <= (unsigned int) context->udp_pref_limit) strategy = UDP_FIRST; else strategy = UDP_LAST; retval = k5_locate_kdc(context, realm, &servers, *use_master, no_udp); if (retval) return retval; err = 0; retval = k5_sendto(context, message, realm, &servers, strategy, NULL, reply, NULL, NULL, &server_used, check_for_svc_unavailable, &err); if (retval == KRB5_KDC_UNREACH) { if (err == KDC_ERR_SVC_UNAVAILABLE) { retval = KRB5KDC_ERR_SVC_UNAVAILABLE; } else { k5_setmsg(context, retval, _("Cannot contact any KDC for realm '%.*s'"), realm->length, realm->data); } } if (retval) goto cleanup; /* Set use_master to 1 if we ended up talking to a master when we didn't * explicitly request to. */ if (*use_master == 0) { *use_master = k5_kdc_is_master(context, realm, &servers.servers[server_used]); TRACE_SENDTO_KDC_MASTER(context, *use_master); } cleanup: k5_free_serverlist(&servers); 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", &sl, htons(88)); break; case LOOKUP_DNS: err = locate_srv_dns_1(&realm, "_kerberos", "_udp", &sl); break; case LOOKUP_WHATEVER: err = k5_locate_kdc(ctx, &realm, &sl, master, FALSE); break; } if (err) kfatal (err); print_addrs(); k5_free_serverlist(&sl); krb5_free_context(ctx); return 0; }
krb5_error_code krb5_sendto_kdc(krb5_context context, const krb5_data *message, const krb5_data *realm, krb5_data *reply, int *use_master, int tcp_only) { krb5_error_code retval, err; struct serverlist servers; int socktype1 = 0, socktype2 = 0, server_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. */ dprint("krb5_sendto_kdc(%d@%p, \"%D\", use_master=%d, tcp_only=%d)\n", message->length, message->data, realm, *use_master, tcp_only); TRACE_SENDTO_KDC(context, message->length, realm, *use_master, tcp_only); if (!tcp_only && context->udp_pref_limit < 0) { int tmp; retval = profile_get_integer(context->profile, KRB5_CONF_LIBDEFAULTS, KRB5_CONF_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; } if (tcp_only) socktype1 = SOCK_STREAM, socktype2 = 0; else if (message->length <= (unsigned int) context->udp_pref_limit) socktype1 = SOCK_DGRAM, socktype2 = SOCK_STREAM; else socktype1 = SOCK_STREAM, socktype2 = SOCK_DGRAM; retval = k5_locate_kdc(context, realm, &servers, *use_master, tcp_only ? SOCK_STREAM : 0); if (retval) return retval; retval = k5_sendto(context, message, &servers, socktype1, socktype2, NULL, reply, NULL, NULL, &server_used, check_for_svc_unavailable, &err); if (retval == KRB5_KDC_UNREACH) { if (err == KDC_ERR_SVC_UNAVAILABLE) { retval = KRB5KDC_ERR_SVC_UNAVAILABLE; } else { krb5_set_error_message(context, retval, "Cannot contact any KDC for realm '%.*s'", realm->length, realm->data); } } if (retval) goto cleanup; /* 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 serverlist mservers; struct server_entry *entry = &servers.servers[server_used]; retval = k5_locate_kdc(context, realm, &mservers, TRUE, entry->socktype); if (retval == 0) { if (in_addrlist(entry, &mservers)) *use_master = 1; k5_free_serverlist(&mservers); } TRACE_SENDTO_KDC_MASTER(context, *use_master); retval = 0; } cleanup: k5_free_serverlist(&servers); return retval; }