Пример #1
0
static int
check_expiration(krb5_context context,
		 krb5_ccache ccache,
		 time_t *expiration)
{
    krb5_error_code ret;
    time_t t;

    ret = krb5_cc_get_lifetime(context, ccache, &t);
    if (ret || t == 0)
	return 1;

    *expiration = time(NULL) + t;

    return 0;
}
Пример #2
0
OM_uint32
__gsskrb5_ccache_lifetime(OM_uint32 *minor_status,
			  krb5_context context,
			  krb5_ccache id,
			  krb5_principal principal,
			  OM_uint32 *lifetime)
{
    krb5_error_code kret;
    time_t left;

    kret = krb5_cc_get_lifetime(context, id, &left);
    if (kret) {
        *minor_status = kret;
        return GSS_S_FAILURE;
    }

    *lifetime = left;

    return GSS_S_COMPLETE;
}
Пример #3
0
/*
 * Acquires an initiator credential from a ccache or using a keytab.
 */
static OM_uint32
acquire_initiator_cred(OM_uint32 *minor_status,
                       krb5_context context,
                       OM_uint32 time_req,
                       gss_const_OID desired_mech,
                       gss_cred_usage_t cred_usage,
                       gsskrb5_cred handle)
{
    OM_uint32 ret = GSS_S_FAILURE;
    krb5_creds cred;
    krb5_get_init_creds_opt *opt;
    krb5_principal def_princ = NULL;
    krb5_ccache def_ccache = NULL;
    krb5_ccache ccache = NULL;  /* we may store into this ccache */
    krb5_keytab keytab = NULL;
    krb5_error_code kret = 0;
    OM_uint32 left;
    time_t lifetime = 0;
    time_t now;

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

    /*
     * Get current time early so we can set handle->endtime to a value that
     * cannot accidentally be past the real endtime.  We need a variant of
     * krb5_cc_get_lifetime() that returns absolute endtime.
     */
    krb5_timeofday(context, &now);

    /*
     * First look for a ccache that has the desired_name (which may be
     * the default credential name).
     *
     * If we don't have an unexpired credential, acquire one with a
     * keytab.
     *
     * If we acquire one with a keytab, save it in the ccache we found
     * with the expired credential, if any.
     *
     * If we don't have any such ccache, then use a MEMORY ccache.
     */

    if (handle->principal != NULL) {
        /*
         * Not default credential case.  See if we can find a ccache in
         * the cccol for the desired_name.
         */
	kret = krb5_cc_cache_match(context,
				   handle->principal,
				   &ccache);
	if (kret == 0) {
            kret = krb5_cc_get_lifetime(context, ccache, &lifetime);
            if (kret == 0) {
                if (lifetime > 0)
                    goto found;
                else
                    goto try_keytab;
            }
	}
        /*
         * Fall through.  We shouldn't find this in the default ccache
         * either, but we'll give it a try, then we'll try using a keytab.
         */
    }

    /*
     * Either desired_name was GSS_C_NO_NAME (default cred) or
     * krb5_cc_cache_match() failed (or found expired).
     */
    kret = krb5_cc_default(context, &def_ccache);
    if (kret != 0)
        goto try_keytab;
    kret = krb5_cc_get_lifetime(context, def_ccache, &lifetime);
    if (kret != 0)
        lifetime = 0;
    kret = krb5_cc_get_principal(context, def_ccache, &def_princ);
    if (kret != 0)
        goto try_keytab;
    /*
     * Have a default ccache; see if it matches desired_name.
     */
    if (handle->principal == NULL ||
        krb5_principal_compare(context, handle->principal,
                               def_princ) == TRUE) {
        /*
         * It matches.
         *
         * If we end up trying a keytab then we can write the result to
         * the default ccache.
         */
        if (handle->principal == NULL) {
            kret = krb5_copy_principal(context, def_princ, &handle->principal);
            if (kret)
                goto end;
        }
        if (ccache != NULL)
            krb5_cc_close(context, ccache);
        ccache = def_ccache;
        def_ccache = NULL;
        if (lifetime > 0)
            goto found;
        /* else we fall through and try using a keytab */
    }

try_keytab:
    if (handle->principal == NULL) {
        /* We need to know what client principal to use */
        kret = krb5_get_default_principal(context, &handle->principal);
        if (kret)
            goto end;
    }
    kret = get_keytab(context, &keytab);
    if (kret)
        goto end;

    kret = krb5_get_init_creds_opt_alloc(context, &opt);
    if (kret)
        goto end;
    krb5_timeofday(context, &now);
    kret = krb5_get_init_creds_keytab(context, &cred, handle->principal,
                                      keytab, 0, NULL, opt);
    krb5_get_init_creds_opt_free(context, opt);
    if (kret)
        goto end;

    /*
     * We got a credential with a keytab.  Save it if we can.
     */
    if (ccache == NULL) {
        /*
         * There's no ccache we can overwrite with the credentials we acquired
         * with a keytab.  We'll use a MEMORY ccache then.
         *
         * Note that an application that falls into this repeatedly will do an
         * AS exchange every time it acquires a credential handle.  Hopefully
         * this doesn't happen much.  A workaround is to kinit -k once so that
         * we always re-initialize the matched/default ccache here.  I.e., once
         * there's a FILE/DIR ccache, we'll keep it frash automatically if we
         * have a keytab, but if there's no FILE/DIR ccache, then we'll
         * get a fresh credential *every* time we're asked.
         */
        kret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache);
        if (kret)
            goto end;
        handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;
    } /* else we'll re-initialize whichever ccache we matched above */

    kret = krb5_cc_initialize(context, ccache, cred.client);
    if (kret)
        goto end;
    kret = krb5_cc_store_cred(context, ccache, &cred);
    if (kret)
        goto end;

