Ejemplo n.º 1
0
krb5_error_code
k5_locate_server(krb5_context context, const krb5_data *realm,
                 struct serverlist *serverlist, enum locate_service_type svc,
                 int socktype)
{
    krb5_error_code code;
    struct serverlist al = SERVERLIST_INIT;

    *serverlist = al;

    if (realm == NULL || realm->data == NULL || realm->data[0] == 0) {
        krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE,
                               "Cannot find KDC for invalid realm name \"\"");
        return KRB5_REALM_CANT_RESOLVE;
    }

    code = module_locate_server(context, realm, &al, svc, socktype);
    Tprintf("module_locate_server returns %d\n", code);
    if (code == KRB5_PLUGIN_NO_HANDLE) {
        /*
         * We always try the local file before DNS.  Note that there
         * is no way to indicate "service not available" via the
         * config file.
         */

        code = prof_locate_server(context, realm, &al, svc, socktype);

#ifdef KRB5_DNS_LOOKUP
        if (code) {             /* Try DNS for all profile errors?  */
            krb5_error_code code2;
            code2 = dns_locate_server(context, realm, &al, svc, socktype);
            if (code2 != KRB5_PLUGIN_NO_HANDLE)
                code = code2;
        }
#endif /* KRB5_DNS_LOOKUP */

        /* We could put more heuristics here, like looking up a hostname
           of "kerberos."+REALM, etc.  */
    }
    if (code == 0)
        Tprintf ("krb5int_locate_server found %d addresses\n",
                 al.nservers);
    else
        Tprintf ("krb5int_locate_server returning error code %d/%s\n",
                 code, error_message(code));
    if (code != 0) {
        k5_free_serverlist(&al);
        return code;
    }
    if (al.nservers == 0) {       /* No good servers */
        k5_free_serverlist(&al);
        krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE,
                               _("Cannot resolve servers for KDC in realm "
                                 "\"%.*s\""), realm->length, realm->data);
        return KRB5_REALM_CANT_RESOLVE;
    }
    *serverlist = al;
    return 0;
}
Ejemplo n.º 2
0
krb5_error_code
k5_locate_server(krb5_context context, const krb5_data *realm,
                 struct serverlist *serverlist, enum locate_service_type svc,
                 krb5_boolean no_udp)
{
    krb5_error_code ret;
    k5_transport transport = no_udp ? TCP : TCP_OR_UDP;

    memset(serverlist, 0, sizeof(*serverlist));
    if (realm == NULL || realm->data == NULL || realm->data[0] == 0) {
        k5_setmsg(context, KRB5_REALM_CANT_RESOLVE,
                  "Cannot find KDC for invalid realm name \"\"");
        return KRB5_REALM_CANT_RESOLVE;
    }

    ret = locate_server(context, realm, serverlist, svc, transport);
    if (ret)
        return ret;

    if (serverlist->nservers == 0) {
        k5_free_serverlist(serverlist);
        k5_setmsg(context, KRB5_REALM_UNKNOWN,
                  _("Cannot find KDC for realm \"%.*s\""),
                  realm->length, realm->data);
        return KRB5_REALM_UNKNOWN;
    }
    return 0;
}
Ejemplo n.º 3
0
/*
 * Try all of the server location methods in sequence.  transport must be
 * TCP_OR_UDP, TCP, or UDP.  It is applied to hostname entries in the profile
 * and affects whether we query modules or DNS for UDP or TCP or both, but does
 * not restrict a method from returning entries of other transports.
 */
static krb5_error_code
locate_server(krb5_context context, const krb5_data *realm,
              struct serverlist *serverlist, enum locate_service_type svc,
              k5_transport transport)
{
    krb5_error_code ret;
    struct serverlist list = SERVERLIST_INIT;

    *serverlist = list;

    /* Try modules.  If a module returns 0 but leaves the list empty, return an
     * empty list. */
    ret = module_locate_server(context, realm, &list, svc, transport);
    if (ret != KRB5_PLUGIN_NO_HANDLE)
        goto done;

    /* Try the profile.  Fall back to DNS if it returns an empty list. */
    ret = prof_locate_server(context, realm, &list, svc, transport);
    if (ret)
        goto done;

#ifdef KRB5_DNS_LOOKUP
    if (list.nservers == 0)
        ret = dns_locate_server(context, realm, &list, svc, transport);
#endif

done:
    if (ret) {
        k5_free_serverlist(&list);
        return ret;
    }
    *serverlist = list;
    return 0;
}
Ejemplo n.º 4
0
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");
}
Ejemplo n.º 5
0
krb5_boolean
k5_kdc_is_master(krb5_context context, const krb5_data *realm,
                 struct server_entry *server)
{
    struct serverlist list;
    krb5_boolean found;

