Ejemplo n.º 1
0
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_kt_have_content(krb5_context context,
		     krb5_keytab id)
{
    krb5_keytab_entry entry;
    krb5_kt_cursor cursor;
    krb5_error_code ret;
    char *name;

    ret = krb5_kt_start_seq_get(context, id, &cursor);
    if (ret)
	goto notfound;

    ret = krb5_kt_next_entry(context, id, &entry, &cursor);
    krb5_kt_end_seq_get(context, id, &cursor);
    if (ret)
	goto notfound;

    krb5_kt_free_entry(context, &entry);

    return 0;

 notfound:
    ret = krb5_kt_get_full_name(context, id, &name);
    if (ret == 0) {
	krb5_set_error_message(context, KRB5_KT_NOTFOUND,
			       N_("No entry in keytab: %s", ""), name);
	free(name);
    }
    return KRB5_KT_NOTFOUND;
}
Ejemplo n.º 2
0
/*
 * Find the principal of the first entry of a keytab and return it.  The
 * caller is responsible for freeing the result with krb5_free_principal.
 * Exit on error.
 */
krb5_principal
kerberos_keytab_principal(krb5_context ctx, const char *path)
{
    krb5_keytab keytab;
    krb5_kt_cursor cursor;
    krb5_keytab_entry entry;
    krb5_principal princ;
    krb5_error_code status;

    status = krb5_kt_resolve(ctx, path, &keytab);
    if (status != 0)
        bail_krb5(ctx, status, "error opening %s", path);
    status = krb5_kt_start_seq_get(ctx, keytab, &cursor);
    if (status != 0)
        bail_krb5(ctx, status, "error reading %s", path);
    status = krb5_kt_next_entry(ctx, keytab, &entry, &cursor);
    if (status == 0) {
        status = krb5_copy_principal(ctx, entry.principal, &princ);
        if (status != 0)
            bail_krb5(ctx, status, "error copying principal from %s", path);
        krb5_kt_free_entry(ctx, &entry);
    }
    if (status != 0)
        bail("no principal found in keytab file %s", path);
    krb5_kt_end_seq_get(ctx, keytab, &cursor);
    krb5_kt_close(ctx, keytab);
    return princ;
}
static krb5_error_code KRB5_CALLCONV
any_next_entry (krb5_context context,
		krb5_keytab id,
		krb5_keytab_entry *entry,
		krb5_kt_cursor *cursor)
{
    krb5_error_code ret, ret2;
    struct any_cursor_extra_data *ed;

    ed = (struct any_cursor_extra_data *)cursor->data;
    do {
	ret = krb5_kt_next_entry(context, ed->a->kt, entry, &ed->cursor);
	if (ret == 0)
	    return 0;
	else if (ret != KRB5_KT_END)
	    return ret;

	ret2 = krb5_kt_end_seq_get (context, ed->a->kt, &ed->cursor);
	if (ret2)
	    return ret2;
	while ((ed->a = ed->a->next) != NULL) {
	    ret2 = krb5_kt_start_seq_get(context, ed->a->kt, &ed->cursor);
	    if (ret2 == 0)
		break;
	}
	if (ed->a == NULL) {
	    krb5_clear_error_message (context);
	    return KRB5_KT_END;
	}
    } while (1);
}
Ejemplo n.º 4
0
/*
 * Given two files containing keytab data, second keytab, merge the keys into
 * the new file.  Currently, this doesn't do any cleanup of old kvnos and
 * doesn't handle duplicate kvnos correctly.  Dies on any error.
 */
static void
merge_keytab(krb5_context ctx, const char *newfile, const char *file)
{
    char *oldfile;
    krb5_keytab old = NULL, temp = NULL;
    krb5_kt_cursor cursor;
    krb5_keytab_entry entry;
    krb5_error_code status;

    memset(&entry, 0, sizeof(entry));
    xasprintf(&oldfile, "WRFILE:%s", file);
    status = krb5_kt_resolve(ctx, oldfile, &old);
    if (status != 0)
        die_krb5(ctx, status, "cannot open keytab %s", file);
    free(oldfile);
    status = krb5_kt_resolve(ctx, newfile, &temp);
    if (status != 0)
        die_krb5(ctx, status, "cannot open temporary keytab %s", newfile);
    status = krb5_kt_start_seq_get(ctx, temp, &cursor);
    if (status != 0)
        die_krb5(ctx, status, "cannot read temporary keytab %s", newfile);
    while ((status = krb5_kt_next_entry(ctx, temp, &entry, &cursor)) == 0) {
        status = krb5_kt_add_entry(ctx, old, &entry);
        if (status != 0)
            die_krb5(ctx, status, "cannot write to keytab %s", file);
        krb5_kt_free_entry(ctx, &entry);
    }
    if (status != KRB5_KT_END)
        die_krb5(ctx, status, "error reading temporary keytab %s", newfile);
    krb5_kt_end_seq_get(ctx, temp, &cursor);
    if (old != NULL)
        krb5_kt_close(ctx, old);
    if (temp != NULL)
        krb5_kt_close(ctx, temp);
}
Ejemplo n.º 5
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 */
}
Ejemplo n.º 6
0
/*
 * Given a context, a keytab file, and a realm, return a list of all
 * principals in that file.
 */
