Exemple #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 */
}
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;
}
krb5_error_code
_adcli_krb5_keytab_add_entries (krb5_context k5,
                                krb5_keytab keytab,
                                krb5_principal principal,
                                krb5_kvno kvno,
                                krb5_data *password,
                                krb5_enctype *enctypes,
                                krb5_data *salt)
{
	krb5_keytab_entry entry;
	krb5_error_code code;
	int i;

	for (i = 0; enctypes[i] != 0; i++) {
		memset (&entry, 0, sizeof(entry));

		code = krb5_c_string_to_key (k5, enctypes[i], password, salt, &entry.key);
		if (code != 0)
			return code;

		entry.principal = principal;
		entry.vno = kvno;

		code = krb5_kt_add_entry (k5, keytab, &entry);

		entry.principal = NULL;
		krb5_free_keytab_entry_contents (k5, &entry);

		if (code != 0)
			return code;
	}

	return 0;
}
Exemple #4
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;
}
Exemple #5
0
 krb5_error_code smb_krb5_kt_free_entry(krb5_context context, krb5_keytab_entry *kt_entry)
{
#if defined(HAVE_KRB5_KT_FREE_ENTRY)
	return krb5_kt_free_entry(context, kt_entry);
#elif defined(HAVE_KRB5_FREE_KEYTAB_ENTRY_CONTENTS)
	return krb5_free_keytab_entry_contents(context, kt_entry);
#else
#error UNKNOWN_KT_FREE_FUNCTION
#endif
}
Exemple #6
0
KRB5Keytab::cursor::~cursor()
{
    krb5_free_keytab_entry_contents(g_context.get(), &m_entry);
    memset(&m_entry, 0, sizeof(m_entry));
    // Tell m_princ to not free its contents!
    m_princ.reset_no_free(NULL);
    krb5_error_code ret = krb5_kt_end_seq_get(g_context.get(), m_keytab.m_keytab, &m_cursor);
    if (ret) {
        // FIXME: shouldn't throw from destructor...
        throw KRB5Exception("krb5_kt_end_seq_get", 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;
 }
Exemple #8
0
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
}
Exemple #9
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;
}
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;
}        
Exemple #11
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;
}
Exemple #12
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;
}
Exemple #13
0
static int gss_create_principal(AFPObj *obj)
{
    int rv = -1;
#ifdef HAVE_KERBEROS
    krb5_context context;
    krb5_error_code ret;
    const char *error_msg;
    krb5_keytab keytab;
    krb5_keytab_entry entry;
    krb5_principal service_principal;
    char *principal;
    krb5_kt_cursor cursor;

    if (krb5_init_context(&context)) {
        LOG(log_error, logtype_afpd, "gss_create_principal: failed to intialize a krb5_context");
        goto exit;
    }
    if ((ret = krb5_kt_default(context, &keytab)))
        goto krb5_error;

    if (obj->options.k5service && obj->options.fqdn && obj->options.k5realm) {
        LOG(log_debug, logtype_afpd, "gss_create_principal: using service principal specified in options");
            
        if ((ret = krb5_build_principal(context,
                                        &service_principal,
                                        strlen(obj->options.k5realm),
                                        obj->options.k5realm,
                                        obj->options.k5service,
                                        obj->options.fqdn,
                                        NULL)))
            goto krb5_error;

        if ((ret = krb5_kt_get_entry(context,
                                     keytab,
                                     service_principal,
                                     0, // kvno - wildcard
                                     0, // enctype - wildcard
                                     &entry)) == KRB5_KT_NOTFOUND) {
            krb5_unparse_name(context, service_principal, &principal);
            LOG(log_error, logtype_afpd, "gss_create_principal: specified service principal '%s' not found in keytab", principal);
#ifdef HAVE_KRB5_FREE_UNPARSED_NAME
            krb5_free_unparsed_name(context, principal);
#else
            krb5_xfree(principal);
#endif
            goto krb5_cleanup;
        }
        krb5_free_principal(context, service_principal);
        if (ret)
            goto krb5_error;
    } else {
        LOG(log_debug, logtype_afpd, "gss_create_principal: using first entry from keytab as service principal");
        if ((ret = krb5_kt_start_seq_get(context, keytab, &cursor)))
            goto krb5_error;
        ret = krb5_kt_next_entry(context, keytab, &entry, &cursor);
        krb5_kt_end_seq_get(context, keytab, &cursor);
        if (ret)
            goto krb5_error;
    }

    krb5_unparse_name(context, entry.principal, &principal);
#ifdef HAVE_KRB5_FREE_KEYTAB_ENTRY_CONTENTS
    krb5_free_keytab_entry_contents(context, &entry);
#elif defined(HAVE_KRB5_KT_FREE_ENTRY)
    krb5_kt_free_entry(context, &entry);
#endif
    set_principal(obj, principal);
    free(principal);
    rv = 0;
    goto krb5_cleanup;

krb5_error:
    if (ret) {
        error_msg = krb5_get_error_message(context, ret);
        LOG(log_note, logtype_afpd, "Can't get principal from default keytab: %s",
            (char *)error_msg);
#ifdef HAVE_KRB5_FREE_ERROR_MESSAGE
        krb5_free_error_message(context, error_msg);
#else
        krb5_xfree(error_msg);
#endif
    }

krb5_cleanup:
    krb5_kt_close(context, keytab);
    krb5_free_context(context);

#else /* ! HAVE_KERBEROS */
    if (!obj->options.k5service || !obj->options.fqdn || !obj->options.k5realm)
        goto exit;

    char principal[255];
    size_t len = snprintf(principal, sizeof(principal), "%s/%s@%s",
                          obj->options.k5service, obj->options.fqdn, obj->options.k5realm);
    (void)set_principal(obj, principal);
    rv = 0;
#endif /* HAVE_KERBEROS */

exit:
    return rv;
}
Exemple #14
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 */
}
/*
 * create Kerberos memory cache
 */
