/* * 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; }
static int net_lookup_kdc(int argc, const char **argv) { #ifdef HAVE_KRB5 krb5_error_code rc; krb5_context ctx; struct sockaddr_in *addrs; int num_kdcs,i; krb5_data realm; char **realms; rc = krb5_init_context(&ctx); if (rc) { DEBUG(1,("krb5_init_context failed (%s)\n", error_message(rc))); return -1; } if (argc>0) { realm.data = (krb5_pointer) argv[0]; realm.length = strlen(argv[0]); } else if (lp_realm() && *lp_realm()) { realm.data = (krb5_pointer) lp_realm(); realm.length = strlen(realm.data); } else { rc = krb5_get_host_realm(ctx, NULL, &realms); if (rc) { DEBUG(1,("krb5_gethost_realm failed (%s)\n", error_message(rc))); return -1; } realm.data = (krb5_pointer) *realms; realm.length = strlen(realm.data); } rc = krb5_locate_kdc(ctx, &realm, &addrs, &num_kdcs, 0); if (rc) { DEBUG(1, ("krb5_locate_kdc failed (%s)\n", error_message(rc))); return -1; } for (i=0;i<num_kdcs;i++) if (addrs[i].sin_family == AF_INET) d_printf("%s:%hd\n", inet_ntoa(addrs[i].sin_addr), ntohs(addrs[i].sin_port)); return 0; #endif DEBUG(1, ("No kerberos support\n")); return -1; }
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; }
krb5_error_code smb_krb5_locate_kdc(krb5_context ctx, const krb5_data *realm, struct sockaddr **addr_pp, int *naddrs, int get_masters) { return krb5_locate_kdc(ctx, realm, addr_pp, naddrs, get_masters); }
/* * 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; }