static struct principal_name *
keytab_principals(krb5_context ctx, const char *file, char *realm)
{
    char *princname = NULL, *princrealm = NULL;
    bool found;
    krb5_keytab keytab = NULL;
    krb5_kt_cursor cursor;
    krb5_keytab_entry entry;
    krb5_error_code status;
    struct principal_name *names = NULL, *current = NULL, *last = NULL;

    memset(&entry, 0, sizeof(entry));
    status = krb5_kt_resolve(ctx, file, &keytab);
    if (status != 0)
        die_krb5(ctx, status, "cannot open keytab %s", file);
    status = krb5_kt_start_seq_get(ctx, keytab, &cursor);
    if (status != 0)
        die_krb5(ctx, status, "cannot read keytab %s", file);
    while ((status = krb5_kt_next_entry(ctx, keytab, &entry, &cursor)) == 0) {
        status = krb5_unparse_name(ctx, entry.principal, &princname);
        if (status != 0)
            die_krb5(ctx, status, "cannot unparse name for a principal");

        /* Separate into principal and realm. */
        princrealm = strchr(princname, '@');
        if (princrealm != NULL) {
            *princrealm = '\0';
            princrealm++;
        }
        if (princrealm == NULL || strcmp(princrealm, realm) != 0)
            continue;

        /* Check to see if the principal has already been listed. */
        found = false;
        for (current = names; current != NULL; current = current->next) {
            if (strcmp(current->princ, princname) == 0) {
                found = true;
                break;
            }
            last = current;
        }
        if (found == false) {
            current = xmalloc(sizeof(struct principal_name));
            current->princ = xstrdup(princname);
            current->next = NULL;
            if (last == NULL)
                names = current;
            else
                last->next = current;
        }
        krb5_kt_free_entry(ctx, &entry);
        free(princname);
    }
    if (status != KRB5_KT_END)
        die_krb5(ctx, status, "error reading keytab %s", file);
    krb5_kt_end_seq_get(ctx, keytab, &cursor);
    krb5_kt_close(ctx, keytab);
    return names;
}
Ejemplo n.º 7
0
bool KRB5Keytab::cursor::next()
{
    krb5_free_keytab_entry_contents(g_context.get(), &m_entry);
    memset(&m_entry, 0, sizeof(m_entry));
    krb5_error_code ret = krb5_kt_next_entry(g_context.get(), m_keytab.m_keytab, &m_entry, &m_cursor);
    m_princ.reset_no_free(m_entry.principal);
    return ret == 0;
}
Ejemplo n.º 8
0
static OM_uint32 acquire_acceptor_cred
		  (OM_uint32 * minor_status,
		   krb5_context context,
		   const gss_name_t desired_name,
		   OM_uint32 time_req,
		   const gss_OID_set desired_mechs,
		   gss_cred_usage_t cred_usage,
		   gsskrb5_cred handle,
		   gss_OID_set * actual_mechs,
		   OM_uint32 * time_rec
		  )
{
    OM_uint32 ret;
    krb5_error_code kret;

    ret = GSS_S_FAILURE;
    kret = get_keytab(context, &handle->keytab);
    if (kret)
	goto end;

    /* check that the requested principal exists in the keytab */
    if (handle->principal) {
	krb5_keytab_entry entry;

	kret = krb5_kt_get_entry(context, handle->keytab,
				 handle->principal, 0, 0, &entry);
	if (kret)
	    goto end;
	krb5_kt_free_entry(context, &entry);
	ret = GSS_S_COMPLETE;
    } else {
	/*
	 * Check if there is at least one entry in the keytab before
	 * declaring it as an useful keytab.
	 */
	krb5_keytab_entry tmp;
	krb5_kt_cursor c;

	kret = krb5_kt_start_seq_get (context, handle->keytab, &c);
	if (kret)
	    goto end;
	if (krb5_kt_next_entry(context, handle->keytab, &tmp, &c) == 0) {
	    krb5_kt_free_entry(context, &tmp);
	    ret = GSS_S_COMPLETE; /* ok found one entry */
	}
	krb5_kt_end_seq_get (context, handle->keytab, &c);
    }
end:
    if (ret != GSS_S_COMPLETE) {
	if (handle->keytab != NULL)
	    krb5_kt_close(context, handle->keytab);
	if (kret != 0) {
	    *minor_status = kret;
	}
    }
    return (ret);
}
 bool next() {
   krb5_free_keytab_entry_contents(kt_->getContext(), &ktentry_);
   memset(&ktentry_, 0, sizeof(ktentry_));
   krb5_error_code code =
     krb5_kt_next_entry(kt_->getContext(), kt_->get(), &ktentry_, &cursor_);
   if (code == KRB5_KT_END) {
     return false;
   } else {
     raiseIf(kt_->getContext(), code, "reading next credential");
   }
   return true;
 }
