Exemplo n.º 1
0
/*
 * Depending on the version of Kerberos, we either need to use
 * a private function, or simply set the environment variable.
 */
static void gssd_set_krb5_ccache_name(char *ccname)
{
#ifdef USE_GSS_KRB5_CCACHE_NAME
	u_int maj_stat, min_stat;

	printerr(2, "using gss_krb5_ccache_name to select krb5 ccache %s\n",
		 ccname);
	maj_stat = gss_krb5_ccache_name(&min_stat, ccname, NULL);
	if (maj_stat != GSS_S_COMPLETE) {
		printerr(0,
			 "WARNING: gss_krb5_ccache_name with "
			 "name '%s' failed (%s)\n", ccname,
			 error_message(min_stat));
	}
#else
	/*
	 * Set the KRB5CCNAME environment variable to tell the krb5 code
	 * which credentials cache to use.  (Instead of using the private
	 * function above for which there is no generic gssapi
	 * equivalent.)
	 */
	printerr(2, "using environment variable to select krb5 ccache %s\n",
		 ccname);
	setenv("KRB5CCNAME", ccname, 1);
#endif
}
Exemplo n.º 2
0
int
main(int argc, char **argv)
{
    int optidx = 0;
    OM_uint32 flag;
    gss_OID type;

    setprogname(argv[0]);
    if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
	usage(1);
    
    if (help_flag)
	usage (0);

    if(version_flag){
	print_version(NULL);
	exit(0);
    }

    argc -= optidx;
    argv += optidx;

    if (argc != 0)
	usage(1);

    if (acquire_type) {
	if (strcasecmp(acquire_type, "both") == 0)
	    flag = GSS_C_BOTH;
	else if (strcasecmp(acquire_type, "accept") == 0)
	    flag = GSS_C_ACCEPT;
	else if (strcasecmp(acquire_type, "initiate") == 0)
	    flag = GSS_C_INITIATE;
	else
	    errx(1, "unknown type %s", acquire_type);
    } else
	flag = GSS_C_ACCEPT;
	
    if (name_type) {
	if (strcasecmp("hostbased-service", name_type) == 0)
	    type = GSS_C_NT_HOSTBASED_SERVICE;
	else if (strcasecmp("user-name", name_type) == 0)
	    type = GSS_C_NT_USER_NAME;
	else
	    errx(1, "unknown name type %s", name_type);
    } else
	type = GSS_C_NT_HOSTBASED_SERVICE;

    if (ccache) {
	OM_uint32 major_status, minor_status;
	major_status = gss_krb5_ccache_name(&minor_status,
					    ccache, NULL);
	if (GSS_ERROR(major_status))
	    errx(1, "gss_krb5_ccache_name %s", 
		 gssapi_err(major_status, minor_status, GSS_C_NO_OID));
    }

    acquire_cred_service(acquire_name, type, flag);

    return 0;
}
Exemplo n.º 3
0
DWORD
LwKrb5SetThreadDefaultCachePath(
    IN PCSTR pszCachePath,
    OUT PSTR* ppszPreviousCachePath
    )
{
    DWORD dwError       = 0;
    DWORD dwMajorStatus = 0;
    DWORD dwMinorStatus = 0;
    PSTR  pszOrigCachePath = NULL;

    // Set the default for gss
    dwMajorStatus = gss_krb5_ccache_name(
                            (OM_uint32 *)&dwMinorStatus,
                            pszCachePath,
                            (ppszPreviousCachePath) ? (const char**)&pszOrigCachePath : NULL);
    BAIL_ON_GSS_ERROR(dwError, dwMajorStatus, dwMinorStatus);

    LW_LOG_DEBUG("Switched gss krb5 credentials path from %s to %s",
            LW_SAFE_LOG_STRING(pszOrigCachePath),
            LW_SAFE_LOG_STRING(pszCachePath));
    
    if (ppszPreviousCachePath) {
        if (!LW_IS_NULL_OR_EMPTY_STR(pszOrigCachePath)) {
            dwError = LwAllocateString(pszOrigCachePath, ppszPreviousCachePath);
            BAIL_ON_LW_ERROR(dwError);
        } else {
            *ppszPreviousCachePath = NULL;
        }
    }
    
cleanup:

    return dwError;
    
error:

    if (ppszPreviousCachePath) {
        *ppszPreviousCachePath = NULL;
    }

    goto cleanup;
}
Exemplo n.º 4
0
DWORD
SMBKrb5SetDefaultCachePath(
    PCSTR pszCachePath,
    PSTR* ppszOrigCachePath
    )
{
    DWORD dwError       = 0;
    DWORD dwMajorStatus = 0;
    DWORD dwMinorStatus = 0;
    PSTR  pszOrigCachePath = NULL;

    // Set the default for gss
    dwMajorStatus = gss_krb5_ccache_name(
                            (OM_uint32 *)&dwMinorStatus,
                            pszCachePath,
                            (ppszOrigCachePath) ? (const char**)&pszOrigCachePath : NULL);
    BAIL_ON_SEC_ERROR(dwMajorStatus);

    if (ppszOrigCachePath) {
        if (!IsNullOrEmptyString(pszOrigCachePath)) {
            dwError = SMBAllocateString(pszOrigCachePath, ppszOrigCachePath);
            BAIL_ON_LWIO_ERROR(dwError);
        } else {
            *ppszOrigCachePath = NULL;
        }
    }

    LWIO_LOG_DEBUG("Cache path set to [%s]", LWIO_SAFE_LOG_STRING(pszCachePath));

cleanup:

    return dwError;

sec_error:
error:

    if (ppszOrigCachePath) {
        *ppszOrigCachePath = NULL;
    }

    goto cleanup;
}
Exemplo n.º 5
0
/* Acquire GSSAPI credentials and set up RPC auth flavor. */
static kadm5_ret_t
setup_gss(kadm5_server_handle_t handle, kadm5_config_params *params_in,
          krb5_principal client, krb5_principal server)
{
    OM_uint32 gssstat, minor_stat;
    gss_buffer_desc buf;
    gss_name_t gss_client;
    gss_name_t gss_target;
    gss_cred_id_t gss_client_creds;
    const char *c_ccname_orig;
    char *ccname_orig;

    gss_client_creds = GSS_C_NO_CREDENTIAL;
    ccname_orig = NULL;
    gss_client = gss_target = GSS_C_NO_NAME;

    /* Temporarily use the kadm5 cache. */
    gssstat = gss_krb5_ccache_name(&minor_stat, handle->cache_name,
                                   &c_ccname_orig);
    if (gssstat != GSS_S_COMPLETE)
        goto error;
    if (c_ccname_orig)
        ccname_orig = strdup(c_ccname_orig);
    else
        ccname_orig = 0;

    buf.value = &server;
    buf.length = sizeof(server);
    gssstat = gss_import_name(&minor_stat, &buf,
                              (gss_OID)gss_nt_krb5_principal, &gss_target);
    if (gssstat != GSS_S_COMPLETE)
        goto error;

    if (client != NULL) {
        buf.value = &client;
        buf.length = sizeof(client);
        gssstat = gss_import_name(&minor_stat, &buf,
                                  (gss_OID)gss_nt_krb5_principal, &gss_client);
    } else gss_client = GSS_C_NO_NAME;

    if (gssstat != GSS_S_COMPLETE)
        goto error;

    gssstat = gss_acquire_cred(&minor_stat, gss_client, 0,
                               GSS_C_NULL_OID_SET, GSS_C_INITIATE,
                               &gss_client_creds, NULL, NULL);
    if (gssstat != GSS_S_COMPLETE) {
#if 0 /* for debugging only */
        {
            OM_uint32 maj_status, min_status, message_context = 0;
            gss_buffer_desc status_string;
            do {
                maj_status = gss_display_status(&min_status,
                                                gssstat,
                                                GSS_C_GSS_CODE,
                                                GSS_C_NO_OID,
                                                &message_context,
                                                &status_string);
                if (maj_status == GSS_S_COMPLETE) {
                    fprintf(stderr, "MAJ: %.*s\n",
                            (int) status_string.length,
                            (char *)status_string.value);
                    gss_release_buffer(&min_status, &status_string);
                } else {
                    fprintf(stderr,
                            "MAJ? gss_display_status returns 0x%lx?!\n",
                            (unsigned long) maj_status);
                    message_context = 0;
                }
            } while (message_context != 0);
            do {
                maj_status = gss_display_status(&min_status,
                                                minor_stat,
                                                GSS_C_MECH_CODE,
                                                GSS_C_NO_OID,
                                                &message_context,
                                                &status_string);
                if (maj_status == GSS_S_COMPLETE) {
                    fprintf(stderr, "MIN: %.*s\n",
                            (int) status_string.length,
                            (char *)status_string.value);
                    gss_release_buffer(&min_status, &status_string);
                } else {
                    fprintf(stderr,
                            "MIN? gss_display_status returns 0x%lx?!\n",
                            (unsigned long) maj_status);
                    message_context = 0;
                }
            } while (message_context != 0);
        }
#endif
        goto error;
    }

    /*
     * Do actual creation of RPC auth handle.  Implements auth flavor
     * fallback.
     */
    rpc_auth(handle, params_in, gss_client_creds, gss_target);

error:
    if (gss_client_creds != GSS_C_NO_CREDENTIAL)
        (void) gss_release_cred(&minor_stat, &gss_client_creds);

    if (gss_client)
        gss_release_name(&minor_stat, &gss_client);
    if (gss_target)
        gss_release_name(&minor_stat, &gss_target);

    /* Revert to prior gss_krb5 ccache. */
    if (ccname_orig) {
        gssstat = gss_krb5_ccache_name(&minor_stat, ccname_orig, NULL);
        if (gssstat) {
            return KADM5_GSS_ERROR;
        }
        free(ccname_orig);
    } else {
        gssstat = gss_krb5_ccache_name(&minor_stat, NULL, NULL);
        if (gssstat) {
            return KADM5_GSS_ERROR;
        }
    }

    if (handle->clnt->cl_auth == NULL) {
        return KADM5_GSS_ERROR;
    }
    return 0;
}
Exemplo n.º 6
0
static kbrccache_t userinitcontext(
    const char * user, const char * domain, const char * passwd, const char * cachename, int initialize,
    int * outError )
{
    krb5_context    kcontext = 0;
    krb5_ccache             kcache = 0;
    krb5_creds              kcreds;
    krb5_principal  kme = 0;
    krb5_error_code kres;
    char *                  pPass = strdup( passwd );
    char *                  pName = NULL;
    char *                  pCacheName = NULL;
    int                             numCreds = 0;

    memset( &kcreds, 0, sizeof(kcreds) );
    kres = krb5_init_context( &kcontext );
    if( kres )
        goto return_error;
    if( domain )
        kres = krb5_build_principal( kcontext, &kme, strlen(domain), domain, user, (char *) 0 );
    else
        kres = krb5_parse_name( kcontext, user, &kme );
    if( kres )
        goto fail;
    krb5_unparse_name( kcontext, kme, &pName );
    if( cachename )
    {
        if (asprintf(&pCacheName, "%s%s", cachename, pName) < 0)
        {
            kres = KRB5_CC_NOMEM;
            goto fail;
        }
        kres = krb5_cc_resolve( kcontext, pCacheName, &kcache );
        if( kres )
        {
            kres = krb5_cc_resolve( kcontext, CCACHE_PREFIX_DEFAULT, &kcache );
            if( kres == 0 )
                pCacheName = strdup(CCACHE_PREFIX_DEFAULT);
        }
    }
    else
    {
        kres = krb5_cc_default( kcontext, &kcache );
        pCacheName = strdup( krb5_cc_get_name( kcontext, kcache ) );
    }
    if( kres )
    {
        krb5_free_context(kcontext);
        goto return_error;
    }
    if( initialize )
        krb5_cc_initialize( kcontext, kcache, kme );
    if( kres == 0 && user && passwd )
    {
        long timeneeded = time(0L) +TKTTIMELEFT;
        int have_credentials = 0;
        krb5_cc_cursor cc_curs = NULL;
        numCreds = 0;
        if( (kres=krb5_cc_start_seq_get(kcontext, kcache, &cc_curs)) >= 0 )
        {
            while( (kres=krb5_cc_next_cred(kcontext, kcache, &cc_curs, &kcreds))== 0)
            {
                numCreds++;
                if( krb5_principal_compare( kcontext, kme, kcreds.client ) )
                {
                    if( kcreds.ticket_flags & TKT_FLG_INITIAL && kcreds.times.endtime>timeneeded )
                        have_credentials = 1;
                }
                krb5_free_cred_contents( kcontext, &kcreds );
                if( have_credentials )
                    break;
            }
            krb5_cc_end_seq_get( kcontext, kcache, &cc_curs );
        }
        else
        {
            const char * errmsg = error_message(kres);
            fprintf( stderr, "%s user init(%s): %s\n", "setpass", pName, errmsg );
        }
        if( kres != 0 || have_credentials == 0 )
        {
            krb5_get_init_creds_opt *options = NULL;
            kres = krb5_get_init_creds_opt_alloc(kcontext, &options);
            if ( kres == 0 )
            {
                get_init_creds_opt_init(options);
/*
** no valid credentials - get new ones
*/
                kres = krb5_get_init_creds_password( kcontext, &kcreds, kme, pPass,
                                                     NULL /*prompter*/,
                                                     NULL /*data*/,
                                                     0 /*starttime*/,
                                                     0 /*in_tkt_service*/,
                                                     options /*options*/ );
            }
            if( kres == 0 )
            {
                if( numCreds <= 0 )
                    kres = krb5_cc_initialize( kcontext, kcache, kme );
                if( kres == 0 )
                    kres = krb5_cc_store_cred( kcontext, kcache, &kcreds );
                if( kres == 0 )
                    have_credentials = 1;
            }
            krb5_get_init_creds_opt_free(kcontext, options);
        }
#ifdef NOTUSED
        if( have_credentials )
        {
            int mstat;
            kres = gss_krb5_ccache_name( &mstat, pCacheName, NULL );
            if( getenv( ENV_DEBUG_LDAPKERB ) )
                fprintf( stderr, "gss credentials cache set to %s(%d)\n", pCacheName, kres );
        }
#endif
        krb5_cc_close( kcontext, kcache );
    }
fail:
    if( kres )
    {
        const char * errmsg = error_message(kres);
        fprintf( stderr, "%s user init(%s): %s\n", "setpass", pName, errmsg );
    }
    krb5_free_principal( kcontext, kme );
    krb5_free_cred_contents( kcontext, &kcreds );
    if( pName )
        free( pName );
    free(pPass);
    krb5_free_context(kcontext);

return_error:
    if( kres )
    {
        if( pCacheName )
        {
            free(pCacheName);
            pCacheName = NULL;
        }
    }
    if( outError )
        *outError = kres;
    return pCacheName;
}
Exemplo n.º 7
0
int
main(int argc, char **argv)
{
    gss_OID_set oidset = GSS_C_NULL_OID_SET;
    gss_OID mechoid = GSS_C_NO_OID;
    OM_uint32 maj_stat, min_stat;
    gss_cred_id_t cred;
    gss_name_t target = GSS_C_NO_NAME;
    int i, optidx = 0;
    OM_uint32 flag;
    gss_OID type;

    setprogname(argv[0]);
    if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
	usage(1);

    if (help_flag)
	usage (0);

    if(version_flag){
	print_version(NULL);
	exit(0);
    }

    argc -= optidx;
    argv += optidx;

    if (argc != 0)
	usage(1);

    if (acquire_type) {
	if (strcasecmp(acquire_type, "both") == 0)
	    flag = GSS_C_BOTH;
	else if (strcasecmp(acquire_type, "accept") == 0)
	    flag = GSS_C_ACCEPT;
	else if (strcasecmp(acquire_type, "initiate") == 0)
	    flag = GSS_C_INITIATE;
	else
	    errx(1, "unknown type %s", acquire_type);
    } else
	flag = GSS_C_ACCEPT;

    if (name_type) {
	if (strcasecmp("hostbased-service", name_type) == 0)
	    type = GSS_C_NT_HOSTBASED_SERVICE;
	else if (strcasecmp("user-name", name_type) == 0)
	    type = GSS_C_NT_USER_NAME;
	else
	    errx(1, "unknown name type %s", name_type);
    } else
	type = GSS_C_NT_HOSTBASED_SERVICE;

    if (ccache) {
	maj_stat = gss_krb5_ccache_name(&min_stat, ccache, NULL);
	if (GSS_ERROR(maj_stat))
	    errx(1, "gss_krb5_ccache_name %s",
		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
    }

    if (kerberos_flag) {
	mechoid = GSS_KRB5_MECHANISM;

	maj_stat = gss_create_empty_oid_set(&min_stat, &oidset);
	if (maj_stat != GSS_S_COMPLETE)
	    errx(1, "gss_create_empty_oid_set: %s",
		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));

	maj_stat = gss_add_oid_set_member(&min_stat, GSS_KRB5_MECHANISM, &oidset);
	if (maj_stat != GSS_S_COMPLETE)
	    errx(1, "gss_add_oid_set_member: %s",
		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
    }

    if (target_name) {
	gss_buffer_desc name;

	name.value = target_name;
	name.length = strlen(target_name);
	maj_stat = gss_import_name(&min_stat, &name,
				   GSS_C_NT_HOSTBASED_SERVICE, &target);
	if (maj_stat != GSS_S_COMPLETE)
	    errx(1, "gss_import_name: %s",
		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
    }

    for (i = 0; i < num_loops; i++) {

	cred = acquire_cred_service(acquire_name, type, oidset, flag);

	if (enctype) {
	    int32_t enctypelist = enctype;

	    maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, cred,
						       1, &enctypelist);
	    if (maj_stat)
		errx(1, "gss_krb5_set_allowable_enctypes: %s",
		     gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
	}

	if (target) {
	    gss_ctx_id_t context = GSS_C_NO_CONTEXT;
	    gss_buffer_desc out;

	    out.length = 0;
	    out.value = NULL;

	    maj_stat = gss_init_sec_context(&min_stat,
					    cred, &context,
					    target, mechoid,
					    GSS_C_MUTUAL_FLAG, 0, NULL,
					    GSS_C_NO_BUFFER, NULL,
					    &out, NULL, NULL);
	    if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
		errx(1, "init_sec_context failed: %s",
		     gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));

	    gss_release_buffer(&min_stat, &out);
	    gss_delete_sec_context(&min_stat, &context, NULL);
	}
	gss_release_cred(&min_stat, &cred);
    }


    return 0;
}
Exemplo n.º 8
0
static bool mag_auth_basic(request_rec *req,
                           struct mag_config *cfg,
                           gss_buffer_desc ba_user,
                           gss_buffer_desc ba_pwd,
                           gss_name_t *client,
                           gss_OID *mech_type,
                           gss_cred_id_t *delegated_cred,
                           uint32_t *vtime)
{
#ifdef HAVE_GSS_KRB5_CCACHE_NAME
    const char *user_ccache = NULL;
    const char *orig_ccache = NULL;
    long long unsigned int rndname;
    apr_status_t rs;
#endif
    gss_name_t user = GSS_C_NO_NAME;
    gss_cred_id_t user_cred = GSS_C_NO_CREDENTIAL;
    gss_ctx_id_t user_ctx = GSS_C_NO_CONTEXT;
    gss_name_t server = GSS_C_NO_NAME;
    gss_cred_id_t server_cred = GSS_C_NO_CREDENTIAL;
    gss_ctx_id_t server_ctx = GSS_C_NO_CONTEXT;
    gss_buffer_desc input = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc output = GSS_C_EMPTY_BUFFER;
    gss_OID_set allowed_mechs;
    gss_OID_set filtered_mechs;
    gss_OID_set actual_mechs = GSS_C_NO_OID_SET;
    uint32_t init_flags = 0;
    uint32_t maj, min;
    int present = 0;
    bool ret = false;

    maj = gss_import_name(&min, &ba_user, GSS_C_NT_USER_NAME, &user);
    if (GSS_ERROR(maj)) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
                      "In Basic Auth, %s",
                      mag_error(req, "gss_import_name() failed",
                                maj, min));
        goto done;
    }

    if (cfg->basic_mechs) {
        allowed_mechs = cfg->basic_mechs;
    } else if (cfg->allowed_mechs) {
        allowed_mechs = cfg->allowed_mechs;
    } else {
        struct mag_server_config *scfg;
        /* Try to fetch the default set if not explicitly configured,
         * We need to do this because gss_acquire_cred_with_password()
         * is currently limited to acquire creds for a single "default"
         * mechanism if no desired mechanisms are passed in. This causes
         * authentication to fail for secondary mechanisms as no user
         * credentials are generated for those. */
        scfg = ap_get_module_config(req->server->module_config,
                                    &auth_gssapi_module);
        /* In the worst case scenario default_mechs equals to GSS_C_NO_OID_SET.
         * This generally causes only the krb5 mechanism to be tried due
         * to implementation constraints, but may change in future. */
        allowed_mechs = scfg->default_mechs;
    }

    /* Remove Spnego if present, or we'd repeat failed authentiations
     * multiple times, one within Spnego and then again with an explicit
     * mechanism. We would normally just force Spnego and use
     * gss_set_neg_mechs, but due to the way we source the server name
     * and the fact MIT up to 1.14 at least does no handle union names,
     * we can't provide spnego with a server name that can be used by
     * multiple mechanisms, causing any but the first mechanism to fail.
     * Also remove unwanted krb mechs, or AS requests will be repeated
     * multiple times uselessly.
     */
    filtered_mechs = mag_filter_unwanted_mechs(allowed_mechs);
    if (filtered_mechs == allowed_mechs) {
        /* in case filtered_mechs was not allocated here don't free it */
        filtered_mechs = GSS_C_NO_OID_SET;
    } else if (filtered_mechs == GSS_C_NO_OID_SET) {
        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, req, "Fatal "
                      "failure while filtering mechs, aborting");
        goto done;
    } else {
        /* use the filtered list */
        allowed_mechs = filtered_mechs;
    }

