Beispiel #1
0
 BOOL kerberos_compatible_enctypes(krb5_context context,
				  krb5_enctype enctype1,
				  krb5_enctype enctype2)
{
#if defined(HAVE_KRB5_C_ENCTYPE_COMPARE)
	krb5_boolean similar = 0;

	krb5_c_enctype_compare(context, enctype1, enctype2, &similar);
	return similar ? True : False;
#elif defined(HAVE_KRB5_ENCTYPES_COMPATIBLE_KEYS)
	return krb5_enctypes_compatible_keys(context, enctype1, enctype2) ? True : False;
#endif
}
Beispiel #2
0
/* Determines Encryption and Salt types,
 * allocates key_salt data storage,
 * filters out equivalent encodings,
 * returns 0 if no enctypes available, >0 if enctypes are available */
static int prep_ksdata(krb5_context krbctx, const char *str,
                       struct keys_container *keys,
                       char **err_msg)
{
    struct krb_key_salt *ksdata;
    krb5_error_code krberr;
    int n, i, j, nkeys;

    *err_msg = NULL;

    if (str == NULL) {
        krb5_enctype *ktypes;

        krberr = krb5_get_permitted_enctypes(krbctx, &ktypes);
        if (krberr) {
            *err_msg = _("No system preferred enctypes ?!\n");
            return 0;
        }

        for (n = 0; ktypes[n]; n++) /* count */ ;

        ksdata = calloc(n + 1, sizeof(struct krb_key_salt));
        if (NULL == ksdata) {
            *err_msg = _("Out of memory!?\n");
            return 0;
        }

        for (i = 0; i < n; i++) {
            ksdata[i].enctype = ktypes[i];
            ksdata[i].salttype = KRB5_KDB_SALTTYPE_NORMAL;
        }

        ipa_krb5_free_ktypes(krbctx, ktypes);

        nkeys = i;

    } else {
        char *tmp, *t, *p, *q;

        t = tmp = strdup(str);
        if (!tmp) {
            *err_msg = _("Out of memory\n");
            return 0;
        }

        /* count */
        n = 0;
        while ((p = strchr(t, ','))) {
            t = p+1;
            n++;
        }
        n++; /* count the last one that is 0 terminated instead */

        /* at the end we will have at most n entries + 1 terminating */
        ksdata = calloc(n + 1, sizeof(struct krb_key_salt));
        if (!ksdata) {
            *err_msg = _("Out of memory\n");
            return 0;
        }

        for (i = 0, j = 0, t = tmp; i < n; i++) {

            p = strchr(t, ',');
            if (p) *p = '\0';

            q = strchr(t, ':');
            if (q) *q++ = '\0';

            krberr = krb5_string_to_enctype(t, &ksdata[j].enctype);
            if (krberr != 0) {
                *err_msg = _("Warning unrecognized encryption type.\n");
                if (p) t = p + 1;
                continue;
            }
            if (p) t = p + 1;

            if (!q) {
                ksdata[j].salttype = KRB5_KDB_SALTTYPE_NORMAL;
                j++;
                continue;
            }

            krberr = krb5_string_to_salttype(q, &ksdata[j].salttype);
            if (krberr != 0) {
                *err_msg = _("Warning unrecognized salt type.\n");
                continue;
            }

            j++;
        }

        nkeys = j;

        free(tmp);
    }

    /* Check we don't already have a key with a similar encoding,
     * it would just produce redundant data and this is what the
     * MIT code do anyway */

    for (i = 0, n = 0; i < nkeys; i++ ) {
        krb5_boolean similar = 0;

        for (j = 0; j < i; j++) {
            krberr = krb5_c_enctype_compare(krbctx,
                                            ksdata[j].enctype,
                                            ksdata[i].enctype,
                                            &similar);
            if (krberr) {
                free_keys_contents(krbctx, keys);
                free(ksdata);
                *err_msg = _("Enctype comparison failed!\n");
                return 0;
            }
            if (similar &&
                (ksdata[j].salttype == ksdata[i].salttype)) {
                break;
            }
        }
        if (j < i) {
            /* redundant encoding, remove it, and shift others */
            int x;
            for (x = i; x < nkeys-1; x++) {
                ksdata[x].enctype = ksdata[x+1].enctype;
                ksdata[x].salttype = ksdata[x+1].salttype;
            }
            continue;
        }
        /* count only confirmed enc/salt tuples */
        n++;
    }

    keys->nkeys = n;
    keys->ksdata = ksdata;

    return n;
}
Beispiel #3
0
krb5_error_code parse_bval_key_salt_tuples(krb5_context kcontext,
                                           const char * const *vals,
                                           int n_vals,
                                           krb5_key_salt_tuple **kst,
                                           int *n_kst)
{
    krb5_error_code kerr;
    krb5_key_salt_tuple *ks;
    int n_ks;
    int i;

    ks = calloc(n_vals + 1, sizeof(krb5_key_salt_tuple));
    if (!ks) {
        return ENOMEM;
    }

    for (i = 0, n_ks = 0; i < n_vals; i++) {
        char *enc, *salt;
        krb5_int32 tmpsalt;
        krb5_enctype tmpenc;
        krb5_boolean similar;
        krb5_error_code krberr;
        int j;

        enc = strdup(vals[i]);
        if (!enc) {
            kerr = ENOMEM;
            goto fail;
        }

        salt = strchr(enc, ':');
        if (!salt) {
            free(enc);
            continue;
        }
        *salt = '\0'; /* null terminate the enc type */
        salt++; /* skip : */

        krberr = krb5_string_to_enctype(enc, &tmpenc);
        if (krberr) {
            free(enc);
            continue;
        }

        krberr = krb5_string_to_salttype(salt, &tmpsalt);
        for (j = 0; j < n_ks; j++) {
            krb5_c_enctype_compare(kcontext,
                                   ks[j].ks_enctype, tmpenc, &similar);
            if (similar && (ks[j].ks_salttype == tmpsalt)) {
                break;
            }
        }

        if (j == n_ks) {
            /* not found */
            ks[j].ks_enctype = tmpenc;
            ks[j].ks_salttype = tmpsalt;
            n_ks++;
        }

        free(enc);
    }

    *kst = ks;
    *n_kst = n_ks;

    return 0;

fail:
    free(ks);
    return kerr;
}
Beispiel #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_boolean similar;
    krb5_enctype req_etype = req->ticket->enc_part.enctype;