    if (locate_server(context, realm, &list, locate_service_master_kdc,
                      server->transport) != 0)
        return FALSE;
    found = server_list_contains(&list, server);
    k5_free_serverlist(&list);
    return found;
}
Ejemplo n.º 6
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 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;
}
Ejemplo n.º 7
0
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;
}
Ejemplo n.º 8
0
Archivo: changepw.c Proyecto: WeiY/krb5
/*
** The logic for setting and changing a password is mostly the same
** change_set_password handles both cases
**      if set_password_for is NULL, then a password change is performed,
**  otherwise, the password is set for the principal indicated in set_password_for
*/
static krb5_error_code
change_set_password(krb5_context context,
                    krb5_creds *creds,
                    char *newpw,
                    krb5_principal set_password_for,
                    int *result_code,
                    krb5_data *result_code_string,
                    krb5_data *result_string)
{
    krb5_data                   chpw_rep;
    krb5_address                remote_kaddr;
    krb5_boolean                use_tcp = 0;
    GETSOCKNAME_ARG3_TYPE       addrlen;
    krb5_error_code             code = 0;
    char                        *code_string;
    int                         local_result_code;

    struct sendto_callback_context  callback_ctx;
    struct sendto_callback_info callback_info;
    struct sockaddr_storage     remote_addr;
    struct serverlist           sl = SERVERLIST_INIT;

    memset(&chpw_rep, 0, sizeof(krb5_data));
    memset( &callback_ctx, 0, sizeof(struct sendto_callback_context));
    callback_ctx.context = context;
    callback_ctx.newpw = newpw;
    callback_ctx.set_password_for = set_password_for;

    if ((code = krb5_auth_con_init(callback_ctx.context,
                                   &callback_ctx.auth_context)))
        goto cleanup;

    if ((code = krb5_mk_req_extended(callback_ctx.context,
                                     &callback_ctx.auth_context,
                                     AP_OPTS_USE_SUBKEY,
                                     NULL,
                                     creds,
                                     &callback_ctx.ap_req)))
        goto cleanup;

    callback_ctx.remote_seq_num = callback_ctx.auth_context->remote_seq_number;
    callback_ctx.local_seq_num = callback_ctx.auth_context->local_seq_number;

    do {
        int socktype = (use_tcp ? SOCK_STREAM : SOCK_DGRAM);
        code = locate_kpasswd(callback_ctx.context, &creds->server->realm, &sl,
                              socktype);
        if (code)
            break;

        addrlen = sizeof(remote_addr);

        callback_info.data = &callback_ctx;
        callback_info.pfn_callback = kpasswd_sendto_msg_callback;
        callback_info.pfn_cleanup = kpasswd_sendto_msg_cleanup;
        krb5_free_data_contents(callback_ctx.context, &chpw_rep);

        code = k5_sendto(callback_ctx.context, NULL, &sl, socktype, 0,
                         &callback_info, &chpw_rep, ss2sa(&remote_addr),
                         &addrlen, NULL, NULL, NULL);
        if (code) {
            /*
             * Here we may want to switch to TCP on some errors.
             * right?
             */
            break;
        }

        if (remote_addr.ss_family == AF_INET) {
            remote_kaddr.addrtype = ADDRTYPE_INET;
            remote_kaddr.length = sizeof(ss2sin(&remote_addr)->sin_addr);
            remote_kaddr.contents =
                (krb5_octet *) &ss2sin(&remote_addr)->sin_addr;
        } else if (remote_addr.ss_family == AF_INET6) {
            remote_kaddr.addrtype = ADDRTYPE_INET6;
            remote_kaddr.length = sizeof(ss2sin6(&remote_addr)->sin6_addr);
            remote_kaddr.contents =
                (krb5_octet *) &ss2sin6(&remote_addr)->sin6_addr;
        } else {
            break;
        }

        if ((code = krb5_auth_con_setaddrs(callback_ctx.context,
                                           callback_ctx.auth_context,
                                           NULL,
                                           &remote_kaddr)))
            break;

        code = krb5int_rd_chpw_rep(callback_ctx.context,
                                   callback_ctx.auth_context,
                                   &chpw_rep, &local_result_code,
                                   result_string);

        if (code) {
            if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !use_tcp) {
                k5_free_serverlist(&sl);
                use_tcp = 1;
                continue;
            }

            break;
        }

        if (result_code)
            *result_code = local_result_code;

        if (result_code_string) {
            code = krb5_chpw_result_code_string(callback_ctx.context,
                                                local_result_code,
                                                &code_string);
            if (code)
                goto cleanup;

            result_code_string->length = strlen(code_string);
            result_code_string->data = malloc(result_code_string->length);
            if (result_code_string->data == NULL) {
                code = ENOMEM;
                goto cleanup;
            }
            strncpy(result_code_string->data, code_string, result_code_string->length);
        }

        if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !use_tcp) {
            k5_free_serverlist(&sl);
            use_tcp = 1;
        } else {
            break;
        }
    } while (TRUE);

cleanup:
    if (callback_ctx.auth_context != NULL)
        krb5_auth_con_free(callback_ctx.context, callback_ctx.auth_context);

    k5_free_serverlist(&sl);
    krb5_free_data_contents(callback_ctx.context, &callback_ctx.ap_req);
    krb5_free_data_contents(callback_ctx.context, &chpw_rep);

    return(code);
}
Ejemplo n.º 9
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;
}