int krb5_create_cache(struct main_args *margs,char *domain) {

    krb5_keytab	    keytab = 0;
    krb5_keytab_entry entry;
    krb5_kt_cursor cursor;
    krb5_creds	    *creds=NULL;
    krb5_creds	    *tgt_creds=NULL;
    krb5_principal  *principal_list = NULL;
    krb5_principal  principal = NULL;
    char  *service;
    char  *keytab_name=NULL,*principal_name=NULL,*mem_cache=NULL;
    char  buf[KT_PATH_MAX], *p;
    int nprinc=0;
    int i;
    int	retval=0; 
    int	found=0; 
    krb5_error_code 		code = 0;

    kparam.context=NULL;

    if (!domain || !strcmp(domain,"")) 
	return(1);

    /*
     * Initialise Kerberos
     */

    code = krb5_init_context(&kparam.context);
    if (code)
    {
	fprintf(stderr, "%s| %s: Error while initialising Kerberos library : %s\n",LogTime(), PROGRAM, error_message(code));
	retval=1;
	goto cleanup;
    }

    /*
     * getting default keytab name
     */

    if (margs->debug)
	fprintf(stderr, "%s| %s: Get default keytab file name\n",LogTime(), PROGRAM);
    krb5_kt_default_name(kparam.context, buf, KT_PATH_MAX);
    p = strchr(buf, ':');             /* Find the end if "FILE:" */
    if (p) p++;                       /* step past : */
    keytab_name = strdup(p ? p : buf);
    if (margs->debug)
	fprintf(stderr, "%s| %s: Got default keytab file name %s\n",LogTime(), PROGRAM, keytab_name);

    code = krb5_kt_resolve(kparam.context, keytab_name, &keytab);
    if (code)
    {
	fprintf(stderr, "%s| %s: Error while resolving keytab %s : %s\n", LogTime(), PROGRAM, keytab_name,error_message(code));
	retval=1;
	goto cleanup;
    }

    code = krb5_kt_start_seq_get(kparam.context, keytab, &cursor);
    if (code)
    {
	fprintf(stderr, "%s| %s: Error while starting keytab scan : %s\n", LogTime(), PROGRAM, error_message(code));
	retval=1;
	goto cleanup;
    }
    if (margs->debug)
	fprintf(stderr, "%s| %s: Get principal name from keytab %s\n",LogTime(), PROGRAM, keytab_name);

    nprinc=0;
    while ((code = krb5_kt_next_entry(kparam.context, keytab, &entry, &cursor)) == 0) 
    {

        principal_list=realloc(principal_list,sizeof(krb5_principal)*(nprinc+1));
        krb5_copy_principal(kparam.context,entry.principal,&principal_list[nprinc++]);
	if (margs->debug)
#ifdef HAVE_HEIMDAL_KERBEROS
	    fprintf(stderr, "%s| %s: Keytab entry has realm name: %s\n", LogTime(), PROGRAM, entry.principal->realm);
#else
	    fprintf(stderr, "%s| %s: Keytab entry has realm name: %s\n", LogTime(), PROGRAM, krb5_princ_realm(kparam.context, entry.principal)->data);
#endif
#ifdef HAVE_HEIMDAL_KERBEROS
	    if (!strcasecmp(domain, entry.principal->realm))
#else
	    if (!strcasecmp(domain,krb5_princ_realm(kparam.context, entry.principal)->data))
#endif
	    {
		code = krb5_unparse_name(kparam.context, entry.principal, &principal_name);
		if (code)
		{
		    fprintf(stderr, "%s| %s: Error while unparsing principal name : %s\n", LogTime(), PROGRAM, error_message(code));
		} else {
		    if (margs->debug)
			fprintf(stderr, "%s| %s: Found principal name: %s\n", LogTime(), PROGRAM, principal_name);
		    found=1;
                }
	    }
#if defined(HAVE_HEIMDAL_KERBEROS) || ( defined(HAVE_KRB5_KT_FREE_ENTRY) && HAVE_DECL_KRB5_KT_FREE_ENTRY==1)
	code = krb5_kt_free_entry(kparam.context,&entry);
#else
	code = krb5_free_keytab_entry_contents(kparam.context,&entry);
#endif
	if (code)
        {
	    fprintf(stderr, "%s| %s: Error while freeing keytab entry : %s\n", LogTime(), PROGRAM, error_message(code));
	    retval=1;
	    break;
        }
        if (found) 
            break;
    }

    if (code && code != KRB5_KT_END) 
    {
	fprintf(stderr, "%s| %s: Error while scanning keytab : %s\n", LogTime(), PROGRAM, error_message(code));
	retval=1;
	goto cleanup;
    }

    code = krb5_kt_end_seq_get(kparam.context, keytab, &cursor);
    if (code)
    {
	fprintf(stderr, "%s| %s: Error while ending keytab scan : %s\n", LogTime(), PROGRAM, error_message(code));
	retval=1;
	goto cleanup;
    }

    /*
     * prepare memory credential cache
     */
#ifndef HAVE_KRB5_MEMORY_CACHE
    mem_cache=malloc(strlen("FILE:/tmp/squid_ldap_")+16);
    snprintf(mem_cache,strlen("FILE:/tmp/squid_ldap_")+16,"FILE:/tmp/squid_ldap_%d",(int)getpid());
#else    
    mem_cache=malloc(strlen("MEMORY:squid_ldap_")+16);
    snprintf(mem_cache,strlen("MEMORY:squid_ldap_")+16,"MEMORY:squid_ldap_%d",(int)getpid());
#endif    
    
    setenv("KRB5CCNAME",mem_cache,1);
    if (margs->debug)
	fprintf(stderr, "%s| %s: Set credential cache to %s\n",LogTime(), PROGRAM,mem_cache);
    code = krb5_cc_resolve(kparam.context, mem_cache , &kparam.cc);
    if (code) 
    {
	fprintf(stderr, "%s| %s: Error while resolving memory ccache : %s\n",LogTime(), PROGRAM, error_message(code));
	retval=1;
	goto cleanup;
    }

    /*
     * if no principal name found in keytab for domain use the prinipal name which can get a TGT
     */
    if (!principal_name)
    {
	if (margs->debug) {
	    fprintf(stderr, "%s| %s: Did not find a principal in keytab for domain %s.\n",LogTime(), PROGRAM,domain);
	    fprintf(stderr, "%s| %s: Try to get principal of trusted domain.\n",LogTime(), PROGRAM);
	}
	creds = malloc(sizeof(*creds));
	memset(creds, 0, sizeof(*creds));

        for (i=0;i<nprinc;i++) {	
            /*
             * get credentials
             */
            code = krb5_unparse_name(kparam.context, principal_list[i], &principal_name);
            if (code)
            {
                if (margs->debug)
                    fprintf(stderr, "%s| %s: Error while unparsing principal name : %s\n", LogTime(), PROGRAM, error_message(code));
		goto loop_end;
            }
	    if (margs->debug)
	        fprintf(stderr, "%s| %s: Keytab entry has principal: %s\n", LogTime(), PROGRAM, principal_name);

#if HAVE_GET_INIT_CREDS_KEYTAB
            code = krb5_get_init_creds_keytab(kparam.context, creds, principal_list[i], keytab, 0, NULL, NULL);
#else
            service=malloc(strlen("krbtgt")+2*strlen(domain)+3);
            snprintf(service,strlen("krbtgt")+2*strlen(domain)+3,"krbtgt/%s@%s",domain,domain);
            creds->client=principal_list[i];
            code = krb5_parse_name(kparam.context,service,&creds->server);
            if (service)
               free(service);
            code = krb5_get_in_tkt_with_keytab(kparam.context, 0, NULL, NULL, NULL, keytab, NULL, creds, 0);
#endif
            if (code)
            {
		if (margs->debug)
		    fprintf(stderr, "%s| %s: Error while initialising credentials from keytab : %s\n",LogTime(), PROGRAM, error_message(code));
		goto loop_end;
            }

            code = krb5_cc_initialize(kparam.context, kparam.cc, principal_list[i]);
            if (code)
            {
                fprintf(stderr, "%s| %s: Error while initializing memory caches : %s\n",LogTime(), PROGRAM, error_message(code));
		goto loop_end;
            }

	    code = krb5_cc_store_cred(kparam.context, kparam.cc, creds);
	    if (code)
	    {
	        if (margs->debug)
		    fprintf(stderr, "%s| %s: Error while storing credentials : %s\n",LogTime(), PROGRAM, error_message(code));
		goto loop_end;
    	    }

            if (creds->server)
               krb5_free_principal(kparam.context,creds->server);
#ifdef HAVE_HEIMDAL_KERBEROS
            service=malloc(strlen("krbtgt")+strlen(domain)+strlen(principal_list[i]->realm)+3);
            snprintf(service,strlen("krbtgt")+strlen(domain)+strlen(principal_list[i]->realm)+3,"krbtgt/%s@%s",domain,principal_list[i]->realm);
#else
            service=malloc(strlen("krbtgt")+strlen(domain)+strlen(krb5_princ_realm(kparam.context, principal_list[i])->data)+3);
            snprintf(service,strlen("krbtgt")+strlen(domain)+strlen(krb5_princ_realm(kparam.context, principal_list[i])->data)+3,"krbtgt/%s@%s",domain,krb5_princ_realm(kparam.context, principal_list[i])->data);
#endif
            code = krb5_parse_name(kparam.context,service,&creds->server);
            if (service)
               free(service);
	    if (code)
	    {
		fprintf(stderr, "%s| %s: Error while initialising TGT credentials : %s\n",LogTime(), PROGRAM, error_message(code));
		goto loop_end;
	    }

	    code = krb5_get_credentials(kparam.context, 0, kparam.cc, creds, &tgt_creds);
	    if (code) {
		if (margs->debug)
		    fprintf(stderr, "%s| %s: Error while getting tgt : %s\n",LogTime(), PROGRAM, error_message(code));
		goto loop_end;
	    } else {
		if (margs->debug)
		    fprintf(stderr, "%s| %s: Found trusted principal name: %s\n", LogTime(), PROGRAM, principal_name);
		break;
	    }

loop_end:
            if (principal_name) 
	        free(principal_name);
            principal_name=NULL;
	}
            
	if (tgt_creds)
	    krb5_free_creds(kparam.context,tgt_creds);
        tgt_creds=NULL;
	if (creds)
	    krb5_free_creds(kparam.context,creds);
        creds=NULL;
    }


    if (principal_name) {

	if (margs->debug)
	    fprintf(stderr, "%s| %s: Got principal name %s\n",LogTime(), PROGRAM, principal_name);
	/*
	 * build principal
	 */
	code = krb5_parse_name(kparam.context, principal_name, &principal);
	if (code)
	{
	    fprintf(stderr, "%s| %s: Error while parsing name %s : %s\n", LogTime(), PROGRAM, principal_name,error_message(code));
	    retval=1;
	    goto cleanup;
	}
  
	creds = malloc(sizeof(*creds));
	memset(creds, 0, sizeof(*creds));

	/*
	 * get credentials
	 */
#if HAVE_GET_INIT_CREDS_KEYTAB
        code = krb5_get_init_creds_keytab(kparam.context, creds, principal, keytab, 0, NULL, NULL);
#else
        service=malloc(strlen("krbtgt")+2*strlen(domain)+3);
        snprintf(service,strlen("krbtgt")+2*strlen(domain)+3,"krbtgt/%s@%s",domain,domain);
        creds->client=principal;
        code = krb5_parse_name(kparam.context,service,&creds->server);
        if (service)
           free(service);
        code = krb5_get_in_tkt_with_keytab(kparam.context, 0, NULL, NULL, NULL, keytab, NULL, creds, 0);
#endif
	if (code)
	{
	    fprintf(stderr, "%s| %s: Error while initialising credentials from keytab : %s\n",LogTime(), PROGRAM, error_message(code));
	    retval=1;
	    goto cleanup;
	}

        code = krb5_cc_initialize(kparam.context, kparam.cc, principal);
        if (code)
        {
            fprintf(stderr, "%s| %s: Error while initializing memory caches : %s\n",LogTime(), PROGRAM, error_message(code));
            retval=1;
            goto cleanup;
        }

	code = krb5_cc_store_cred(kparam.context, kparam.cc, creds);
	if (code) 
	{
	    fprintf(stderr, "%s| %s: Error while storing credentials : %s\n",LogTime(), PROGRAM, error_message(code));
	    retval=1;
	    goto cleanup;
	}
	if (margs->debug)
	    fprintf(stderr, "%s| %s: Stored credentials\n",LogTime(), PROGRAM);
    } else {
	if (margs->debug)
	    fprintf(stderr, "%s| %s: Got no principal name\n",LogTime(), PROGRAM);
	retval=1;
    }
 cleanup:
    if (keytab)
        krb5_kt_close(kparam.context, keytab);
    if (keytab_name)
	free(keytab_name);
    if (principal_name)
	free(principal_name);
    if (mem_cache)
	free(mem_cache);
    if (principal)
	krb5_free_principal(kparam.context,principal);
    for (i=0;i<nprinc;i++) {
        if (principal_list[i])
	    krb5_free_principal(kparam.context,principal_list[i]);
    }
    if (principal_list)
        free(principal_list);
    if (creds)
	krb5_free_creds(kparam.context,creds);

    return(retval);
}
 ~State() {
   krb5_free_keytab_entry_contents(kt_->getContext(), &ktentry_);
   krb5_error_code code =
     krb5_kt_end_seq_get(kt_->getContext(), kt_->get(), &cursor_);
   raiseIf(kt_->getContext(), code, "ending read of keytab " + kt_->getName());
 }