found:
    assert(handle->principal != NULL);
    ret = __gsskrb5_ccache_lifetime(minor_status, context, ccache,
                                    handle->principal, &left);
    if (ret != GSS_S_COMPLETE)
        goto end;
    handle->endtime = now + left;
    handle->ccache = ccache;
    ccache = NULL;
    ret = GSS_S_COMPLETE;
    kret = 0;

end:
    if (ccache != NULL) {
        if ((handle->cred_flags & GSS_CF_DESTROY_CRED_ON_RELEASE) != 0)
            krb5_cc_destroy(context, ccache);
        else
            krb5_cc_close(context, ccache);
    }
    if (def_ccache != NULL)
        krb5_cc_close(context, def_ccache);
    if (cred.client != NULL)
	krb5_free_cred_contents(context, &cred);
    if (def_princ != NULL)
	krb5_free_principal(context, def_princ);
    if (keytab != NULL)
	krb5_kt_close(context, keytab);
    if (ret != GSS_S_COMPLETE && kret != 0)
	*minor_status = kret;
    return (ret);
}
Пример #4
0
OM_uint32 GSSAPI_CALLCONV
_gsskrb5_store_cred(OM_uint32         *minor_status,
		    gss_cred_id_t     input_cred_handle,
		    gss_cred_usage_t  cred_usage,
		    const gss_OID     desired_mech,
		    OM_uint32         overwrite_cred,
		    OM_uint32         default_cred,
		    gss_OID_set       *elements_stored,
		    gss_cred_usage_t  *cred_usage_stored)
{
    krb5_context context;
    krb5_error_code ret;
    gsskrb5_cred cred;
    krb5_ccache id = NULL;
    krb5_ccache def_ccache = NULL;
    const char *def_type = NULL;
    time_t exp_current;
    time_t exp_new;

    *minor_status = 0;

    if (cred_usage != GSS_C_INITIATE) {
	*minor_status = GSS_KRB5_S_G_BAD_USAGE;
	return GSS_S_FAILURE;
    }

    if (desired_mech != GSS_C_NO_OID &&
        gss_oid_equal(desired_mech, GSS_KRB5_MECHANISM) == 0)
	return GSS_S_BAD_MECH;

    cred = (gsskrb5_cred)input_cred_handle;
    if (cred == NULL)
	return GSS_S_NO_CRED;

    GSSAPI_KRB5_INIT (&context);

    HEIMDAL_MUTEX_lock(&cred->cred_id_mutex);
    if (cred->usage != cred_usage && cred->usage != GSS_C_BOTH) {
	HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
	*minor_status = GSS_KRB5_S_G_BAD_USAGE;
	return GSS_S_FAILURE;
    }

    ret = krb5_cc_get_lifetime(context, cred->ccache, &exp_new);
    if (ret) {
	HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
	*minor_status = ret;
	return GSS_S_NO_CRED;
    }

    if (cred->principal == NULL) {
	HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
	*minor_status = GSS_KRB5_S_KG_TGT_MISSING;
	return GSS_S_FAILURE;
    }

    ret = krb5_cc_default(context, &def_ccache);
    if (ret == 0) {
        def_type = krb5_cc_get_type(context, def_ccache);
        krb5_cc_close(context, def_ccache);
    }
    def_ccache = NULL;

    /* write out cred to credential cache */
    ret = krb5_cc_cache_match(context, cred->principal, &id);
    if (ret) {
        if (default_cred) {
            ret = krb5_cc_default(context, &id);
            if (ret) {
                HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
                *minor_status = ret;
                return GSS_S_FAILURE;
            }
        } else {
            if (def_type == NULL ||
                !krb5_cc_support_switch(context, def_type)) {
                HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
                *minor_status = 0;      /* XXX */
                return GSS_S_NO_CRED;   /* XXX */
            }
            ret = krb5_cc_new_unique(context, def_type, NULL, &id);
            if (ret) {
                HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
                *minor_status = ret;
                return GSS_S_FAILURE;
            }
            overwrite_cred = 1;
        }
    }

    if (!overwrite_cred) {
        /* If current creds are expired or near it, overwrite */
        ret = krb5_cc_get_lifetime(context, id, &exp_current);
        if (ret != 0 || exp_new > exp_current)
            overwrite_cred = 1;
    }

    if (!overwrite_cred) {
        /* Nothing to do */
        krb5_cc_close(context, id);
        HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
        *minor_status = 0;
        return GSS_S_DUPLICATE_ELEMENT;
    }

    ret = krb5_cc_initialize(context, id, cred->principal);
    if (ret == 0)
	ret = krb5_cc_copy_match_f(context, cred->ccache, id, NULL, NULL, NULL);
    if (ret) {
        krb5_cc_close(context, id);
	HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
	*minor_status = ret;
	return(GSS_S_FAILURE);
    }

    if (default_cred && def_type != NULL &&
        krb5_cc_support_switch(context, def_type))
	krb5_cc_switch(context, id);

    krb5_cc_close(context, id);
    HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
    *minor_status = 0;
    return GSS_S_COMPLETE;
}
Пример #5
0
_PUBLIC_ int cli_credentials_get_named_ccache(struct cli_credentials *cred, 
					      struct tevent_context *event_ctx,
					      struct loadparm_context *lp_ctx,
					      char *ccache_name,
					      struct ccache_container **ccc,
					      const char **error_string)
{
	krb5_error_code ret;
	enum credentials_obtained obtained;
	
	if (cred->machine_account_pending) {
		cli_credentials_set_machine_account(cred, lp_ctx);
	}

	if (cred->ccache_obtained >= cred->ccache_threshold && 
	    cred->ccache_obtained > CRED_UNINITIALISED) {
		time_t lifetime;
		bool expired = false;
		ret = krb5_cc_get_lifetime(cred->ccache->smb_krb5_context->krb5_context, 
					   cred->ccache->ccache, &lifetime);
		if (ret == KRB5_CC_END) {
			/* If we have a particular ccache set, without
			 * an initial ticket, then assume there is a
			 * good reason */
		} else if (ret == 0) {
			if (lifetime == 0) {
				DEBUG(3, ("Ticket in credentials cache for %s expired, will refresh\n",
					  cli_credentials_get_principal(cred, cred)));
				expired = true;
			} else if (lifetime < 300) {
				DEBUG(3, ("Ticket in credentials cache for %s will shortly expire (%u secs), will refresh\n", 
					  cli_credentials_get_principal(cred, cred), (unsigned int)lifetime));
				expired = true;
			}
		} else {
			(*error_string) = talloc_asprintf(cred, "failed to get ccache lifetime: %s\n",
							  smb_get_krb5_error_message(cred->ccache->smb_krb5_context->krb5_context,
										     ret, cred));
			return ret;
		}

		DEBUG(5, ("Ticket in credentials cache for %s will expire in %u secs\n", 
			  cli_credentials_get_principal(cred, cred), (unsigned int)lifetime));
		
		if (!expired) {
			*ccc = cred->ccache;
			return 0;
		}
	}
	if (cli_credentials_is_anonymous(cred)) {
		(*error_string) = "Cannot get anonymous kerberos credentials";
		return EINVAL;
	}

	ret = cli_credentials_new_ccache(cred, lp_ctx, ccache_name, ccc, error_string);
	if (ret) {
		return ret;
	}

	ret = kinit_to_ccache(cred, cred, (*ccc)->smb_krb5_context, event_ctx, (*ccc)->ccache, &obtained, error_string);
	if (ret) {
		return ret;
	}

	ret = cli_credentials_set_from_ccache(cred, *ccc, 
					      obtained, error_string);
	
	cred->ccache = *ccc;
	cred->ccache_obtained = cred->principal_obtained;
	if (ret) {
		return ret;
	}
	cli_credentials_invalidate_client_gss_creds(cred, cred->ccache_obtained);
	return 0;
}