Example #1
0
static int
list_caches(krb5_context context, struct klist_options *opt)
{
    krb5_cccol_cursor cursor;
    const char *cdef_name;
    char *def_name;
    krb5_error_code ret;
    krb5_ccache id;
    rtbl_t ct;

    cdef_name = krb5_cc_default_name(context);
    if (cdef_name == NULL)
	krb5_errx(context, 1, "krb5_cc_default_name");
    def_name = strdup(cdef_name);

    ret = krb5_cccol_cursor_new(context, &cursor);
    if (ret == KRB5_CC_NOSUPP)
	return 0;
    else if (ret)
	krb5_err (context, 1, ret, "krb5_cc_cache_get_first");

    ct = rtbl_create();
    rtbl_add_column(ct, COL_DEFCACHE, 0);
    rtbl_add_column(ct, COL_NAME, 0);
    rtbl_add_column(ct, COL_CACHENAME, 0);
    rtbl_add_column(ct, COL_EXPIRES, 0);
    rtbl_add_column(ct, COL_DEFCACHE, 0);
    rtbl_set_prefix(ct, "   ");
    rtbl_set_column_prefix(ct, COL_DEFCACHE, "");
    rtbl_set_column_prefix(ct, COL_NAME, " ");
    if (opt->json_flag)
	rtbl_set_flags(ct, RTBL_JSON);

    while (krb5_cccol_cursor_next(context, cursor, &id) == 0) {
	int expired = 0;
	char *name;
	time_t t;

	expired = check_expiration(context, id, &t);

	ret = krb5_cc_get_friendly_name(context, id, &name);
	if (ret == 0) {
	    const char *str;
	    char *fname;

	    rtbl_add_column_entry(ct, COL_NAME, name);
	    free(name);

	    if (expired)
		str = N_(">>> Expired <<<", "");
	    else
		str = printable_time(t);
	    rtbl_add_column_entry(ct, COL_EXPIRES, str);

	    ret = krb5_cc_get_full_name(context, id, &fname);
	    if (ret)
		krb5_err (context, 1, ret, "krb5_cc_get_full_name");

	    rtbl_add_column_entry(ct, COL_CACHENAME, fname);
	    if (opt->json_flag)
		;
	    else if (strcmp(fname, def_name) == 0)
		rtbl_add_column_entry(ct, COL_DEFCACHE, "*");
	    else
		rtbl_add_column_entry(ct, COL_DEFCACHE, "");

	    krb5_xfree(fname);
	}
	krb5_cc_close(context, id);
    }

    krb5_cccol_cursor_free(context, &cursor);

    free(def_name);
    rtbl_format(ct, stdout);
    rtbl_destroy(ct);

    if (opt->json_flag)
	printf("\n");

    return 0;
}
Example #2
0
static
NTSTATUS
LwIoCreateDefaultKrb5Creds(
    PIO_CREDS* ppCreds
    )
{
    NTSTATUS Status = STATUS_SUCCESS;
    krb5_context pKrb5Context = NULL;
    krb5_error_code krb5Error = 0;
    krb5_ccache pKrb5Cache = NULL;
    krb5_principal pKrb5Principal = NULL;
    char* pszPrincipalName = NULL;
    const char* pszCredCachePath = NULL;
    PIO_CREDS pCreds = NULL;

    *ppCreds = NULL;

    krb5Error = krb5_init_context(&pKrb5Context);
    if (krb5Error)
    {
        if (krb5Error == KRB5_CONFIG_BADFORMAT)
        {
            /* If krb5.conf is corrupted, give up */
            goto cleanup;
        }

        Status = STATUS_INSUFFICIENT_RESOURCES;
        BAIL_ON_NT_STATUS(Status);
    }

    pszCredCachePath = krb5_cc_default_name(pKrb5Context);
    if (!pszCredCachePath)
    {
        /* If there is no default path, give up */
        goto cleanup;
    }

    krb5Error = krb5_cc_resolve(pKrb5Context, pszCredCachePath, &pKrb5Cache);
    if (krb5Error)
    {
        /* If we can't access the cache, give up */
        goto cleanup;
    }

    krb5Error = krb5_cc_get_principal(pKrb5Context, pKrb5Cache, &pKrb5Principal);
    if (krb5Error)
    {
        /* If there is no principal, give up */
        goto cleanup;
    }

    krb5Error = krb5_unparse_name(pKrb5Context, pKrb5Principal, &pszPrincipalName);
    if (krb5Error)
    {
        Status = STATUS_UNSUCCESSFUL;
        BAIL_ON_NT_STATUS(Status);
    }
    
    Status = LwIoAllocateMemory(sizeof(*pCreds), OUT_PPVOID(&pCreds));
    BAIL_ON_NT_STATUS(Status);

    pCreds->type = IO_CREDS_TYPE_KRB5_CCACHE;

    Status = LwRtlWC16StringAllocateFromCString(
        &pCreds->payload.krb5Ccache.pwszPrincipal,
        pszPrincipalName
        );
    BAIL_ON_NT_STATUS(Status);
    
    Status = LwRtlWC16StringAllocateFromCString(
        &pCreds->payload.krb5Ccache.pwszCachePath,
        pszCredCachePath
        );
    BAIL_ON_NT_STATUS(Status);

    *ppCreds = pCreds;

cleanup:

    if (pszPrincipalName)
    {
        krb5_free_unparsed_name(pKrb5Context, pszPrincipalName);
    }
    if (pKrb5Principal)
    {
        krb5_free_principal(pKrb5Context, pKrb5Principal);
    }
    if (pKrb5Cache)
    {
        krb5_cc_close(pKrb5Context, pKrb5Cache);
    }
    if (pKrb5Context)
    {
        krb5_free_context(pKrb5Context);
    }

    return Status;

error:

    if (pCreds)
    {
        LwIoDeleteCreds(pCreds);
    }

    goto cleanup;
}
Example #3
0
/*
  get a kerberos5 ticket for the given service 
*/
int cli_krb5_get_ticket(const char *principal, time_t time_offset, 
			DATA_BLOB *ticket, DATA_BLOB *session_key_krb5, 
			uint32 extra_ap_opts, const char *ccname, 
			time_t *tgs_expire)