#ifdef HAVE_GSS_KRB5_CCACHE_NAME
    /* If we are using the krb5 mechanism make sure to set a per thread
     * memory ccache so that there can't be interferences between threads.
     * Also make sure we have  new cache so no cached results end up being
     * used. Some implementations of gss_acquire_cred_with_password() do
     * not reacquire creds if cached ones are around, failing to check
     * again for the password. */
    maj = gss_test_oid_set_member(&min, discard_const(gss_mech_krb5),
                                  allowed_mechs, &present);
    if (GSS_ERROR(maj)) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
                      "In Basic Auth, %s",
                      mag_error(req, "gss_test_oid_set_member() failed",
                                maj, min));
        goto done;
    }
    if (present) {
        rs = apr_generate_random_bytes((unsigned char *)(&rndname),
                                       sizeof(long long unsigned int));
        if (rs != APR_SUCCESS) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
                          "Failed to generate random ccache name");
            goto done;
        }
        user_ccache = apr_psprintf(req->pool, "MEMORY:user_%qu", rndname);
        maj = gss_krb5_ccache_name(&min, user_ccache, &orig_ccache);
        if (GSS_ERROR(maj)) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
                          "In Basic Auth, %s",
                          mag_error(req, "gss_krb5_ccache_name() "
                                    "failed", maj, min));
            goto done;
        }
    }