krb5_error_code
_adcli_krb5_keytab_clear (krb5_context k5,
                          krb5_keytab keytab,
                          krb5_boolean (* match_func) (krb5_context,
                                                       krb5_keytab_entry *,
                                                       void *),
                          void *match_data)
{
	krb5_kt_cursor cursor;
	krb5_keytab_entry entry;
	krb5_error_code code;

	code = krb5_kt_start_seq_get (k5, keytab, &cursor);
	if (code == KRB5_KT_END || code == ENOENT)
		return 0;
	else if (code != 0)
		return code;

	for (;;) {
		code = krb5_kt_next_entry (k5, keytab, &entry, &cursor);
		if (code != 0)
			break;

		/* See if we should remove this entry */
		if (!match_func (k5, &entry, match_data)) {
			krb5_free_keytab_entry_contents (k5, &entry);
			continue;
		}

		/*
		 * Here we close the cursor, remove the entry and then
		 * start all over again from the beginning. Dumb but works.
		 */

		code = krb5_kt_end_seq_get (k5, keytab, &cursor);
		return_val_if_fail (code == 0, code);

		code = krb5_kt_remove_entry (k5, keytab, &entry);
		krb5_free_keytab_entry_contents (k5, &entry);

		if (code != 0)
			return code;

		code = krb5_kt_start_seq_get (k5, keytab, &cursor);
		return_val_if_fail (code == 0, code);
	}

	if (code == KRB5_KT_END)
		code = 0;

	krb5_kt_end_seq_get (k5, keytab, &cursor);
	return code;
}
Ejemplo n.º 11
0
krb5_error_code krb5_kt_find_realm(krb5_context context, krb5_keytab keytab,
    krb5_principal princ, krb5_data *realm) {

	krb5_kt_cursor cur;
	krb5_keytab_entry ent;
	krb5_boolean match;
	krb5_data tmp_realm;
	krb5_error_code ret, ret2;

	ret = krb5_kt_start_seq_get(context, keytab, &cur);
	if (ret != 0) {
		return (ret);
	}

	while ((ret = krb5_kt_next_entry(context, keytab, &ent, &cur)) == 0) {
		/* For the comparison the realms should be the same. */
		memcpy(&tmp_realm, &ent.principal->realm, sizeof (krb5_data));
		memcpy(&ent.principal->realm, &princ->realm,
		    sizeof (krb5_data));

		match = krb5_principal_compare(context, ent.principal, princ);

		/* Copy the realm back */
		memcpy(&ent.principal->realm, &tmp_realm, sizeof (krb5_data));

		if (match) {
			/*
			 * A suitable entry was found in the keytab.
			 * Copy its realm
			 */
			ret = krb5int_copy_data_contents(context,
			    &ent.principal->realm, realm);
			if (ret) {
				krb5_kt_free_entry(context, &ent);
				krb5_kt_end_seq_get(context, keytab, &cur);
				return (ret);
			}

			krb5_kt_free_entry(context, &ent);
			break;
		}

		krb5_kt_free_entry(context, &ent);
	}

	ret2 = krb5_kt_end_seq_get(context, keytab, &cur);

	if (ret == KRB5_KT_END) {
		return (KRB5_KT_NOTFOUND);
	}

	return (ret ? ret : ret2);
}
Ejemplo n.º 12
0
static krb5_error_code
krb5_kt_get_entry_wrapped(krb5_context context,
			  krb5_keytab id,
			  krb5_const_principal principal,
			  krb5_kvno kvno,
			  krb5_enctype enctype,
			  krb5_keytab_entry *entry)
{
    krb5_keytab_entry tmp;
    krb5_error_code ret;
    krb5_kt_cursor cursor;

    if(id->get)
	return (*id->get)(context, id, principal, kvno, enctype, entry);

    ret = krb5_kt_start_seq_get (context, id, &cursor);
    if (ret) {
	/* This is needed for krb5_verify_init_creds, but keep error
	 * string from previous error for the human. */
	context->error_code = KRB5_KT_NOTFOUND;
	return KRB5_KT_NOTFOUND;
    }

    entry->vno = 0;
    while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) {
	if (krb5_kt_compare(context, &tmp, principal, 0, enctype)) {
	    /* the file keytab might only store the lower 8 bits of
	       the kvno, so only compare those bits */
	    if (kvno == tmp.vno
		|| (tmp.vno < 256 && kvno % 256 == tmp.vno)) {
		krb5_kt_copy_entry_contents (context, &tmp, entry);
		krb5_kt_free_entry (context, &tmp);
		krb5_kt_end_seq_get(context, id, &cursor);
		return 0;
	    } else if (kvno == 0 && tmp.vno > entry->vno) {
		if (entry->vno)
		    krb5_kt_free_entry (context, entry);
		krb5_kt_copy_entry_contents (context, &tmp, entry);
	    }
	}
	krb5_kt_free_entry(context, &tmp);
    }
    krb5_kt_end_seq_get (context, id, &cursor);
    if (entry->vno == 0)
	return _krb5_kt_principal_not_found(context, KRB5_KT_NOTFOUND,
					    id, principal, enctype, kvno);
    return 0;
}
Ejemplo n.º 13
0
static krb5_error_code
copy_keytab(krb5_context context, krb5_keytab from, krb5_keytab to)
{
    krb5_keytab_entry entry;
    krb5_kt_cursor cursor;
    krb5_error_code ret;

    ret = krb5_kt_start_seq_get(context, from, &cursor);
    if (ret)
	return ret;
    while((ret = krb5_kt_next_entry(context, from, &entry, &cursor)) == 0){
	krb5_kt_add_entry(context, to, &entry);
	krb5_kt_free_entry(context, &entry);
    }
    return krb5_kt_end_seq_get(context, from, &cursor);
}	    
Ejemplo n.º 14
0
krb5_error_code kt_copy (krb5_context context, const char *from, const char *to)
{
    krb5_error_code ret;
    krb5_keytab src_keytab, dst_keytab;
    krb5_kt_cursor cursor;
    krb5_keytab_entry entry;

    ret = krb5_kt_resolve (context, from, &src_keytab);
    if (ret) {
	krb5_set_error_message (context, ret, "resolving src keytab `%s'", from);
	return ret;
    }

    ret = krb5_kt_resolve (context, to, &dst_keytab);
    if (ret) {
	krb5_kt_close (context, src_keytab);
	krb5_set_error_message (context, ret, "resolving dst keytab `%s'", to);
	return ret;
    }

    ret = krb5_kt_start_seq_get (context, src_keytab, &cursor);
    if (ret) {
	krb5_set_error_message (context, ret, "krb5_kt_start_seq_get %s", from);
	goto out;
    }

    while((ret = krb5_kt_next_entry(context, src_keytab,
				    &entry, &cursor)) == 0) {
	ret = copy_one_entry(context, src_keytab, dst_keytab, entry);
	if (ret) {
	    break;
	}
    }
    krb5_kt_end_seq_get (context, src_keytab, &cursor);

  out:
    krb5_kt_close (context, src_keytab);
    krb5_kt_close (context, dst_keytab);
    if (ret == KRB5_KT_END) {
	return 0;
    } else if (ret == 0) {
	return EINVAL;
    }
    return ret;
}
Ejemplo n.º 15
0
mit_krb5_error_code KRB5_CALLCONV
krb5_kt_get_entry(mit_krb5_context context,
		  mit_krb5_keytab id,
		  mit_krb5_const_principal principal,
		  mit_krb5_kvno kvno,
		  mit_krb5_enctype enctype,
		  mit_krb5_keytab_entry *entry)
{
    mit_krb5_keytab_entry tmp;
    mit_krb5_error_code ret;
    mit_krb5_kt_cursor cursor;

    LOG_ENTRY();

    memset(entry, 0, sizeof(*entry));

    ret = krb5_kt_start_seq_get (context, id, &cursor);
    if (ret)
	return KRB5_KT_NOTFOUND;

    entry->vno = 0;
    while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) {
	if (krb5_kt_compare(context, &tmp, principal, 0, enctype)) {
	    /* the file keytab might only store the lower 8 bits of
	       the kvno, so only compare those bits */
	    if (kvno == tmp.vno
		|| (tmp.vno < 256 && kvno % 256 == tmp.vno)) {
		krb5_kt_copy_entry_contents (context, &tmp, entry);
		krb5_kt_free_entry (context, &tmp);
		krb5_kt_end_seq_get(context, id, &cursor);
		return 0;
	    } else if (kvno == 0 && tmp.vno > entry->vno) {
		if (entry->vno)
		    krb5_kt_free_entry (context, entry);
		krb5_kt_copy_entry_contents (context, &tmp, entry);
	    }
	}
	krb5_kt_free_entry(context, &tmp);
    }
    krb5_kt_end_seq_get (context, id, &cursor);
    if (entry->vno == 0)
	return KRB5_KT_NOTFOUND;
    return 0;
}
Ejemplo n.º 16
0
/*
 * In a couple of places we need to get a principal name from a keytab: when
 * verifying credentials against a keytab, and when querying the name of a
 * default GSS acceptor cred.  Keytabs do not have the concept of a default
 * principal like ccaches do, so for now we just return the first principal
 * listed in the keytab, or an error if it's not iterable.  In the future we
 * could consider elevating this to a public API and giving keytab types an
 * operation to return a default principal, and maybe extending the file format
 * and tools to support it.  Returns KRB5_KT_NOTFOUND if the keytab is empty
 * or non-iterable.
 */
krb5_error_code
k5_kt_get_principal(krb5_context context, krb5_keytab keytab,
                    krb5_principal *princ_out)
{
    krb5_error_code ret;
    krb5_kt_cursor cursor;
    krb5_keytab_entry kte;

    *princ_out = NULL;
    if (keytab->ops->start_seq_get == NULL)
        return KRB5_KT_NOTFOUND;
    ret = krb5_kt_start_seq_get(context, keytab, &cursor);
    if (ret)
        return ret;
    ret = krb5_kt_next_entry(context, keytab, &kte, &cursor);
    (void)krb5_kt_end_seq_get(context, keytab, &cursor);
    if (ret)
        return (ret == KRB5_KT_END) ? KRB5_KT_NOTFOUND : ret;
    ret = krb5_copy_principal(context, kte.principal, princ_out);
    krb5_kt_free_entry(context, &kte);
    return ret;
}
Ejemplo n.º 17
0
Archivo: sss_krb5.c Proyecto: 3van/sssd
krb5_error_code sss_krb5_kt_have_content(krb5_context context,
                                         krb5_keytab keytab)
{
#ifdef HAVE_KRB5_KT_HAVE_CONTENT
    return krb5_kt_have_content(context, keytab);
#else
    krb5_keytab_entry entry;
    krb5_kt_cursor cursor;
    krb5_error_code kerr;
    krb5_error_code kerr_end;

    kerr = krb5_kt_start_seq_get(context, keytab, &cursor);
    if (kerr != 0) {
        DEBUG(SSSDBG_OP_FAILURE,
              "krb5_kt_start_seq_get failed, assuming no entries.\n");
        return KRB5_KT_NOTFOUND;
    }

    kerr = krb5_kt_next_entry(context, keytab, &entry, &cursor);
    kerr_end = krb5_kt_end_seq_get(context, keytab, &cursor);
    if (kerr != 0) {
        DEBUG(SSSDBG_OP_FAILURE,
              "krb5_kt_next_entry failed, assuming no entries.\n");
        return KRB5_KT_NOTFOUND;
    }
    kerr = krb5_free_keytab_entry_contents(context, &entry);

    if (kerr_end != 0) {
        DEBUG(SSSDBG_TRACE_FUNC,
              "krb5_kt_end_seq_get failed, ignored.\n");
    }
    if (kerr != 0) {
        DEBUG(SSSDBG_TRACE_FUNC,
              "krb5_free_keytab_entry_contents failed, ignored.\n");
    }

    return 0;
#endif
}
Ejemplo n.º 18
0
int
main(int argc, char **argv)
{
    krb5_context kcontext = NULL;
    krb5_keytab kt = NULL;
    krb5_keytab_entry entry;
    krb5_kt_cursor cursor = NULL;
    krb5_error_code krb5_err;
    int matched = 0;
    
    char svc_name[] = "host";
    int svc_name_len = strlen (svc_name);
    
    
    krb5_err = krb5_init_context(&kcontext);
    if (krb5_err) { goto Error; }
    krb5_err = krb5_kt_default(kcontext, &kt);
    if (krb5_err) { goto Error; }
    krb5_err = krb5_kt_start_seq_get(kcontext, kt, &cursor);
    if (krb5_err) { goto Error; }
    while ((matched == 0) && (krb5_err = krb5_kt_next_entry(kcontext, kt, &entry, &cursor)) == 0) {
	
	krb5_data *nameData = krb5_princ_name (kcontext, entry.principal);
	if (NULL != nameData->data && svc_name_len == nameData->length
	    && 0 == strncmp (svc_name, nameData->data, nameData->length)) {
	    matched = 1;
	}
        
	krb5_free_keytab_entry_contents(kcontext, &entry);
    }
    
    krb5_err = krb5_kt_end_seq_get(kcontext, kt, &cursor);
 Error:
    if (NULL != kt) { krb5_kt_close (kcontext, kt); }
    if (NULL != kcontext) { krb5_free_context (kcontext); }
    // Return 0 if we got match or -1 if err or no match
    return (0 != krb5_err) ? -1 : matched ? 0 : -1;
}        
Ejemplo n.º 19
0
/*
 * Given a keytab, extract the principal name of the (first) entry with
 * the highest kvno in the keytab.  This provides compatibility with the
 * rxkad KeyFile behavior of always using the highest kvno entry when
 * printing tickets.  We could return the kvno as well, but krb5_kt_get_entry
 * can find the highest kvno on its own.
 *
 * Returns 0 on success, krb5 errors on failure.
 */
