Esempio n. 1
0
/*
 * Decrypt the ticket in req using an entry in keytab matching server (if
 * given).  Set req->ticket->server to the principal of the keytab entry used.
 * Store the decrypting key in *keyblock_out if it is not NULL.
 */
static krb5_error_code
decrypt_ticket(krb5_context context, const krb5_ap_req *req,
               krb5_const_principal server, krb5_keytab keytab,
               krb5_keyblock *keyblock_out)
{
    krb5_error_code ret;
    krb5_keytab_entry ent;
    krb5_kt_cursor cursor;

#ifdef LEAN_CLIENT
    return KRB5KRB_AP_WRONG_PRINC;
#else
    /* If we have an explicit server principal, try just that one. */
    if (!is_matching(context, server))
        return try_one_princ(context, req, server, keytab, keyblock_out);

    if (keytab->ops->start_seq_get == NULL) {
        /* We can't iterate over the keytab.  Try the principal asserted by the
         * client if it's allowed by the server parameter. */
        if (!krb5_sname_match(context, server, req->ticket->server))
            return KRB5KRB_AP_WRONG_PRINC;
        return try_one_princ(context, req, req->ticket->server, keytab,
                             keyblock_out);
    }

    ret = krb5_kt_start_seq_get(context, keytab, &cursor);
    if (ret)
        goto cleanup;

    while ((ret = krb5_kt_next_entry(context, keytab, &ent, &cursor)) == 0) {
        if (ent.key.enctype == req->ticket->enc_part.enctype &&
            krb5_sname_match(context, server, ent.principal)) {
            ret = try_one_entry(context, req, &ent, keyblock_out);
            if (ret == 0) {
                TRACE_RD_REQ_DECRYPT_ANY(context, ent.principal, &ent.key);
                (void)krb5_free_keytab_entry_contents(context, &ent);
                break;
            }
        }

        (void)krb5_free_keytab_entry_contents(context, &ent);
    }

    (void)krb5_kt_end_seq_get(context, keytab, &cursor);

cleanup:
    switch (ret) {
    case KRB5_KT_KVNONOTFOUND:
    case KRB5_KT_NOTFOUND:
    case KRB5_KT_END:
    case KRB5KRB_AP_ERR_BAD_INTEGRITY:
        ret = KRB5KRB_AP_WRONG_PRINC;
        break;
    default:
        break;
    }

    return ret;
#endif /* LEAN_CLIENT */
}
Esempio n. 2
0
/* Decrypt the ticket in req using a principal looked up from keytab. */
static krb5_error_code
try_one_princ(krb5_context context, const krb5_ap_req *req,
              krb5_const_principal princ, krb5_keytab keytab,
              krb5_keyblock *keyblock_out)
{
    krb5_error_code ret;
    krb5_keytab_entry ent;

    ret = krb5_kt_get_entry(context, keytab, princ,
                            req->ticket->enc_part.kvno,
                            req->ticket->enc_part.enctype, &ent);
    if (ret)
        return ret;
    ret = try_one_entry(context, req, &ent, keyblock_out);
    if (ret == 0)
        TRACE_RD_REQ_DECRYPT_SPECIFIC(context, ent.principal, &ent.key);
    (void)krb5_free_keytab_entry_contents(context, &ent);
    if (ret)
        return ret;

    return 0;
}
Esempio n. 3
0
/* Decrypt the ticket in req using a principal looked up from keytab.
 * explicit_server should be true if this is the only usable principal. */
static krb5_error_code
try_one_princ(krb5_context context, const krb5_ap_req *req,
              krb5_const_principal princ, krb5_keytab keytab,
              krb5_boolean explicit_server, krb5_keyblock *keyblock_out)
{
    krb5_error_code ret;
    krb5_keytab_entry ent;
    krb5_kvno tkt_kvno = req->ticket->enc_part.kvno;
    krb5_enctype tkt_etype = req->ticket->enc_part.enctype;
    krb5_principal tkt_server = req->ticket->server;

    ret = krb5_kt_get_entry(context, keytab, princ, tkt_kvno, tkt_etype, &ent);
    if (ret) {
        return keytab_fetch_error(context, ret, princ, tkt_server, tkt_kvno,
                                  explicit_server);
    }
    ret = try_one_entry(context, req, &ent, keyblock_out);
    if (ret == 0)
        TRACE_RD_REQ_DECRYPT_SPECIFIC(context, ent.principal, &ent.key);
    (void)krb5_free_keytab_entry_contents(context, &ent);
    if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY)
        return integrity_error(context, princ, req->ticket->server);
    return ret;
}
Esempio n. 4
0
/*
 * Decrypt the ticket in req using an entry in keytab matching server (if
 * given).  Set req->ticket->server to the principal of the keytab entry used.
 * Store the decrypting key in *keyblock_out if it is not NULL.
 */