Exemple #17
0
krb5_error_code sss_extract_pac(krb5_context ctx,
                                krb5_ccache ccache,
                                krb5_principal server_principal,
                                krb5_principal client_principal,
                                krb5_keytab keytab,
                                krb5_authdata ***_pac_authdata)
{
#ifdef HAVE_PAC_RESPONDER
    krb5_error_code kerr;
    krb5_creds mcred;
    krb5_creds cred;
    krb5_authdata **pac_authdata = NULL;
    krb5_pac pac = NULL;
    int ret;
    krb5_ticket *ticket = NULL;
    krb5_keytab_entry entry;

    memset(&entry, 0, sizeof(entry));
    memset(&mcred, 0, sizeof(mcred));
    memset(&cred, 0, sizeof(mcred));

    mcred.server = server_principal;
    mcred.client = client_principal;

    kerr = krb5_cc_retrieve_cred(ctx, ccache, 0, &mcred, &cred);
    if (kerr != 0) {
        DEBUG(SSSDBG_OP_FAILURE, "krb5_cc_retrieve_cred failed.\n");
        goto done;
    }

    kerr = krb5_decode_ticket(&cred.ticket, &ticket);
    if (kerr != 0) {
        DEBUG(SSSDBG_OP_FAILURE, "krb5_decode_ticket failed.\n");
        goto done;
    }

    kerr = krb5_server_decrypt_ticket_keytab(ctx, keytab, ticket);
    if (kerr != 0) {
        DEBUG(SSSDBG_OP_FAILURE, "krb5_server_decrypt_ticket_keytab failed.\n");
        goto done;
    }

    kerr = sss_krb5_find_authdata(ctx,
                                  ticket->enc_part2->authorization_data, NULL,
                                  KRB5_AUTHDATA_WIN2K_PAC, &pac_authdata);
    if (kerr != 0) {
        DEBUG(SSSDBG_OP_FAILURE, "krb5_find_authdata failed.\n");
        goto done;
    }

    if (pac_authdata == NULL || pac_authdata[0] == NULL) {
        DEBUG(SSSDBG_OP_FAILURE, "No PAC authdata available.\n");
        kerr = ENOENT;
        goto done;
    }

    if (pac_authdata[1] != NULL) {
        DEBUG(SSSDBG_OP_FAILURE, "More than one PAC autdata found.\n");
        kerr = EINVAL;
        goto done;
    }

    kerr = krb5_pac_parse(ctx, pac_authdata[0]->contents,
                          pac_authdata[0]->length, &pac);
    if (kerr != 0) {
        DEBUG(SSSDBG_OP_FAILURE, "krb5_pac_parse failed.\n");
        goto done;
    }

    kerr = krb5_kt_get_entry(ctx, keytab, ticket->server,
                             ticket->enc_part.kvno, ticket->enc_part.enctype,
                             &entry);
    if (kerr != 0) {
        DEBUG(SSSDBG_OP_FAILURE, "krb5_kt_get_entry failed.\n");
        goto done;
    }

    kerr = krb5_pac_verify(ctx, pac, 0, NULL, &entry.key, NULL);
    if (kerr != 0) {
        DEBUG(SSSDBG_OP_FAILURE, "krb5_pac_verify failed.\n");
        goto done;
    }

    ret = unsetenv("_SSS_LOOPS");
    if (ret != EOK) {
        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to unset _SSS_LOOPS, "
                  "sss_pac_make_request will most certainly fail.\n");
    }

    *_pac_authdata = pac_authdata;
    kerr = 0;