static int
pick_principal(krb5_context context, krb5_keytab kt,
	       krb5_principal *service_principal)
{
    krb5_error_code code;
    krb5_kvno vno = 0;
    krb5_kt_cursor c;
    krb5_keytab_entry n_entry;

    /* Nothing to do */
    if (*service_principal != NULL)
	return 0;

    memset(&n_entry, 0, sizeof(n_entry));

    code = krb5_kt_start_seq_get(context, kt, &c);
    if (code != 0)
	goto cleanup;
    while (code == 0 && krb5_kt_next_entry(context, kt, &n_entry, &c) == 0) {
	if (n_entry.vno > vno) {
	    vno = n_entry.vno;
	    (void)krb5_free_principal(context, *service_principal);
	    code = krb5_copy_principal(context, n_entry.principal,
				       service_principal);
	}
	(void)krb5_free_keytab_entry_contents(context, &n_entry);
    }
    if (code != 0) {
	(void)krb5_kt_end_seq_get(context, kt, &c);
	goto cleanup;
    }
    code = krb5_kt_end_seq_get(context, kt, &c);

cleanup:
    return code;
}
Ejemplo n.º 20
0
/* Return a list of all unique host service princs in keytab. */
static krb5_error_code
get_host_princs_from_keytab(krb5_context context, krb5_keytab keytab,
                            krb5_principal **princ_list_out)
{
    krb5_error_code ret;
    krb5_kt_cursor cursor;
    krb5_keytab_entry kte;
    krb5_principal *plist = NULL, p;

    *princ_list_out = NULL;

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

    while ((ret = krb5_kt_next_entry(context, keytab, &kte, &cursor)) == 0) {
        p = kte.principal;
        if (p->length == 2 && data_eq_string(p->data[0], "host"))
            ret = add_princ_list(context, p, &plist);
        krb5_kt_free_entry(context, &kte);
        if (ret)
            break;
    }
    (void)krb5_kt_end_seq_get(context, keytab, &cursor);
    if (ret == KRB5_KT_END)
        ret = 0;
    if (ret)
        goto cleanup;

    *princ_list_out = plist;
    plist = NULL;

cleanup:
    free_princ_list(context, plist);
    return ret;
}
static int
check_keytab(krb5_context context,
	     gsskrb5_cred handle,
	     const char *service,
	     int require_lkdc)
{
    krb5_keytab_entry tmp;
    krb5_error_code ret;
    krb5_kt_cursor c;
    int found = 0;

    ret = krb5_kt_start_seq_get (context, handle->keytab, &c);
    if (ret)
	return 0;
    while (!found && krb5_kt_next_entry(context, handle->keytab, &tmp, &c) == 0) {
	krb5_principal principal = tmp.principal;

	if (service) {
	    if (principal->name.name_string.len < 1
		|| strcmp(principal->name.name_string.val[0], service) != 0)
		goto next;
	}
	if (require_lkdc) {
	    if (krb5_principal_is_lkdc(context, principal))
		found = 1;
	    if (krb5_principal_is_pku2u(context, principal))
		found = 1;
	} else
	    found = 1;
      next:
	krb5_kt_free_entry(context, &tmp);
    }
    krb5_kt_end_seq_get (context, handle->keytab, &c);

    return found;
}
Ejemplo n.º 22
0
Archivo: ktutil.c Proyecto: GSam/samba
int main (int argc, char **argv)
{
	TALLOC_CTX *mem_ctx = talloc_init("ktutil");
	krb5_context context;
	krb5_keytab keytab;
	krb5_kt_cursor cursor;
	krb5_keytab_entry entry;
	krb5_error_code ret;
	char *keytab_name = NULL;

	if (mem_ctx == NULL) {
		printf("talloc_init() failed\n");
		exit(1);
	}

	if (argc != 2) {
		printf("Usage: %s KEYTAB\n", argv[0]);
		exit(1);
	}

	keytab_name = argv[1];

	initialize_krb5_error_table();

	ret = krb5_init_context(&context);
	if (ret) {
		smb_krb5_err(mem_ctx, context, 1, ret, "krb5_context");
	}

	ret = smb_krb5_open_keytab_relative(context, keytab_name, false, &keytab);
	if (ret) {
		smb_krb5_err(mem_ctx, context, 1, ret, "open keytab");
	}

	ret = krb5_kt_start_seq_get(context, keytab, &cursor);
	if (ret) {
		smb_krb5_err(mem_ctx, context, 1, ret, "krb5_kt_start_seq_get");
	}

	for (ret = krb5_kt_next_entry(context, keytab, &entry, &cursor);
	     ret == 0;
	     ret = krb5_kt_next_entry(context, keytab, &entry, &cursor))
	{
		char *principal = NULL;
		char *enctype_str = NULL;
		krb5_enctype enctype = smb_get_enctype_from_kt_entry(&entry);

		ret = smb_krb5_unparse_name(mem_ctx,
					    context,
					    entry.principal,
					    &principal);
		if (ret) {
			smb_krb5_err(mem_ctx, context, 1, ret, "krb5_enctype_to_string");
		}

		ret = smb_krb5_enctype_to_string(context,
						 enctype,
						 &enctype_str);
		if (ret) {
			smb_krb5_err(mem_ctx, context, 1, ret, "krb5_enctype_to_string");
		}

		printf("%s (%s)\n", principal, enctype_str);

		TALLOC_FREE(principal);
		SAFE_FREE(enctype_str);
		smb_krb5_kt_free_entry(context, &entry);
	}

	ret = krb5_kt_end_seq_get(context, keytab, &cursor);
	if (ret) {
		smb_krb5_err(mem_ctx, context, 1, ret, "krb5_kt_end_seq_get");
	}

	ret = krb5_kt_close(context, keytab);
	if (ret) {
		smb_krb5_err(mem_ctx, context, 1, ret, "krb5_kt_close");
	}

	krb5_free_context(context);
	talloc_free(mem_ctx);
	return 0;
}
Ejemplo n.º 23
0
/* Return the list of etypes available for client in keytab. */
static krb5_error_code
lookup_etypes_for_keytab(krb5_context context, krb5_keytab keytab,
                         krb5_principal client, krb5_enctype **etypes_out)
{
    krb5_kt_cursor cursor;
    krb5_keytab_entry entry;
    krb5_enctype *p, *etypes = NULL, etype;
    krb5_kvno max_kvno = 0, vno;
    krb5_error_code ret;
    krb5_boolean match;
    size_t count = 0;

    *etypes_out = NULL;

    if (keytab->ops->start_seq_get == NULL)
        return EINVAL;
    ret = krb5_kt_start_seq_get(context, keytab, &cursor);
    if (ret != 0)
        return ret;

    while (!(ret = krb5_kt_next_entry(context, keytab, &entry, &cursor))) {
        /* Extract what we need from the entry and free it. */
        etype = entry.key.enctype;
        vno = entry.vno;
        match = krb5_principal_compare(context, entry.principal, client);
        krb5_free_keytab_entry_contents(context, &entry);

        /* Filter out old or non-matching entries and invalid enctypes. */
        if (vno < max_kvno || !match || !krb5_c_valid_enctype(etype))
            continue;

        /* Update max_kvno and reset the list if we find a newer kvno. */
        if (vno > max_kvno) {
            max_kvno = vno;
            free(etypes);
            etypes = NULL;
            count = 0;
        }

        /* Leave room for the terminator and possibly a second entry. */
        p = realloc(etypes, (count + 3) * sizeof(*etypes));
        if (p == NULL) {
            ret = ENOMEM;
            goto cleanup;
        }
        etypes = p;
        etypes[count++] = etype;
        /* All DES key types work with des-cbc-crc, which is more likely to be
         * accepted by the KDC (since MIT KDCs refuse des-cbc-md5). */
        if (etype == ENCTYPE_DES_CBC_MD5 || etype == ENCTYPE_DES_CBC_MD4)
            etypes[count++] = ENCTYPE_DES_CBC_CRC;
        etypes[count] = 0;
    }
    if (ret != KRB5_KT_END)
        goto cleanup;
    ret = 0;

    *etypes_out = etypes;
    etypes = NULL;

cleanup:
    krb5_kt_end_seq_get(context, keytab, &cursor);
    free(etypes);
    return ret;
}
Ejemplo n.º 24
0
krb5_error_code KRB5_LIB_FUNCTION
krb5_kt_get_entry(krb5_context context,
		  krb5_keytab id,
		  krb5_const_principal principal,
		  krb5_kvno kvno,
		  krb5_enctype enctype,
		  krb5_keytab_entry *entry)
{
    krb5_keytab_entry tmp;
    krb5_error_code ret;
    krb5_kt_cursor cursor;

    if(id->get)
	return (*id->get)(context, id, principal, kvno, enctype, entry);

    ret = krb5_kt_start_seq_get (context, id, &cursor);
    if (ret) {
	/* This is needed for krb5_verify_init_creds, but keep error
	 * string from previous error for the human. */
	context->error_code = KRB5_KT_NOTFOUND;
	return KRB5_KT_NOTFOUND;
    }

    entry->vno = 0;
    while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) {
	if (krb5_kt_compare(context, &tmp, principal, 0, enctype)) {
	    /* the file keytab might only store the lower 8 bits of
	       the kvno, so only compare those bits */
	    if (kvno == tmp.vno
		|| (tmp.vno < 256 && kvno % 256 == tmp.vno)) {
		krb5_kt_copy_entry_contents (context, &tmp, entry);
		krb5_kt_free_entry (context, &tmp);
		krb5_kt_end_seq_get(context, id, &cursor);
		return 0;
	    } else if (kvno == 0 && tmp.vno > entry->vno) {
		if (entry->vno)
		    krb5_kt_free_entry (context, entry);
		krb5_kt_copy_entry_contents (context, &tmp, entry);
	    }
	}
	krb5_kt_free_entry(context, &tmp);
    }
    krb5_kt_end_seq_get (context, id, &cursor);
    if (entry->vno) {
	return 0;
    } else {
	char princ[256], kvno_str[25], *kt_name;
	char *enctype_str = NULL;

	krb5_unparse_name_fixed (context, principal, princ, sizeof(princ));
	krb5_kt_get_full_name (context, id, &kt_name);
	krb5_enctype_to_string(context, enctype, &enctype_str);

	if (kvno)
	    snprintf(kvno_str, sizeof(kvno_str), "(kvno %d)", kvno);
	else
	    kvno_str[0] = '\0';

	krb5_set_error_message (context, KRB5_KT_NOTFOUND,
				N_("Failed to find %s%s in keytab %s (%s)",
				   "principal, kvno, keytab file, enctype"),
				princ,
				kvno_str,
				kt_name ? kt_name : "unknown keytab",
				enctype_str ? enctype_str : "unknown enctype");
	free(kt_name);
	free(enctype_str);
	return KRB5_KT_NOTFOUND;
    }
}
Ejemplo n.º 25
0
static void
remove_principal(char *keytab_str, krb5_keytab keytab,
                 char *princ_str, char *kvno_str)
{
    krb5_principal princ;
    krb5_keytab_entry entry;
    krb5_kt_cursor cursor;
    enum { UNDEF, SPEC, HIGH, ALL, OLD } mode;
    int code, did_something;
    krb5_kvno kvno;

    code = krb5_parse_name(context, princ_str, &princ);
    if (code != 0) {
        com_err(whoami, code, "while parsing principal name %s", princ_str);
        return;
    }

    mode = UNDEF;
    if (kvno_str == NULL) {
        mode = HIGH;
        kvno = 0;
    } else if (strcmp(kvno_str, "all") == 0) {
        mode = ALL;
        kvno = 0;
    } else if (strcmp(kvno_str, "old") == 0) {
        mode = OLD;
        kvno = 0;
    } else {
        mode = SPEC;
        kvno = atoi(kvno_str);
    }

    /* kvno is set to specified value for SPEC, 0 otherwise */
    code = krb5_kt_get_entry(context, keytab, princ, kvno, 0, &entry);
    if (code != 0) {
        if (code == ENOENT) {
            fprintf(stderr, "%s: Keytab %s does not exist.\n",
                    whoami, keytab_str);
        } else if (code == KRB5_KT_NOTFOUND) {
            if (mode != SPEC) {
                fprintf(stderr, "%s: No entry for principal "
                        "%s exists in keytab %s\n",
                        whoami, princ_str, keytab_str);
            } else {
                fprintf(stderr, "%s: No entry for principal "
                        "%s with kvno %d exists in keytab "
                        "%s.\n", whoami, princ_str, kvno, keytab_str);
            }
        } else
            com_err(whoami, code, "while retrieving highest kvno from keytab");
        return;
    }

    /* set kvno to spec'ed value for SPEC, highest kvno otherwise */
    kvno = entry.vno;
    krb5_kt_free_entry(context, &entry);

    code = krb5_kt_start_seq_get(context, keytab, &cursor);
    if (code != 0) {
        com_err(whoami, code, "while starting keytab scan");
        return;
    }

    did_something = 0;
    while ((code = krb5_kt_next_entry(context, keytab, &entry,
                                      &cursor)) == 0) {
        if (krb5_principal_compare(context, princ, entry.principal) &&
            ((mode == ALL) ||
             (mode == SPEC && entry.vno == kvno) ||
             (mode == OLD && entry.vno != kvno) ||
             (mode == HIGH && entry.vno == kvno))) {

            /*
             * Ack!  What a kludge... the scanning functions lock
             * the keytab so entries cannot be removed while they
             * are operating.
             */
            code = krb5_kt_end_seq_get(context, keytab, &cursor);
            if (code != 0) {
                com_err(whoami, code, "while temporarily ending keytab scan");
                return;
            }
            code = krb5_kt_remove_entry(context, keytab, &entry);
            if (code != 0) {
                com_err(whoami, code, "while deleting entry from keytab");
                return;
            }
            code = krb5_kt_start_seq_get(context, keytab, &cursor);
            if (code != 0) {
                com_err(whoami, code, "while restarting keytab scan");
                return;
            }

            did_something++;
            if (!quiet)
                printf("Entry for principal %s with kvno %d "
                       "removed from keytab %s.\n",
                       princ_str, entry.vno, keytab_str);
        }
        krb5_kt_free_entry(context, &entry);
    }
    if (code && code != KRB5_KT_END) {
        com_err(whoami, code, "while scanning keytab");
        return;
    }
    code = krb5_kt_end_seq_get(context, keytab, &cursor);
    if (code) {
        com_err(whoami, code, "while ending keytab scan");
        return;
    }

    /*
     * If !did_someting then mode must be OLD or we would have
     * already returned with an error.  But check it anyway just to
     * prevent unexpected error messages...
     */
    if (!did_something && mode == OLD) {
        fprintf(stderr, "%s: There is only one entry for principal "
                "%s in keytab %s\n", whoami, princ_str, keytab_str);
    }
}
Ejemplo n.º 26
0
int print_keytab (const char *in_name)
{
    krb5_error_code err = 0;
    krb5_keytab kt;
    krb5_keytab_entry entry;
    krb5_kt_cursor cursor;
    char keytab_name[BUFSIZ]; /* hopefully large enough for any type */

    if (!err) {
        if (!in_name) {
            err = krb5_kt_default (kcontext, &kt);
            printiferr (err, "while resolving default keytab");
        } else {
            err = krb5_kt_resolve (kcontext, in_name, &kt);
            printiferr (err, "while resolving keytab %s", in_name);
        }
    }

    if (!err) {
        err = krb5_kt_get_name (kcontext, kt, keytab_name, sizeof (keytab_name));
        printiferr (err, "while getting keytab name");
    }

    if (!err) {
        printmsg ("Keytab name: %s\n", keytab_name);
    }

    if (!err) {
        err = krb5_kt_start_seq_get (kcontext, kt, &cursor);
        printiferr (err, "while starting scan of keytab %s", keytab_name);
    }

    if (!err) {
        if (show_entry_timestamps) {
            printmsg ("KVNO Timestamp");
            printfiller (' ', get_timestamp_width () - sizeof ("Timestamp") + 2);
            printmsg ("Principal\n");
            printmsg ("---- ");
            printfiller ('-', get_timestamp_width ());
            printmsg (" ");
            printfiller ('-', 78 - get_timestamp_width () - sizeof ("KVNO"));
            printmsg ("\n");
        } else {
            printmsg("KVNO Principal\n");
            printmsg("---- --------------------------------------------------------------------------\n");
        }
    }

    while (!err) {
        char *principal_name = NULL;

        err = krb5_kt_next_entry (kcontext, kt, &entry, &cursor);
	if (err == KRB5_KT_END) {
	    err = 0;
	    break;
	}
 
        if (!err) {
            err = krb5_unparse_name (kcontext, entry.principal, &principal_name);
            printiferr (err, "while unparsing principal name");
        }
        
        if (!err) {
            printmsg ("%4d ", entry.vno);
            if (show_entry_timestamps) {
                printtime (entry.timestamp);
                printmsg (" ");
            }
            printmsg ("%s", principal_name);
            if (show_enctypes) {
                printmsg (" (%s) ", enctype_to_string (entry.key.enctype));
            }
            if (show_entry_DES_keys) {
                unsigned int i;
                
                printmsg (" (0x");
                for (i = 0; i < entry.key.length; i++) {
                    printmsg ("%02x", entry.key.contents[i]);
                }
                printmsg (")");
            }
            printmsg ("\n");
        }
	printiferr (err, "while scanning keytab %s", keytab_name);

        if (principal_name) { krb5_free_unparsed_name (kcontext, principal_name); }
    }

    if (!err) {
        err = krb5_kt_end_seq_get (kcontext, kt, &cursor);
        printiferr (err, "while ending scan of keytab %s", keytab_name);
    }

    return err ? 1 : 0;
}
Ejemplo n.º 27
0
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_rd_req_ctx(krb5_context context,
		krb5_auth_context *auth_context,
		const krb5_data *inbuf,
		krb5_const_principal server,
		krb5_rd_req_in_ctx inctx,
		krb5_rd_req_out_ctx *outctx)
{
    krb5_error_code ret;
    krb5_ap_req ap_req;
    krb5_rd_req_out_ctx o = NULL;
    krb5_keytab id = NULL, keytab = NULL;
    krb5_principal service = NULL;

    *outctx = NULL;

    o = calloc(1, sizeof(*o));
    if (o == NULL) {
	krb5_set_error_message(context, ENOMEM,
			       N_("malloc: out of memory", ""));
	return ENOMEM;
    }

    if (*auth_context == NULL) {
	ret = krb5_auth_con_init(context, auth_context);
	if (ret)
	    goto out;
    }

    ret = krb5_decode_ap_req(context, inbuf, &ap_req);
    if(ret)
	goto out;

    /* Save that principal that was in the request */
    ret = _krb5_principalname2krb5_principal(context,
					     &o->server,
					     ap_req.ticket.sname,
					     ap_req.ticket.realm);
    if (ret)
	goto out;

    if (ap_req.ap_options.use_session_key &&
	(*auth_context)->keyblock == NULL) {
	ret = KRB5KRB_AP_ERR_NOKEY;
	krb5_set_error_message(context, ret,
			       N_("krb5_rd_req: user to user auth "
				  "without session key given", ""));
	goto out;
    }

    if (inctx && inctx->keytab)
	id = inctx->keytab;

    if((*auth_context)->keyblock){
	ret = krb5_copy_keyblock(context,
				 (*auth_context)->keyblock,
				 &o->keyblock);
	if (ret)
	    goto out;
    } else if(inctx && inctx->keyblock){
	ret = krb5_copy_keyblock(context,
				 inctx->keyblock,
				 &o->keyblock);
	if (ret)
	    goto out;
    } else {

	if(id == NULL) {
	    krb5_kt_default(context, &keytab);
	    id = keytab;
	}
	if (id == NULL)
	    goto out;

	if (server == NULL) {
	    ret = _krb5_principalname2krb5_principal(context,
						     &service,
						     ap_req.ticket.sname,
						     ap_req.ticket.realm);
	    if (ret)
		goto out;
	    server = service;
	}

	ret = get_key_from_keytab(context,
				  &ap_req,
				  server,
				  id,
				  &o->keyblock);
	if (ret) {
	    /* If caller specified a server, fail. */
	    if (service == NULL && (context->flags & KRB5_CTX_F_RD_REQ_IGNORE) == 0)
		goto out;
	    /* Otherwise, fall back to iterating over the keytab. This
	     * have serious performace issues for larger keytab.
	     */
	    o->keyblock = NULL;
	}
    }

    if (o->keyblock) {
	/*
	 * We got an exact keymatch, use that.
	 */

	ret = krb5_verify_ap_req2(context,
				  auth_context,
				  &ap_req,
				  server,
				  o->keyblock,
				  0,
				  &o->ap_req_options,
				  &o->ticket,
				  KRB5_KU_AP_REQ_AUTH);

	if (ret)
	    goto out;

    } else {
	/*
	 * Interate over keytab to find a key that can decrypt the request.
	 */

	krb5_keytab_entry entry;
	krb5_kt_cursor cursor;
	int done = 0, kvno = 0;

	memset(&cursor, 0, sizeof(cursor));

	if (ap_req.ticket.enc_part.kvno)
	    kvno = *ap_req.ticket.enc_part.kvno;

	ret = krb5_kt_start_seq_get(context, id, &cursor);
	if (ret)
	    goto out;

	done = 0;
	while (!done) {
	    krb5_principal p;

	    ret = krb5_kt_next_entry(context, id, &entry, &cursor);
	    if (ret) {
		_krb5_kt_principal_not_found(context, ret, id, o->server,
					     ap_req.ticket.enc_part.etype,
					     kvno);
		krb5_kt_end_seq_get(context, id, &cursor);
		goto out;
	    }

	    if (entry.keyblock.keytype != ap_req.ticket.enc_part.etype) {
		krb5_kt_free_entry (context, &entry);
		continue;
	    }

	    ret = krb5_verify_ap_req2(context,
				      auth_context,
				      &ap_req,
				      server,
				      &entry.keyblock,
				      0,
				      &o->ap_req_options,
				      &o->ticket,
				      KRB5_KU_AP_REQ_AUTH);
	    if (ret) {
		krb5_kt_free_entry(context, &entry);
		continue;
	    }

	    /*
	     * Found a match, save the keyblock for PAC processing,
	     * and update the service principal in the ticket to match
	     * whatever is in the keytab.
	     */

	    ret = krb5_copy_keyblock(context,
				     &entry.keyblock,
				     &o->keyblock);
	    if (ret) {
		krb5_kt_free_entry(context, &entry);
		krb5_kt_end_seq_get(context, id, &cursor);
		goto out;
	    }

	    ret = krb5_copy_principal(context, entry.principal, &p);
	    if (ret) {
		krb5_kt_free_entry(context, &entry);
		krb5_kt_end_seq_get(context, id, &cursor);
		goto out;
	    }
	    krb5_free_principal(context, o->ticket->server);
	    o->ticket->server = p;
	    
	    krb5_kt_free_entry(context, &entry);

	    done = 1;
	}
	krb5_kt_end_seq_get(context, id, &cursor);
    }

    /* If there is a PAC, verify its server signature */
    if (inctx == NULL || inctx->check_pac) {
	krb5_pac pac;
	krb5_data data;

	ret = krb5_ticket_get_authorization_data_type(context,
						      o->ticket,
						      KRB5_AUTHDATA_WIN2K_PAC,
						      &data);
	if (ret == 0) {
	    ret = krb5_pac_parse(context, data.data, data.length, &pac);
	    krb5_data_free(&data);
	    if (ret)
		goto out;

	    ret = krb5_pac_verify(context,
				  pac,
				  o->ticket->ticket.authtime,
				  o->ticket->client,
				  o->keyblock,
				  NULL);
	    krb5_pac_free(context, pac);
	    if (ret == 0)
		o->flags |= KRB5_RD_REQ_OUT_PAC_VALID;
	    ret = 0;
	} else
	    ret = 0;
    }
 out:

    if (ret || outctx == NULL) {
	krb5_rd_req_out_ctx_free(context, o);
    } else
	*outctx = o;

    free_AP_REQ(&ap_req);

    if (service)
	krb5_free_principal(context, service);

    if (keytab)
	krb5_kt_close(context, keytab);

    return ret;
}
Ejemplo n.º 28
0
int
kt_copy (void *opt, int argc, char **argv)
{
    krb5_error_code ret;
    krb5_keytab src_keytab, dst_keytab;
    krb5_kt_cursor cursor;
    krb5_keytab_entry entry, dummy;
    const char *from = argv[0];
    const char *to = argv[1];

    ret = krb5_kt_resolve (context, from, &src_keytab);
    if (ret) {
	krb5_warn (context, ret, "resolving src keytab `%s'", from);
	return 1;
    }

    ret = krb5_kt_resolve (context, to, &dst_keytab);
    if (ret) {
	krb5_kt_close (context, src_keytab);
	krb5_warn (context, ret, "resolving dst keytab `%s'", to);
	return 1;
    }

    ret = krb5_kt_start_seq_get (context, src_keytab, &cursor);
    if (ret) {
	krb5_warn (context, ret, "krb5_kt_start_seq_get %s", keytab_string);
	goto out;
    }

    if (verbose_flag)
	fprintf(stderr, "copying %s to %s\n", from, to);

    while((ret = krb5_kt_next_entry(context, src_keytab,
				    &entry, &cursor)) == 0) {
	char *name_str;
	char *etype_str;
	ret = krb5_unparse_name (context, entry.principal, &name_str);
	if(ret) {
	    krb5_warn(context, ret, "krb5_unparse_name");
	    name_str = NULL; /* XXX */
	}
	ret = krb5_enctype_to_string(context, entry.keyblock.keytype, &etype_str);
	if(ret) {
	    krb5_warn(context, ret, "krb5_enctype_to_string");
	    etype_str = NULL; /* XXX */
	}
	ret = krb5_kt_get_entry(context, dst_keytab,
				entry.principal,
				entry.vno,
				entry.keyblock.keytype,
				&dummy);
	if(ret == 0) {
	    /* this entry is already in the new keytab, so no need to
               copy it; if the keyblocks are not the same, something
               is weird, so complain about that */
	    if(!compare_keyblock(&entry.keyblock, &dummy.keyblock)) {
		krb5_warnx(context, "entry with different keyvalue "
			   "already exists for %s, keytype %s, kvno %d",
			   name_str, etype_str, entry.vno);
	    }
	    krb5_kt_free_entry(context, &dummy);
	    krb5_kt_free_entry (context, &entry);
	    free(name_str);
	    free(etype_str);
	    continue;
	} else if(ret != KRB5_KT_NOTFOUND) {
	    krb5_warn (context, ret, "%s: fetching %s/%s/%u",
		       to, name_str, etype_str, entry.vno);
	    krb5_kt_free_entry (context, &entry);
	    free(name_str);
	    free(etype_str);
	    break;
	}
	if (verbose_flag)
	    fprintf (stderr, "copying %s, keytype %s, kvno %d\n", name_str,
		     etype_str, entry.vno);
	ret = krb5_kt_add_entry (context, dst_keytab, &entry);
	krb5_kt_free_entry (context, &entry);
	if (ret) {
	    krb5_warn (context, ret, "%s: adding %s/%s/%u",
		       to, name_str, etype_str, entry.vno);
	    free(name_str);
	    free(etype_str);
	    break;
	}
	free(name_str);
	free(etype_str);
    }
    krb5_kt_end_seq_get (context, src_keytab, &cursor);

  out:
    krb5_kt_close (context, src_keytab);
    krb5_kt_close (context, dst_keytab);
    return ret != 0;
}
Ejemplo n.º 29
0
static void
get_princ_kt(krb5_context context,
	     krb5_principal *principal,
	     char *name)
{
    krb5_error_code ret;
    krb5_principal tmp;
    krb5_ccache ccache;
    krb5_kt_cursor cursor;
    krb5_keytab_entry entry;
    char *def_realm;

    if (name == NULL) {
	/*
	 * If the credential cache exists and specifies a client principal,
	 * use that.
	 */
	if (krb5_cc_default(context, &ccache) == 0) {
	    ret = krb5_cc_get_principal(context, ccache, principal);
	    krb5_cc_close(context, ccache);
	    if (ret == 0)
		return;
	}
    }

    if (name) {
	/* If the principal specifies an explicit realm, just use that. */
	int parseflags = KRB5_PRINCIPAL_PARSE_NO_DEF_REALM;

	parse_name_realm(context, name, parseflags, NULL, &tmp);
	if (krb5_principal_get_realm(context, tmp) != NULL) {
	    *principal = tmp;
	    return;
	}
    } else {
	/* Otherwise, search keytab for bare name of the default principal. */
	get_default_principal(context, &tmp);
	set_princ_realm(context, tmp, NULL);
    }

    def_realm = get_default_realm(context);

    ret = krb5_kt_start_seq_get(context, kt, &cursor);
    if (ret)
	krb5_err(context, 1, ret, "krb5_kt_start_seq_get");

    while (ret == 0 &&
           krb5_kt_next_entry(context, kt, &entry, &cursor) == 0) {
        const char *realm;

        if (!krb5_principal_compare_any_realm(context, tmp, entry.principal))
            continue;
        if (*principal &&
	    krb5_principal_compare(context, *principal, entry.principal))
            continue;
        /* The default realm takes precedence */
        realm = krb5_principal_get_realm(context, entry.principal);
        if (*principal && strcmp(def_realm, realm) == 0) {
            krb5_free_principal(context, *principal);
            ret = krb5_copy_principal(context, entry.principal, principal);
            break;
        }
        if (!*principal)
            ret = krb5_copy_principal(context, entry.principal, principal);
    }
    if (ret != 0 || (ret = krb5_kt_end_seq_get(context, kt, &cursor)) != 0)
	krb5_err(context, 1, ret, "get_princ_kt");
    if (!*principal) {
	if (name)
	    parse_name_realm(context, name, 0, NULL, principal);
	else
	    krb5_err(context, 1, KRB5_CC_NOTFOUND, "get_princ_kt");
    }

    krb5_free_principal(context, tmp);
    free(def_realm);
}
Ejemplo n.º 30
0
/*
 * Walk the keytab, looking for entries of this principal name,
 * with KVNO other than current kvno -1.
 *
 * These entries are now stale,
 * we only keep the current and previous entries around.
 *
 * Inspired by the code in Samba3 for 'use kerberos keytab'.
 */