{
	krb5_error_code retval;
	krb5_data packet;
	krb5_context context = NULL;
	krb5_ccache ccdef = NULL;
	krb5_auth_context auth_context = NULL;
	krb5_enctype enc_types[] = {
#ifdef ENCTYPE_ARCFOUR_HMAC
		ENCTYPE_ARCFOUR_HMAC,
#endif 
		ENCTYPE_DES_CBC_MD5, 
		ENCTYPE_DES_CBC_CRC, 
		ENCTYPE_NULL};

	initialize_krb5_error_table();
	retval = krb5_init_context(&context);
	if (retval) {
		DEBUG(1,("cli_krb5_get_ticket: krb5_init_context failed (%s)\n", 
			 error_message(retval)));
		goto failed;
	}

	if (time_offset != 0) {
		krb5_set_real_time(context, time(NULL) + time_offset, 0);
	}

	if ((retval = krb5_cc_resolve(context, ccname ?
			ccname : krb5_cc_default_name(context), &ccdef))) {
		DEBUG(1,("cli_krb5_get_ticket: krb5_cc_default failed (%s)\n",
			 error_message(retval)));
		goto failed;
	}

	if ((retval = krb5_set_default_tgs_ktypes(context, enc_types))) {
		DEBUG(1,("cli_krb5_get_ticket: krb5_set_default_tgs_ktypes failed (%s)\n",
			 error_message(retval)));
		goto failed;
	}

	if ((retval = ads_krb5_mk_req(context, 
					&auth_context, 
					AP_OPTS_USE_SUBKEY | (krb5_flags)extra_ap_opts,
					principal,
					ccdef, &packet,
					tgs_expire))) {
		goto failed;
	}

	get_krb5_smb_session_key(context, auth_context, session_key_krb5, False);

	*ticket = data_blob(packet.data, packet.length);

 	kerberos_free_data_contents(context, &packet); 

failed:

	if ( context ) {
		if (ccdef)
			krb5_cc_close(context, ccdef);
		if (auth_context)
			krb5_auth_con_free(context, auth_context);
		krb5_free_context(context);
	}
		
	return retval;
}
Example #4
0
int
main(int argc, char **argv)
{
    krb5_error_code ret;
    krb5_context context;
    int optidx = 0;
    const char *from_name, *to_name;
    krb5_ccache from_ccache, to_ccache;
    unsigned int matched;
    struct ctx ctx;

    setprogname(argv[0]);

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

    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 < 1 || argc > 2)
	usage(1);

    if (krb5_init_context(&context))
	errx(1, "krb5_init_context failed");

    if (service_string) {
	ret = krb5_parse_name(context, service_string, &ctx.mcreds.server);
	if (ret)
	    krb5_err(context, 1, ret, "%s", service_string);
    }
    if (enctype_string) {
	krb5_enctype enctype;
	ret = krb5_string_to_enctype(context, enctype_string, &enctype);
	if (ret)
	    krb5_err(context, 1, ret, "%s", enctype_string);
	ctx.whichfields |= KRB5_TC_MATCH_KEYTYPE;
	ctx.mcreds.session.keytype = enctype;
    }
    if (flags_string) {
	parse_ticket_flags(context, flags_string, &ctx.mcreds.flags);
	ctx.whichfields |= KRB5_TC_MATCH_FLAGS;
    }
    if (valid_string) {
	time_t t = parse_time(valid_string, "s");
	if(t < 0)
	    errx(1, "unknown time \"%s\"", valid_string);
	ctx.mcreds.times.endtime = time(NULL) + t;
	ctx.whichfields |= KRB5_TC_MATCH_TIMES;
    }
    if (fcache_version)
	krb5_set_fcache_version(context, fcache_version);

    if (argc == 1) {
	from_name = krb5_cc_default_name(context);
	to_name = argv[0];
    } else {
	from_name = argv[0];
	to_name = argv[1];
    }

    ret = krb5_cc_resolve(context, from_name, &from_ccache);
    if (ret)
	krb5_err(context, 1, ret, "%s", from_name);

    if (krbtgt_only_flag) {
	krb5_principal client;
	ret = krb5_cc_get_principal(context, from_ccache, &client);
	if (ret)
	    krb5_err(context, 1, ret, "getting default principal");
	ret = krb5_make_principal(context, &ctx.mcreds.server,
				  krb5_principal_get_realm(context, client),
				  KRB5_TGS_NAME,
				  krb5_principal_get_realm(context, client),
				  NULL);
	if (ret)
	    krb5_err(context, 1, ret, "constructing krbtgt principal");
	krb5_free_principal(context, client);
    }
    ret = krb5_cc_resolve(context, to_name, &to_ccache);
    if (ret)
	krb5_err(context, 1, ret, "%s", to_name);

    ret = krb5_cc_copy_match_f(context, from_ccache, to_ccache,
			       matchfunc, &ctx, &matched);
    if (ret)
	krb5_err(context, 1, ret, "copying cred cache");

    krb5_cc_close(context, from_ccache);
    if(matched == 0)
	krb5_cc_destroy(context, to_ccache);
    else
	krb5_cc_close(context, to_ccache);
    krb5_free_context(context);
    return matched == 0;
}
Example #5
0
 krb5_error_code smb_krb5_renew_ticket(const char *ccache_string,	/* FILE:/tmp/krb5cc_0 */
				       const char *client_string,	/* [email protected] */
				       const char *service_string,	/* krbtgt/[email protected] */
				       time_t *expire_time)
{
	krb5_error_code ret;
	krb5_context context = NULL;
	krb5_ccache ccache = NULL;
	krb5_principal client = NULL;

	initialize_krb5_error_table();
	ret = krb5_init_context(&context);
	if (ret) {
		goto done;
	}

	if (!ccache_string) {
		ccache_string = krb5_cc_default_name(context);
	}

	DEBUG(10,("smb_krb5_renew_ticket: using %s as ccache\n", ccache_string));

	/* FIXME: we should not fall back to defaults */
	ret = krb5_cc_resolve(context, CONST_DISCARD(char *, ccache_string), &ccache);
	if (ret) {
		goto done;
	}

#ifdef HAVE_KRB5_GET_RENEWED_CREDS	/* MIT */
	{
		krb5_creds creds;
	
		if (client_string) {
			ret = smb_krb5_parse_name(context, client_string, &client);
			if (ret) {
				goto done;
			}
		} else {
			ret = krb5_cc_get_principal(context, ccache, &client);
			if (ret) {
				goto done;
			}
		}
	
		ret = krb5_get_renewed_creds(context, &creds, client, ccache, CONST_DISCARD(char *, service_string));
		if (ret) {
			DEBUG(10,("smb_krb5_renew_ticket: krb5_get_kdc_cred failed: %s\n", error_message(ret)));
			goto done;
		}

		/* hm, doesn't that create a new one if the old one wasn't there? - Guenther */
		ret = krb5_cc_initialize(context, ccache, client);
		if (ret) {
			goto done;
		}
	
		ret = krb5_cc_store_cred(context, ccache, &creds);

		if (expire_time) {
			*expire_time = (time_t) creds.times.endtime;
		}

		krb5_free_cred_contents(context, &creds);
	}
#elif defined(HAVE_KRB5_GET_KDC_CRED)	/* Heimdal */
	{
		krb5_kdc_flags flags;
		krb5_creds creds_in;
		krb5_realm *client_realm;
		krb5_creds *creds;

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

		if (client_string) {
			ret = smb_krb5_parse_name(context, client_string, &creds_in.client);
			if (ret) {
				goto done;
			}
		} else {
			ret = krb5_cc_get_principal(context, ccache, &creds_in.client);
			if (ret) {
				goto done;
			}
		}

		if (service_string) {
			ret = smb_krb5_parse_name(context, service_string, &creds_in.server);
			if (ret) { 
				goto done;
			}
		} else {
			/* build tgt service by default */
			client_realm = krb5_princ_realm(context, creds_in.client);
			if (!client_realm) {
				ret = ENOMEM;
				goto done;
			}
			ret = krb5_make_principal(context, &creds_in.server, *client_realm, KRB5_TGS_NAME, *client_realm, NULL);
			if (ret) {
				goto done;
			}
		}

		flags.i = 0;
		flags.b.renewable = flags.b.renew = True;

		ret = krb5_get_kdc_cred(context, ccache, flags, NULL, NULL, &creds_in, &creds);
		if (ret) {
			DEBUG(10,("smb_krb5_renew_ticket: krb5_get_kdc_cred failed: %s\n", error_message(ret)));
			goto done;
		}
		
		/* hm, doesn't that create a new one if the old one wasn't there? - Guenther */
		ret = krb5_cc_initialize(context, ccache, creds_in.client);
		if (ret) {
			goto done;
		}
	
		ret = krb5_cc_store_cred(context, ccache, creds);

		if (expire_time) {
			*expire_time = (time_t) creds->times.endtime;
		}
						
		krb5_free_cred_contents(context, &creds_in);
		krb5_free_creds(context, creds);
	}
#else
#error No suitable krb5 ticket renew function available
#endif


done:
	if (client) {
		krb5_free_principal(context, client);
	}
	if (context) {
		krb5_free_context(context);
	}
	if (ccache) {
		krb5_cc_close(context, ccache);
	}

	return ret;
    
}
Example #6
0
static char *
init_cc_from_keytab(const char *keytab_name, const char *user)
{
	krb5_context context = NULL;
	krb5_error_code ret;
	krb5_creds my_creds;
	krb5_keytab keytab = NULL;
	krb5_principal me = NULL;
	krb5_ccache cc = NULL;
	char *ccname = NULL;

	memset((char *) &my_creds, 0, sizeof(my_creds));

	ret = krb5_init_context(&context);
	if (ret) {
		syslog(LOG_DEBUG, "krb5_init_context: %d", (int)ret);
		goto icfk_cleanup;
	}

	ret = krb5_kt_resolve(context, keytab_name, &keytab);
	if (ret) {
		syslog(LOG_DEBUG, "krb5_kt_resolve: %d", (int)ret);
		goto icfk_cleanup;
	}

	ret = krb5_parse_name(context, user, &me);
	if (ret) {
		syslog(LOG_DEBUG, "krb5_parse_name: %d", (int)ret);
		goto icfk_cleanup;
	}

	ret = krb5_get_init_creds_keytab(context, &my_creds, me,
			keytab, 0, NULL, NULL);
	if (ret) {
		syslog(LOG_DEBUG, "krb5_get_init_creds_keytab: %d", (int)ret);
		goto icfk_cleanup;
	}

	ret = krb5_cc_default(context, &cc);
	if (ret) {
		syslog(LOG_DEBUG, "krb5_cc_default: %d", (int)ret);
		goto icfk_cleanup;
	}

	ret = krb5_cc_initialize(context, cc, me);
	if (ret) {
		syslog(LOG_DEBUG, "krb5_cc_initialize: %d", (int)ret);
		goto icfk_cleanup;
	}

	ret = krb5_cc_store_cred(context, cc, &my_creds);
	if (ret)
		syslog(LOG_DEBUG, "krb5_cc_store_cred: %d", (int)ret);

	ccname = strdup(krb5_cc_default_name(context));
	if (ccname == NULL)
		syslog(LOG_ERR, "Unable to allocate memory");
icfk_cleanup:
	my_creds.client = 0;
	krb5_free_cred_contents(context, &my_creds);

	if (me)
		krb5_free_principal(context, me);
	if (cc)
		krb5_cc_close(context, cc);
	if (keytab)
		krb5_kt_close(context, keytab);
	if (context)
		krb5_free_context(context);
	return ccname;
}
Example #7
0
krb5_error_code KRB5_CALLCONV
krb5_cccol_have_content(krb5_context context)
{
    krb5_error_code ret;
    krb5_cccol_cursor col_cursor;
    krb5_cc_cursor cache_cursor;
    krb5_ccache cache;
    krb5_creds creds;
    krb5_boolean found = FALSE;
    struct errinfo errsave = EMPTY_ERRINFO;
    const char *defname;

    ret = krb5_cccol_cursor_new(context, &col_cursor);
    save_first_error(context, ret, &errsave);
    if (ret)
        goto no_entries;

    while (!found) {
        ret = krb5_cccol_cursor_next(context, col_cursor, &cache);
        save_first_error(context, ret, &errsave);
        if (ret || cache == NULL)
            break;

        ret = krb5_cc_start_seq_get(context, cache, &cache_cursor);
        save_first_error(context, ret, &errsave);
        if (ret)
            continue;
        while (!found) {
            ret = krb5_cc_next_cred(context, cache, &cache_cursor, &creds);
            save_first_error(context, ret, &errsave);
            if (ret)
                break;

            if (!krb5_is_config_principal(context, creds.server))
                found = TRUE;
            krb5_free_cred_contents(context, &creds);
        }
        krb5_cc_end_seq_get(context, cache, &cache_cursor);
        krb5_cc_close(context, cache);
    }
    krb5_cccol_cursor_free(context, &col_cursor);
    if (found)
        return 0;

no_entries:
    if (errsave.code) {
        /* Report the first error we encountered. */
        ret = k5_restore_ctx_error(context, &errsave);
        k5_wrapmsg(context, ret, KRB5_CC_NOTFOUND,
                   _("No Kerberos credentials available"));
    } else {
        /* Report the default cache name. */
        defname = krb5_cc_default_name(context);
        if (defname != NULL) {
            k5_setmsg(context, KRB5_CC_NOTFOUND,
                      _("No Kerberos credentials available "
                        "(default cache: %s)"), defname);
        }
    }
    return KRB5_CC_NOTFOUND;
}
int Condor_Auth_Kerberos :: init_user()
{
    int             rc = TRUE;
    krb5_error_code code;
    krb5_ccache     ccache = (krb5_ccache) NULL;
    krb5_creds      mcreds;

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

    dprintf(D_SECURITY, "Acquiring credential for user\n");

    //------------------------------------------
    // First, try the default credential cache
    //------------------------------------------
    ccname_ = strdup(krb5_cc_default_name(krb_context_));
    
    if ((code = krb5_cc_resolve(krb_context_, ccname_, &ccache))) {
        goto error;
    }
    
    //------------------------------------------
    // Get principal info
    //------------------------------------------
    if ((code = krb5_cc_get_principal(krb_context_, ccache, &krb_principal_))) {
        goto error;
    }

    if ((code = krb5_copy_principal(krb_context_,krb_principal_,&mcreds.client))){
        goto error;
    }
    
    if ((code = krb5_copy_principal(krb_context_, server_, &mcreds.server))) {
        goto error;
    }
    
   	dprintf_krb5_principal ( D_FULLDEBUG, "init_user: pre mcreds->client is '%s'\n", mcreds.client);
	dprintf_krb5_principal ( D_FULLDEBUG, "init_user: pre mcreds->server is '%s'\n", mcreds.server);
	if (creds_) {
		dprintf_krb5_principal ( D_FULLDEBUG, "init_user: pre creds_->client is '%s'\n", creds_->client);
		dprintf_krb5_principal ( D_FULLDEBUG, "init_user: pre creds_->server is '%s'\n", creds_->server);
	} else {
		dprintf ( D_FULLDEBUG, "init_user: pre creds_ is NULL\n");
	}		

    if ((code = krb5_get_credentials(krb_context_, 0, ccache, &mcreds, &creds_))) {
        goto error;
    }                                   

	dprintf_krb5_principal ( D_FULLDEBUG, "init_user: post mcreds->client is '%s'\n", mcreds.client);
	dprintf_krb5_principal ( D_FULLDEBUG, "init_user: post mcreds->server is '%s'\n", mcreds.server);
	if (creds_) {
		dprintf_krb5_principal ( D_FULLDEBUG, "init_user: post creds_->client is '%s'\n", creds_->client);
		dprintf_krb5_principal ( D_FULLDEBUG, "init_user: post creds_->server is '%s'\n", creds_->server);
	} else {
		dprintf ( D_FULLDEBUG, "init_user: post creds_ is NULL\n");
	}		
    
    dprintf(D_SECURITY, "Successfully located credential cache\n");
    
    rc = TRUE;
    goto cleanup;
    
 error:
    dprintf( D_ALWAYS, "KERBEROS: %s\n", error_message(code) );
    rc = FALSE;

 cleanup:

    krb5_free_cred_contents(krb_context_, &mcreds);

    if (ccache) {  // maybe should destroy this
        krb5_cc_close(krb_context_, ccache);
    }
    return rc;
}
Example #9
0
File: sly.c Project: OPSF/uClinux
int
_pam_krb5_sly_maybe_refresh(pam_handle_t *pamh, int flags,
			    int argc, PAM_KRB5_MAYBE_CONST char **argv)
{
	PAM_KRB5_MAYBE_CONST char *user;
	krb5_context ctx;
	struct _pam_krb5_options *options;
	struct _pam_krb5_user_info *userinfo;
	struct _pam_krb5_stash *stash;
	struct stat st;
	int i, retval, stored;
	uid_t uid;
	gid_t gid;
	const char *v5ccname, *v5filename, *v4tktfile;
#ifdef TKT_ROOT
	char v4tktfilebuf[PATH_MAX];
#endif

	/* Inexpensive checks. */
	switch (_pam_krb5_sly_looks_unsafe()) {
	case 0:
		/* nothing: everything's okay */
		break;
	case 1:
		warn("won't refresh credentials while running under sudo");
		return PAM_SERVICE_ERR;
		break;
	case 2:
		warn("won't refresh credentials while running setuid");
		return PAM_SERVICE_ERR;
		break;
	case 3:
		warn("won't refresh credentials while running setgid");
		return PAM_SERVICE_ERR;
		break;
	default:
		warn("not safe to refresh credentials");
		return PAM_SERVICE_ERR;
		break;
	}

	/* Initialize Kerberos. */
	if (_pam_krb5_init_ctx(&ctx, argc, argv) != 0) {
		warn("error initializing Kerberos");
		return PAM_SERVICE_ERR;
	}

	/* Get the user's name. */
	i = pam_get_user(pamh, &user, NULL);
	if ((i != PAM_SUCCESS) || (user == NULL)) {
		warn("could not identify user name");
		krb5_free_context(ctx);
		return i;
	}

	/* Read our options. */
	options = _pam_krb5_options_init(pamh, argc, argv, ctx);
	if (options == NULL) {
		warn("error parsing options (shouldn't happen)");
		krb5_free_context(ctx);
		return PAM_SERVICE_ERR;
	}
	if (options->debug) {
		debug("called to update credentials for '%s'", user);
	}

	/* Get information about the user and the user's principal name. */
	userinfo = _pam_krb5_user_info_init(ctx, user, options);
	if (userinfo == NULL) {
		if (options->ignore_unknown_principals) {
			retval = PAM_IGNORE;
		} else {
			warn("error getting information about '%s' "
			     "(shouldn't happen)", user);
			retval = PAM_USER_UNKNOWN;
		}
		_pam_krb5_options_free(pamh, ctx, options);
		krb5_free_context(ctx);
		return retval;
	}

	if ((options->user_check) &&
	    (options->minimum_uid != (uid_t)-1) &&
	    (userinfo->uid < options->minimum_uid)) {
		if (options->debug) {
			debug("ignoring '%s' -- uid below minimum", user);
		}
		_pam_krb5_user_info_free(ctx, userinfo);
		_pam_krb5_options_free(pamh, ctx, options);
		krb5_free_context(ctx);
		return PAM_IGNORE;
	}

	/* Get the stash for this user. */
	stash = _pam_krb5_stash_get(pamh, user, userinfo, options);
	if (stash == NULL) {
		warn("error retrieving stash for '%s' (shouldn't happen)",
		     user);
		_pam_krb5_user_info_free(ctx, userinfo);
		_pam_krb5_options_free(pamh, ctx, options);
		krb5_free_context(ctx);
		return PAM_SERVICE_ERR;
	}

	retval = PAM_SERVICE_ERR;

	/* Save credentials in the right places. */
	v5ccname = krb5_cc_default_name(ctx);
	v5filename = NULL;
	if (v5ccname == NULL) {
		/* This should never happen, but all we can do is tell libpam
		 * to ignore us.  We have nothing to do. */
		if (options->debug) {
			debug("ignoring '%s' -- no default ccache name", user);
		}
		retval = PAM_IGNORE;
	} else {
		if (strncmp(v5ccname, "FILE:", 5) == 0) {
			v5filename = v5ccname + 5;
			if (options->debug) {
				debug("ccache is a file named '%s'",
				      v5filename);
			}
		} else {
			if (options->debug) {
				debug("ccache '%s' is not a file", v5ccname);
			}
		}
	}

	stored = 0;
	uid = options->user_check ? userinfo->uid : getuid();
	gid = options->user_check ? userinfo->gid : getgid();

	if (v5_creds_check_initialized(ctx, &stash->v5creds) == 0) {
		if (v5filename != NULL) {
			/* Check the permissions on the ccache file. */
			if ((access(v5filename, R_OK | W_OK) == 0) &&
			    (lstat(v5filename, &st) == 0)) {
				if (S_ISREG(st.st_mode) &&
				    ((st.st_mode & S_IRWXG) == 0) &&
				    ((st.st_mode & S_IRWXO) == 0) &&
				    (st.st_uid == uid) &&
				    (st.st_gid == gid)) {
					if (options->debug) {
						debug("updating ccache '%s' "
						      "for '%s'",
						      v5ccname, user);
					}
					retval = sly_v5(ctx, v5ccname,
							userinfo, stash);
					stored = (retval == PAM_SUCCESS);
				} else {
					if (options->debug) {
						debug("not updating '%s'",
						      v5ccname);
					}
					retval = PAM_SUCCESS;
				}
			} else {
				if (errno == ENOENT) {
					/* We have nothing to do. */
					retval = PAM_SUCCESS;
				}
			}
		} else {
			if (v5ccname != NULL) {
				/* Go ahead and update the current not-a-file
				 * ccache. */
				if (options->debug) {
					debug("updating ccache '%s' for '%s'",
					      v5ccname, user);
				}
				retval = sly_v5(ctx, v5ccname, userinfo, stash);
				stored = (retval == PAM_SUCCESS);
			}
		}
	} else {
		if (options->debug) {
			debug("no credentials available to store in '%s'",
			      v5ccname);
		}
		retval = PAM_SUCCESS;
	}

	v4tktfile = getenv("KRBTKFILE");
#ifdef TKT_ROOT
	if ((v4tktfile == NULL) && (options->user_check)) {
		snprintf(v4tktfilebuf, sizeof(v4tktfilebuf), "%s%ld",
			 TKT_ROOT, (long) uid);
		v4tktfile = v4tktfilebuf;
	}
#endif
	if ((stash->v4present) && (v4tktfile != NULL)) {
		if (access(v4tktfile, R_OK | W_OK) == 0) {
			if (lstat(v4tktfile, &st) == 0) {
				if (S_ISREG(st.st_mode) &&
				    ((st.st_mode & S_IRWXG) == 0) &&
				    ((st.st_mode & S_IRWXO) == 0) &&
				    (st.st_uid == uid) &&
				    (st.st_gid == gid)) {
					if (options->debug) {
						debug("updating ticket file "
						      "'%s' for '%s'",
						      v4tktfile, user);
					}
					sly_v4(ctx, v4tktfile, userinfo, stash);
					stored = 1;
				} else {
					if (options->debug) {
						debug("not updating '%s'",
						      v4tktfile);
					}
				}
			} else {
				if (errno == ENOENT) {
					/* We have nothing to do. */
					if (options->debug) {
						debug("no preexisting ticket "
						      "file found");
					}
					retval = PAM_SUCCESS;
				}
			}
		} else {
			/* Touch nothing. */
			if (options->debug) {
				debug("unable to access preexisting ticket "
				      "file");
			}
			retval = PAM_SUCCESS;
		}
	}

	if (stored && !options->ignore_afs) {
		tokens_obtain(ctx, stash, options, userinfo, 0);
	}

	if (options->debug) {
		debug("_pam_krb5_sly_refresh returning %d (%s)", retval,
		      pam_strerror(pamh, retval));
	}

	_pam_krb5_user_info_free(ctx, userinfo);
	_pam_krb5_options_free(pamh, ctx, options);
	krb5_free_context(ctx);

	return retval;
}