done:
    if (kerr != 0) {
        krb5_free_authdata(ctx, pac_authdata);
    }
    if (entry.magic != 0) {
        krb5_free_keytab_entry_contents(ctx, &entry);
    }
    krb5_pac_free(ctx, pac);
    if (ticket != NULL) {
        krb5_free_ticket(ctx, ticket);
    }

    krb5_free_cred_contents(ctx, &cred);
    return kerr;
#else
    return ENOTSUP;
#endif
}
Exemple #18
0
krb5_error_code
sss_krb5_free_keytab_entry_contents(krb5_context context,
                                    krb5_keytab_entry *entry)
{
    return krb5_free_keytab_entry_contents(context, entry);
}
Exemple #19
0
static void
do_keytab(const char *name)
{
    krb5_error_code ret;
    krb5_keytab kt;
    krb5_keytab_entry entry;
    krb5_kt_cursor cursor;
    unsigned int i;
    char buf[BUFSIZ]; /* Hopefully large enough for any type */
    char *pname;

    if (name == NULL && use_client_keytab) {
        ret = krb5_kt_client_default(context, &kt);
        if (ret) {
            com_err(progname, ret, _("while getting default client keytab"));
            exit(1);
        }
    } else if (name == NULL) {
        ret = krb5_kt_default(context, &kt);
        if (ret) {
            com_err(progname, ret, _("while getting default keytab"));
            exit(1);
        }
    } else {
        ret = krb5_kt_resolve(context, name, &kt);
        if (ret) {
            com_err(progname, ret, _("while resolving keytab %s"), name);
            exit(1);
        }
    }

    ret = krb5_kt_get_name(context, kt, buf, BUFSIZ);
    if (ret) {
        com_err(progname, ret, _("while getting keytab name"));
        exit(1);
    }

    printf("Keytab name: %s\n", buf);

    ret = krb5_kt_start_seq_get(context, kt, &cursor);
    if (ret) {
        com_err(progname, ret, _("while starting keytab scan"));
        exit(1);
    }

    /* XXX Translating would disturb table alignment; skip for now. */
    if (show_time) {
        printf("KVNO Timestamp");
        fillit(stdout, timestamp_width - sizeof("Timestamp") + 2, (int) ' ');
        printf("Principal\n");
        printf("---- ");
        fillit(stdout, timestamp_width, (int) '-');
        printf(" ");
        fillit(stdout, 78 - timestamp_width - sizeof("KVNO"), (int) '-');
        printf("\n");
    } else {
        printf("KVNO Principal\n");
        printf("---- ------------------------------------------------"
               "--------------------------\n");
    }

    while ((ret = krb5_kt_next_entry(context, kt, &entry, &cursor)) == 0) {
        ret = krb5_unparse_name(context, entry.principal, &pname);
        if (ret) {
            com_err(progname, ret, _("while unparsing principal name"));
            exit(1);
        }
        printf("%4d ", entry.vno);
        if (show_time) {
            printtime(entry.timestamp);
            printf(" ");
        }
        printf("%s", pname);
        if (show_etype)
            printf(" (%s) " , etype_string(entry.key.enctype));
        if (show_keys) {
            printf(" (0x");
            for (i = 0; i < entry.key.length; i++)
                printf("%02x", entry.key.contents[i]);
            printf(")");
        }
        printf("\n");
        krb5_free_unparsed_name(context, pname);
        krb5_free_keytab_entry_contents(context, &entry);
    }
    if (ret && ret != KRB5_KT_END) {
        com_err(progname, ret, _("while scanning keytab"));
        exit(1);
    }
    ret = krb5_kt_end_seq_get(context, kt, &cursor);
    if (ret) {
        com_err(progname, ret, _("while ending keytab scan"));
        exit(1);
    }
    exit(0);
}
Exemple #20
0
char* server_principal_details(const char* service, const char* hostname)
{
    char match[1024];
    size_t match_len = 0;
    char* result = NULL;
    
    int code;
    krb5_context kcontext;
    krb5_keytab kt = NULL;
    krb5_kt_cursor cursor = NULL;
    krb5_keytab_entry entry;
    char* pname = NULL;
    
    // Generate the principal prefix we want to match
    snprintf(match, 1024, "%s/%s@", service, hostname);
    match_len = strlen(match);
    
    code = krb5_init_context(&kcontext);
    if (code)
    {
        PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))",
                                                          "Cannot initialize Kerberos5 context", code));
        return NULL;
    }
    
    if ((code = krb5_kt_default(kcontext, &kt)))
    {
        PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))",
                                                          "Cannot get default keytab", code));
        goto end;
    }
    
    if ((code = krb5_kt_start_seq_get(kcontext, kt, &cursor)))
    {
        PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))",
                                                          "Cannot get sequence cursor from keytab", code));
        goto end;
    }
    
    while ((code = krb5_kt_next_entry(kcontext, kt, &entry, &cursor)) == 0)
    {
        if ((code = krb5_unparse_name(kcontext, entry.principal, &pname)))
        {
            PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))",
                                                              "Cannot parse principal name from keytab", code));
            goto end;
        }
        
        if (strncmp(pname, match, match_len) == 0)
        {
            result = malloc(strlen(pname) + 1);
            strcpy(result, pname);
            krb5_free_unparsed_name(kcontext, pname);
            krb5_free_keytab_entry_contents(kcontext, &entry);
            break;
        }
        
        krb5_free_unparsed_name(kcontext, pname);
        krb5_free_keytab_entry_contents(kcontext, &entry);
    }
    
    if (result == NULL)
    {
        PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))",
                                                          "Principal not found in keytab", -1));
    }
    