static krb5_error_code
decrypt_ticket(krb5_context context, const krb5_ap_req *req,
               krb5_const_principal server, krb5_keytab keytab,
               krb5_keyblock *keyblock_out)
{
    krb5_error_code ret;
    krb5_keytab_entry ent;
    krb5_kt_cursor cursor;
    krb5_principal tkt_server = req->ticket->server;
    krb5_kvno tkt_kvno = req->ticket->enc_part.kvno;
    krb5_enctype tkt_etype = req->ticket->enc_part.enctype;
    krb5_boolean similar_enctype;
    krb5_boolean tkt_server_mismatch = FALSE, found_server_match = FALSE;
    krb5_boolean found_tkt_server = FALSE, found_enctype = FALSE;
    krb5_boolean found_kvno = FALSE, found_higher_kvno = FALSE;

#ifdef LEAN_CLIENT
    return KRB5KRB_AP_WRONG_PRINC;
#else
    /* If we have an explicit server principal, try just that one. */
    if (!is_matching(context, server)) {
        return try_one_princ(context, req, server, keytab, TRUE,
                             keyblock_out);
    }

    if (keytab->ops->start_seq_get == NULL) {
        /* We can't iterate over the keytab.  Try the principal asserted by the
         * client if it's allowed by the server parameter. */
        if (!krb5_sname_match(context, server, tkt_server))
            return nomatch_error(context, server, tkt_server);
        return try_one_princ(context, req, tkt_server, keytab, FALSE,
                             keyblock_out);
    }

    /* Scan all keys in the keytab, in case the ticket server is an alias for
     * one of the principals in the keytab. */
    ret = krb5_kt_start_seq_get(context, keytab, &cursor);
    if (ret) {
        k5_change_error_message_code(context, ret, KRB5KRB_AP_ERR_NOKEY);
        return KRB5KRB_AP_ERR_NOKEY;
    }
    while ((ret = krb5_kt_next_entry(context, keytab, &ent, &cursor)) == 0) {
        /* Only try keys which match the server principal. */
        if (!krb5_sname_match(context, server, ent.principal)) {
            if (krb5_principal_compare(context, ent.principal, tkt_server))
                tkt_server_mismatch = TRUE;
            continue;
        }
        found_server_match = TRUE;

        if (krb5_c_enctype_compare(context, ent.key.enctype, tkt_etype,
                                   &similar_enctype) != 0)
            similar_enctype = FALSE;

        if (krb5_principal_compare(context, ent.principal, tkt_server)) {
            found_tkt_server = TRUE;
            if (ent.vno == tkt_kvno) {
                found_kvno = TRUE;
                if (similar_enctype)
                    found_enctype = TRUE;
            } else if (ent.vno > tkt_kvno) {
                found_higher_kvno = TRUE;
            }
        }

        /* Only try keys with similar enctypes to the ticket enctype. */
        if (similar_enctype) {
            /* Coerce inexact matches to the request enctype. */
            ent.key.enctype = tkt_etype;
            if (try_one_entry(context, req, &ent, keyblock_out) == 0) {
                TRACE_RD_REQ_DECRYPT_ANY(context, ent.principal, &ent.key);
                (void)krb5_free_keytab_entry_contents(context, &ent);
                break;
            }
        }

        (void)krb5_free_keytab_entry_contents(context, &ent);
    }

    (void)krb5_kt_end_seq_get(context, keytab, &cursor);

    if (ret != KRB5_KT_END)
        return ret;
    return iteration_error(context, server, tkt_server, tkt_kvno, tkt_etype,
                           tkt_server_mismatch, found_server_match,
                           found_tkt_server, found_kvno, found_higher_kvno,
                           found_enctype);
#endif /* LEAN_CLIENT */
}