krb5_error_code smb_krb5_remove_obsolete_keytab_entries(TALLOC_CTX *mem_ctx,
							krb5_context context,
							krb5_keytab keytab,
							uint32_t num_principals,
							krb5_principal *principals,
							krb5_kvno kvno,
							bool *found_previous,
							const char **error_string)
{
	TALLOC_CTX *tmp_ctx;
	krb5_error_code code;
	krb5_kt_cursor cursor;

	tmp_ctx = talloc_new(mem_ctx);
	if (tmp_ctx == NULL) {
		*error_string = "Cannot allocate tmp_ctx";
		return ENOMEM;
	}

	*found_previous = true;

	code = krb5_kt_start_seq_get(context, keytab, &cursor);
	switch (code) {
	case 0:
		break;
#ifdef HEIM_ERR_OPNOTSUPP
	case HEIM_ERR_OPNOTSUPP:
#endif
	case ENOENT:
	case KRB5_KT_END:
		/* no point enumerating if there isn't anything here */
		code = 0;
		goto done;
	default:
		*error_string = talloc_asprintf(mem_ctx,
						"failed to open keytab for read of old entries: %s\n",
						smb_get_krb5_error_message(context, code, mem_ctx));
		goto done;
	}

	do {
		krb5_kvno old_kvno = kvno - 1;
		krb5_keytab_entry entry;
		bool matched = false;
		uint32_t i;

		code = krb5_kt_next_entry(context, keytab, &entry, &cursor);
		if (code) {
			break;
		}

		for (i = 0; i < num_principals; i++) {
			krb5_boolean ok;

			ok = smb_krb5_kt_compare(context,
						&entry,
						principals[i],
						0,
						0);
			if (ok) {
				matched = true;
				break;
			}
		}

		if (!matched) {
			/*
			 * Free the entry, it wasn't the one we were looking
			 * for anyway
			 */
			krb5_kt_free_entry(context, &entry);
			/* Make sure we do not double free */
			ZERO_STRUCT(entry);
			continue;
		}

		/*
		 * Delete it, if it is not kvno - 1.
		 *
		 * Some keytab files store the kvno only in 8bits. Limit the
		 * compare to 8bits, so that we don't miss old keys and delete
		 * them.
		 */
		if ((entry.vno & 0xff) != (old_kvno & 0xff)) {
			krb5_error_code rc;

			/* Release the enumeration.  We are going to
			 * have to start this from the top again,
			 * because deletes during enumeration may not
			 * always be consistent.
			 *
			 * Also, the enumeration locks a FILE: keytab
			 */
			krb5_kt_end_seq_get(context, keytab, &cursor);

			code = krb5_kt_remove_entry(context, keytab, &entry);
			krb5_kt_free_entry(context, &entry);

			/* Make sure we do not double free */
			ZERO_STRUCT(entry);

			/* Deleted: Restart from the top */
			rc = krb5_kt_start_seq_get(context, keytab, &cursor);
			if (rc != 0) {
				krb5_kt_free_entry(context, &entry);

				/* Make sure we do not double free */
				ZERO_STRUCT(entry);

				DEBUG(1, ("failed to restart enumeration of keytab: %s\n",
					  smb_get_krb5_error_message(context,
								     code,
								     tmp_ctx)));

				talloc_free(tmp_ctx);
				return rc;
			}

			if (code != 0) {
				break;
			}

		} else {
			*found_previous = true;
		}

		/* Free the entry, we don't need it any more */
		krb5_kt_free_entry(context, &entry);
		/* Make sure we do not double free */
		ZERO_STRUCT(entry);
	} while (code != 0);

	krb5_kt_end_seq_get(context, keytab, &cursor);

	switch (code) {
	case 0:
		break;
	case ENOENT:
	case KRB5_KT_END:
		code = 0;
		break;
	default:
		*error_string = talloc_asprintf(mem_ctx,
						"failed in deleting old entries for principal: %s\n",
						smb_get_krb5_error_message(context,
									   code,
									   mem_ctx));
	}

	code = 0;
done:
	talloc_free(tmp_ctx);
	return code;
}