end:
    if (cursor)
        krb5_kt_end_seq_get(kcontext, kt, &cursor);
    if (kt)
        krb5_kt_close(kcontext, kt);
    krb5_free_context(kcontext);
    
    return result;
}
Exemple #21
0
/*
 * Print a krb5 ticket in our service key, for the supplied client principal.
 * The path to a keytab is mandatory, but the service principal may be
 * guessed from the keytab contents if desired.  The keytab entry must be
 * one of the allowed_enctypes (a zero-terminated list) if a non-NULL
 * parameter is passed.
 */
krb5_error_code
get_credv5_akimpersonate(krb5_context context, char* keytab,
			 krb5_principal service_principal,
			 krb5_principal client_principal, time_t starttime,
			 time_t endtime, const int *allowed_enctypes,
			 krb5_creds** out_creds /* out */ )
{
    krb5_error_code code;
    krb5_keytab kt = 0;
    krb5_keytab_entry entry[1];
    krb5_creds *creds = 0;
    krb5_enctype enctype;
    krb5_keyblock session_key[1];
#if USING_HEIMDAL
    Ticket *ticket_reply;
    EncTicketPart *enc_tkt_reply;
#else
    krb5_ticket *ticket_reply;
    krb5_enc_tkt_part *enc_tkt_reply;
#endif
    *out_creds = NULL;
    enctype = 0; /* AKIMPERSONATE_IGNORE_ENCTYPE */
    memset(entry, 0, sizeof *entry);
    memset(session_key, 0, sizeof *session_key);
    ticket_reply = NULL;
    enc_tkt_reply = NULL;

    creds = calloc(1, sizeof(*creds));
    if (creds == NULL) {
        code = ENOMEM;
        goto cleanup;
    }
    code = alloc_ticket(&ticket_reply);
    if (code != 0)
	goto cleanup;
    code = alloc_enc_tkt_part(&enc_tkt_reply);
    if (code != 0)
	goto cleanup;
    /* Empty list of allowed etypes must fail.  Do it here to avoid issues. */
    if (allowed_enctypes != NULL && *allowed_enctypes == 0) {
	code = KRB5_BAD_ENCTYPE;
	goto cleanup;
    }
    if (allowed_enctypes == NULL)
        allowed_enctypes = any_enctype;

    if (keytab != NULL)
      code = krb5_kt_resolve(context, keytab, &kt);
    else
      code = krb5_kt_default(context, &kt);
    if (code != 0)
        goto cleanup;

    code = pick_enctype_and_principal(context, kt, allowed_enctypes,
				      &enctype, &service_principal, entry);
    if (code != 0)
	goto cleanup;

    /* Conjure up a random session key */
    deref_keyblock_enctype(session_key) = enctype;
#if USING_HEIMDAL
    code = krb5_generate_random_keyblock(context, enctype, session_key);
#else
    code = krb5_c_make_random_key(context, enctype, session_key);
#endif
    if (code != 0)
        goto cleanup;

    populate_enc_tkt(session_key, client_principal, starttime, endtime,
		     enc_tkt_reply);

    code = encrypt_enc_tkt(context, service_principal, entry, ticket_reply,
			   enc_tkt_reply);
    if (code != 0)
	goto cleanup;

    code = populate_creds(context, service_principal, client_principal,
			  session_key, ticket_reply, enc_tkt_reply, creds);
    if (code != 0)
	goto cleanup;

    /* return creds */
    *out_creds = creds;
    creds = NULL;
cleanup:
    if (deref_enc_data(&ticket_reply->enc_part) != NULL)
        free(deref_enc_data(&ticket_reply->enc_part));
    krb5_free_keytab_entry_contents(context, entry);
    if (client_principal != NULL)
        krb5_free_principal(context, client_principal);
    if (service_principal != NULL)
        krb5_free_principal(context, service_principal);
    if (kt != NULL)
        krb5_kt_close(context, kt);
    if (creds != NULL)
	krb5_free_creds(context, creds);
    krb5_free_keyblock_contents(context, session_key);
    free_ticket(ticket_reply);
    free_enc_tkt_part(enc_tkt_reply);
    return code;
}
krb5_error_code KRB5_CALLCONV
krb5_kt_free_entry (krb5_context context, krb5_keytab_entry *entry)
{
    return krb5_free_keytab_entry_contents (context, entry);
}
krb5_error_code KRB5_CALLCONV
krb5_server_decrypt_ticket_keytab(krb5_context context,
				  const krb5_keytab keytab,
				  krb5_ticket *ticket)
{
    krb5_error_code 	  retval;
    krb5_keytab_entry 	  ktent;

    retval = KRB5_KT_NOTFOUND;

    if (keytab->ops->start_seq_get == NULL) {
	retval = krb5_kt_get_entry(context, keytab,
				   ticket->server,
				   ticket->enc_part.kvno,
				   ticket->enc_part.enctype, &ktent);
	if (retval == 0) {
	    retval = krb5int_server_decrypt_ticket_keyblock(context, &ktent.key, ticket);

	    (void) krb5_free_keytab_entry_contents(context, &ktent);
	}
    } else {
	krb5_error_code code;
	krb5_kt_cursor cursor;

	retval = krb5_kt_start_seq_get(context, keytab, &cursor);
	if (retval != 0)
	    goto map_error;

	while ((code = krb5_kt_next_entry(context, keytab,
					  &ktent, &cursor)) == 0) {
	    if (ktent.key.enctype != ticket->enc_part.enctype)
		continue;

	    retval = krb5int_server_decrypt_ticket_keyblock(context, &ktent.key, ticket);
	    if (retval == 0) {
		krb5_principal tmp;

		retval = krb5_copy_principal(context, ktent.principal, &tmp);
		if (retval == 0) {
		    krb5_free_principal(context, ticket->server);
		    ticket->server = tmp;
		}
		(void) krb5_free_keytab_entry_contents(context, &ktent);
		break;
	    }
	    (void) krb5_free_keytab_entry_contents(context, &ktent);
	}

	code = krb5_kt_end_seq_get(context, keytab, &cursor);
	if (code != 0)
	    retval = code;
    }

map_error:
    switch (retval) {
    case KRB5_KT_KVNONOTFOUND:
    case KRB5_KT_NOTFOUND:
    case KRB5KRB_AP_ERR_BAD_INTEGRITY:
	retval = KRB5KRB_AP_WRONG_PRINC;
	break;
    default:
	break;
    }

    return retval;
}
Exemple #24
0
static void
kt_test(krb5_context context, const char *name)
{
    krb5_error_code kret;
    krb5_keytab kt;
    const char *type;
    char buf[BUFSIZ];
    char *p;
    krb5_keytab_entry kent, kent2;
    krb5_principal princ;
    krb5_kt_cursor cursor, cursor2;
    int cnt;

    kret = krb5_kt_resolve(context, name, &kt);
    CHECK(kret, "resolve");

    type = krb5_kt_get_type(context, kt);
    CHECK_STR(type, "getting kt type");
    printf("  Type is: %s\n", type);

    kret = krb5_kt_get_name(context, kt, buf, sizeof(buf));
    CHECK(kret, "get_name");
    printf("  Name is: %s\n", buf);

    /* Check that length checks fail */
    /* The buffer is allocated too small - to allow for valgrind test of
       overflows
    */
    p = malloc(strlen(buf));
    kret = krb5_kt_get_name(context, kt, p, 1);
    if(kret != KRB5_KT_NAME_TOOLONG) {
        CHECK(kret, "get_name - size 1");
    }


    kret = krb5_kt_get_name(context, kt, p, strlen(buf));
    if(kret != KRB5_KT_NAME_TOOLONG) {
        CHECK(kret, "get_name");
    }
    free(p);

    /* Try to lookup unknown principal - when keytab does not exist*/
    kret = krb5_parse_name(context, "test/[email protected]", &princ);
    CHECK(kret, "parsing principal");


    kret = krb5_kt_get_entry(context, kt, princ, 0, 0, &kent);
    if((kret != KRB5_KT_NOTFOUND) && (kret != ENOENT)) {
        CHECK(kret, "Getting non-existant entry");
    }


    /* ===================   Add entries to keytab ================= */
    /*
     * Add the following for this principal
     * enctype 1, kvno 1, key = "1"
     * enctype 2, kvno 1, key = "1"
     * enctype 1, kvno 2, key = "2"
     */
    memset(&kent, 0, sizeof(kent));
    kent.magic = KV5M_KEYTAB_ENTRY;
    kent.principal = princ;
    kent.timestamp = 327689;
    kent.vno = 1;
    kent.key.magic = KV5M_KEYBLOCK;
    kent.key.enctype = 1;
    kent.key.length = 1;
    kent.key.contents = (krb5_octet *) "1";


    kret = krb5_kt_add_entry(context, kt, &kent);
    CHECK(kret, "Adding initial entry");

    kent.key.enctype = 2;
    kret = krb5_kt_add_entry(context, kt, &kent);
    CHECK(kret, "Adding second entry");

    kent.key.enctype = 1;
    kent.vno = 2;
    kent.key.contents = (krb5_octet *) "2";
    kret = krb5_kt_add_entry(context, kt, &kent);
    CHECK(kret, "Adding third entry");

    /* Free memory */
    krb5_free_principal(context, princ);

    /* ==============   Test iterating over contents of keytab ========= */

    kret = krb5_kt_start_seq_get(context, kt, &cursor);
    CHECK(kret, "Start sequence get");


    memset(&kent, 0, sizeof(kent));
    cnt = 0;
    while((kret = krb5_kt_next_entry(context, kt, &kent, &cursor)) == 0) {
        if(((kent.vno != 1) && (kent.vno != 2)) ||
           ((kent.key.enctype != 1) && (kent.key.enctype != 2)) ||
           (kent.key.length != 1) ||
           (kent.key.contents[0] != kent.vno +'0')) {
            fprintf(stderr, "Error in read contents\n");
            exit(1);
        }

        if((kent.magic != KV5M_KEYTAB_ENTRY) ||
           (kent.key.magic != KV5M_KEYBLOCK)) {
            fprintf(stderr, "Magic number in sequence not proper\n");
            exit(1);
        }

        cnt++;
        krb5_free_keytab_entry_contents(context, &kent);
    }
    if (kret != KRB5_KT_END) {
        CHECK(kret, "getting next entry");
    }

    if(cnt != 3) {
        fprintf(stderr, "Mismatch in number of entries in keytab");
    }

    kret = krb5_kt_end_seq_get(context, kt, &cursor);
    CHECK(kret, "End sequence get");


    /* ==========================   get_entry tests ============== */

    /* Try to lookup unknown principal  - now that keytab exists*/
    kret = krb5_parse_name(context, "test3/[email protected]", &princ);
    CHECK(kret, "parsing principal");


    kret = krb5_kt_get_entry(context, kt, princ, 0, 0, &kent);
    if((kret != KRB5_KT_NOTFOUND)) {
        CHECK(kret, "Getting non-existant entry");
    }

    krb5_free_principal(context, princ);

    /* Try to lookup known principal */
    kret = krb5_parse_name(context, "test/[email protected]", &princ);
    CHECK(kret, "parsing principal");

    kret = krb5_kt_get_entry(context, kt, princ, 0, 0, &kent);
    CHECK(kret, "looking up principal");

    /* Ensure a valid answer  - we did not specify an enctype or kvno */
    if (!krb5_principal_compare(context, princ, kent.principal) ||
        ((kent.vno != 1) && (kent.vno != 2)) ||
        ((kent.key.enctype != 1) && (kent.key.enctype != 2)) ||
        (kent.key.length != 1) ||
        (kent.key.contents[0] != kent.vno +'0')) {
        fprintf(stderr, "Retrieved principal does not check\n");
        exit(1);
    }

    krb5_free_keytab_entry_contents(context, &kent);

    /* Try to lookup a specific enctype - but unspecified kvno - should give
     * max kvno
     */
    kret = krb5_kt_get_entry(context, kt, princ, 0, 1, &kent);
    CHECK(kret, "looking up principal");

    /* Ensure a valid answer  - we did specified an enctype */
    if (!krb5_principal_compare(context, princ, kent.principal) ||
        (kent.vno != 2) || (kent.key.enctype != 1) ||
        (kent.key.length != 1) ||
        (kent.key.contents[0] != kent.vno +'0')) {
        fprintf(stderr, "Retrieved principal does not check\n");

        exit(1);

    }

    krb5_free_keytab_entry_contents(context, &kent);

    /* Try to lookup unspecified enctype, but a specified kvno */

    kret = krb5_kt_get_entry(context, kt, princ, 2, 0, &kent);
    CHECK(kret, "looking up principal");

    /* Ensure a valid answer  - we did not specify a kvno */
    if (!krb5_principal_compare(context, princ, kent.principal) ||
        (kent.vno != 2) || (kent.key.enctype != 1) ||
        (kent.key.length != 1) ||
        (kent.key.contents[0] != kent.vno +'0')) {
        fprintf(stderr, "Retrieved principal does not check\n");

        exit(1);

    }

    krb5_free_keytab_entry_contents(context, &kent);



    /* Try to lookup specified enctype and kvno */

    kret = krb5_kt_get_entry(context, kt, princ, 1, 1, &kent);
    CHECK(kret, "looking up principal");

    if (!krb5_principal_compare(context, princ, kent.principal) ||
        (kent.vno != 1) || (kent.key.enctype != 1) ||
        (kent.key.length != 1) ||
        (kent.key.contents[0] != kent.vno +'0')) {
        fprintf(stderr, "Retrieved principal does not check\n");

        exit(1);

    }

    krb5_free_keytab_entry_contents(context, &kent);


    /* Try lookup with active iterators.  */
    kret = krb5_kt_start_seq_get(context, kt, &cursor);
    CHECK(kret, "Start sequence get(2)");
    kret = krb5_kt_start_seq_get(context, kt, &cursor2);
    CHECK(kret, "Start sequence get(3)");
    kret = krb5_kt_next_entry(context, kt, &kent, &cursor);
    CHECK(kret, "getting next entry(2)");
    krb5_free_keytab_entry_contents(context, &kent);
    kret = krb5_kt_next_entry(context, kt, &kent, &cursor);
    CHECK(kret, "getting next entry(3)");
    kret = krb5_kt_next_entry(context, kt, &kent2, &cursor2);
    CHECK(kret, "getting next entry(4)");
    krb5_free_keytab_entry_contents(context, &kent2);
    kret = krb5_kt_get_entry(context, kt, kent.principal, 0, 0, &kent2);
    CHECK(kret, "looking up principal(2)");
    krb5_free_keytab_entry_contents(context, &kent2);
    kret = krb5_kt_next_entry(context, kt, &kent2, &cursor2);
    CHECK(kret, "getting next entry(5)");
    if (!krb5_principal_compare(context, kent.principal, kent2.principal)) {
        fprintf(stderr, "iterators not in sync\n");
        exit(1);
    }
    krb5_free_keytab_entry_contents(context, &kent);
    krb5_free_keytab_entry_contents(context, &kent2);
    kret = krb5_kt_next_entry(context, kt, &kent, &cursor);
    CHECK(kret, "getting next entry(6)");
    kret = krb5_kt_next_entry(context, kt, &kent2, &cursor2);
    CHECK(kret, "getting next entry(7)");
    krb5_free_keytab_entry_contents(context, &kent);
    krb5_free_keytab_entry_contents(context, &kent2);
    kret = krb5_kt_end_seq_get(context, kt, &cursor);
    CHECK(kret, "ending sequence get(1)");
    kret = krb5_kt_end_seq_get(context, kt, &cursor2);
    CHECK(kret, "ending sequence get(2)");

    /* Try to lookup specified enctype and kvno  - that does not exist*/

    kret = krb5_kt_get_entry(context, kt, princ, 3, 1, &kent);
    if(kret != KRB5_KT_KVNONOTFOUND) {
        CHECK(kret, "looking up specific principal, kvno, enctype");
    }

    krb5_free_principal(context, princ);


    /* =========================   krb5_kt_remove_entry =========== */
    /* Lookup the keytab entry w/ 2 kvno - and delete version 2 -
       ensure gone */
    kret = krb5_parse_name(context, "test/[email protected]", &princ);
    CHECK(kret, "parsing principal");

    kret = krb5_kt_get_entry(context, kt, princ, 0, 1, &kent);
    CHECK(kret, "looking up principal");

    /* Ensure a valid answer  - we are looking for max(kvno) and enc=1 */
    if (!krb5_principal_compare(context, princ, kent.principal) ||
        (kent.vno != 2) || (kent.key.enctype != 1) ||
        (kent.key.length != 1) ||
        (kent.key.contents[0] != kent.vno +'0')) {
        fprintf(stderr, "Retrieved principal does not check\n");

        exit(1);

    }

    /* Delete it */
    kret = krb5_kt_remove_entry(context, kt, &kent);
    CHECK(kret, "Removing entry");

    krb5_free_keytab_entry_contents(context, &kent);
    /* And ensure gone */

    kret = krb5_kt_get_entry(context, kt, princ, 0, 1, &kent);
    CHECK(kret, "looking up principal");

    /* Ensure a valid answer - kvno should now be 1 - we deleted 2 */
    if (!krb5_principal_compare(context, princ, kent.principal) ||
        (kent.vno != 1) || (kent.key.enctype != 1) ||
        (kent.key.length != 1) ||
        (kent.key.contents[0] != kent.vno +'0')) {
        fprintf(stderr, "Delete principal check failed\n");

        exit(1);

    }
    krb5_free_keytab_entry_contents(context, &kent);

    krb5_free_principal(context, princ);

    /* =======================  Finally close =======================  */

    kret = krb5_kt_close(context, kt);
    CHECK(kret, "close");

}
Exemple #25
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;
}
Exemple #26
0
static krb5_error_code
reload_keys(void)
{
    krb5_error_code ret;
    krb5_keytab fkeytab = NULL;
    krb5_kt_cursor c;
    krb5_keytab_entry kte;
    int i, n_nkeys, o_nkeys;
    krb5_keytab_entry *n_ktent = NULL, *o_ktent;
    struct stat tstat;

    if (stat(checkfile_path, &tstat) == 0) {
	if (have_keytab_keys && tstat.st_mtime == last_reload) {
	    /* We haven't changed since the last time we loaded our keys, so
	     * there's nothing to do. */
	    ret = 0;
	    goto cleanup;
	}
	last_reload = tstat.st_mtime;
    } else if (have_keytab_keys) {
	/* stat() failed, but we already have keys, so don't do anything. */
	ret = 0;
	goto cleanup;
    }

    if (keytab_name != NULL)
	ret = krb5_kt_resolve(k5ctx, keytab_name, &fkeytab);
    else
	ret = krb5_kt_default(k5ctx, &fkeytab);
    if (ret != 0)
	goto cleanup;
    ret = krb5_kt_start_seq_get(k5ctx, fkeytab, &c);
    if (ret != 0)
	goto cleanup;
    n_nkeys = 0;
    while (krb5_kt_next_entry(k5ctx, fkeytab, &kte, &c) == 0) {
	krb5_free_keytab_entry_contents(k5ctx, &kte);
	n_nkeys++;
    }
    krb5_kt_end_seq_get(k5ctx, fkeytab, &c);
    if (n_nkeys == 0) {
	ret = KRB5_KT_NOTFOUND;
	goto cleanup;
    }
    n_ktent = calloc(n_nkeys, sizeof(krb5_keytab_entry));
    if (n_ktent == NULL) {
	ret = KRB5_KT_NOTFOUND;
	goto cleanup;
    }
    ret = krb5_kt_start_seq_get(k5ctx, fkeytab, &c);
    if (ret != 0)
	goto cleanup;
    for (i = 0; i < n_nkeys; i++)
	if (krb5_kt_next_entry(k5ctx, fkeytab, &n_ktent[i], &c) != 0)
	    break;
    krb5_kt_end_seq_get(k5ctx, fkeytab, &c);
    if (i < n_nkeys)
	goto cleanup;
    have_keytab_keys = 1;
    o_ktent = ktent;
    ktent = n_ktent;

    o_nkeys = nkeys;
    nkeys = n_nkeys;

    /* for cleanup */
    n_ktent = o_ktent;
    n_nkeys = o_nkeys;
cleanup:
    if (n_ktent != NULL) {
	for (i = 0; i < n_nkeys; i++)
	    krb5_free_keytab_entry_contents(k5ctx, &n_ktent[i]);
	free(n_ktent);
    }
    if (fkeytab != NULL) {
	krb5_kt_close(k5ctx, fkeytab);
    }
    return ret;
}