#endif

    maj = gss_acquire_cred_with_password(&min, user, &ba_pwd,
                                         GSS_C_INDEFINITE,
                                         allowed_mechs,
                                         GSS_C_INITIATE,
                                         &user_cred, &actual_mechs, NULL);
    if (GSS_ERROR(maj)) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
                      "In Basic Auth, %s",
                      mag_error(req, "gss_acquire_cred_with_password() "
                                "failed", maj, min));
        goto done;
    }

    /* must acquire creds based on the actual mechs we want to try */
    if (!mag_acquire_creds(req, cfg, actual_mechs,
                           GSS_C_ACCEPT, &server_cred, NULL)) {
        goto done;
    }

#ifdef HAVE_CRED_STORE
    if (cfg->deleg_ccache_dir) {
        /* delegate ourselves credentials so we store them as requested */
        init_flags |= GSS_C_DELEG_FLAG;
    }
#endif

    for (int i = 0; i < actual_mechs->count; i++) {

        /* free these if looping */
        gss_release_buffer(&min, &output);
        gss_release_buffer(&min, &input);
        gss_release_name(&min, &server);

        maj = gss_inquire_cred_by_mech(&min, server_cred,
                                       &actual_mechs->elements[i],
                                       &server, NULL, NULL, NULL);
        if (GSS_ERROR(maj)) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
                          "%s", mag_error(req, "gss_inquired_cred_by_mech() "
                                          "failed", maj, min));
            continue;
        }

        do {
            /* output and input are inverted here, this is intentional */
            maj = gss_init_sec_context(&min, user_cred, &user_ctx, server,
                                       &actual_mechs->elements[i], init_flags,
                                       300, GSS_C_NO_CHANNEL_BINDINGS, &output,
                                       NULL, &input, NULL, NULL);
            if (GSS_ERROR(maj)) {
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
                              "%s", mag_error(req, "gss_init_sec_context() "
                                              "failed", maj, min));
                break;
            }
            gss_release_buffer(&min, &output);
            maj = gss_accept_sec_context(&min, &server_ctx, server_cred,
                                         &input, GSS_C_NO_CHANNEL_BINDINGS,
                                         client, mech_type, &output, NULL,
                                         vtime, delegated_cred);
            if (GSS_ERROR(maj)) {
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
                              "%s", mag_error(req, "gss_accept_sec_context()"
                                              " failed", maj, min));
                break;
            }
            gss_release_buffer(&min, &input);
        } while (maj == GSS_S_CONTINUE_NEEDED);

        if (maj == GSS_S_COMPLETE) {
            ret = true;
            break;
        }
    }

done:
    gss_release_buffer(&min, &output);
    gss_release_buffer(&min, &input);
    gss_release_name(&min, &server);
    gss_delete_sec_context(&min, &server_ctx, GSS_C_NO_BUFFER);
    gss_release_cred(&min, &server_cred);
    gss_release_name(&min, &user);
    gss_release_cred(&min, &user_cred);
    gss_delete_sec_context(&min, &user_ctx, GSS_C_NO_BUFFER);
    gss_release_oid_set(&min, &actual_mechs);
    gss_release_oid_set(&min, &filtered_mechs);
#ifdef HAVE_GSS_KRB5_CCACHE_NAME
    if (user_ccache != NULL) {
        maj = gss_krb5_ccache_name(&min, orig_ccache, NULL);
        if (maj != GSS_S_COMPLETE) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
                          "Failed to restore per-thread ccache, %s",
                          mag_error(req, "gss_krb5_ccache_name() "
                                    "failed", maj, min));
        }
    }
#endif
    return ret;
}