#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) {
        ret = krb5_c_enctype_compare(context, ent.key.enctype, req_etype,
                                     &similar);
        if (ret == 0 && similar &&
                krb5_sname_match(context, server, ent.principal)) {
            /* Coerce inexact matches to the request enctype. */
            ent.key.enctype = req_etype;
            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 */
}
Beispiel #5
0
krb5_error_code KRB5_CALLCONV
krb5_mkt_get_entry(krb5_context context, krb5_keytab id,
		      krb5_const_principal principal, krb5_kvno kvno,
		      krb5_enctype enctype, krb5_keytab_entry *out_entry)
{
    krb5_mkt_cursor   cursor;
    krb5_keytab_entry *entry, *match = NULL;
    krb5_error_code err = 0;
    int found_wrong_kvno = 0;
    krb5_boolean similar = 0;

    err = KTLOCK(id);
    if (err)
	return err;

    for (cursor = KTLINK(id); cursor && cursor->entry; cursor = cursor->next) {
	entry = cursor->entry;

	/* if the principal isn't the one requested, continue to the next. */

	if (!krb5_principal_compare(context, principal, entry->principal))
	    continue;

	/* if the enctype is not ignored and doesn't match,
	   and continue to the next */
	if (enctype != IGNORE_ENCTYPE) {
	    if ((err = krb5_c_enctype_compare(context, enctype,
					      entry->key.enctype,
					       &similar))) {
		/* we can't determine the enctype of the entry */
		continue;
	    }

	    if (!similar)
		continue;
	}

	if (kvno == IGNORE_VNO) {
	    if (match == NULL)
		match = entry;
	    else if (entry->vno > match->vno)
		match = entry;
	} else {
	    if (entry->vno == kvno) {
		match = entry;
		break;
	    } else {
		found_wrong_kvno++;
	    }
	}
    }

    /* if we found an entry that matches, ... */
    if (match) {
	out_entry->magic = match->magic;
	out_entry->timestamp = match->timestamp;
	out_entry->vno = match->vno;
	out_entry->key = match->key;
	err = krb5_copy_keyblock_contents(context, &(match->key),
					  &(out_entry->key));
	/*
	 * Coerce the enctype of the output keyblock in case we
	 * got an inexact match on the enctype.
	 */
	if(enctype != IGNORE_ENCTYPE)
		out_entry->key.enctype = enctype;
	if(!err) {
		err = krb5_copy_principal(context,
					  match->principal,
					  &(out_entry->principal));
	}
    } else {
	if (!err)
	    err = found_wrong_kvno ? KRB5_KT_KVNONOTFOUND : KRB5_KT_NOTFOUND;
    }

    KTUNLOCK(id);
    return(err);
}
Beispiel #6
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 */
}