+ int ret, fd;
+ krb5_keytab kt;
+ krb5_get_init_creds_opt icopts;
+ char buf[1024], *ccname, *filename;
+
+ krb5_get_init_creds_opt_init(&icopts);
+ kt = NULL;
+
+ if(opts->keytab) {
+ if((ret = krb5_kt_resolve(data->ctx, opts->keytab, &kt)) != 0) {
+ log(LOG_ERR, "could not resolve keytab `%s': %s", opts->keytab, error_message(ret));
+ ret = PAM_SERVICE_ERR;
+ goto out;
+ }
+ if(opts->debug)
+ log(LOG_DEBUG, "using keytab `%s'", opts->keytab);
+ }
+ krb5_get_init_creds_opt_set_forwardable(&icopts, opts->forwardable);
+ krb5_get_init_creds_opt_set_renew_life(&icopts, opts->renewable);
+ if(data->hascreds) {
+ krb5_free_cred_contents(data->ctx, &data->initcreds);
+ data->hascreds = 0;
+ }
+ if((ret = krb5_get_init_creds_keytab(data->ctx, &data->initcreds, data->me, kt, 0, NULL, &icopts)) != 0) {
+ log(LOG_ERR, "could not get credentials: %s", error_message(ret));
+ ret = PAM_SERVICE_ERR;
+ goto out;
+ }
+ data->hascreds = 1;
+ if(opts->debug)
+ log(LOG_DEBUG, "got creds successfully");
+ snprintf(buf, sizeof(buf), "KRB5CCNAME=FILE:/tmp/krb5cc_%i_XXXXXX", data->uid);
+ ccname = buf + sizeof("KRB5CCNAME=") - 1;
+ filename = ccname + sizeof("FILE:") - 1;
+ if((fd = mkstemp(filename)) < 0) {
+ log(LOG_ERR, "could not create tempfile for credentials cache: %s", strerror(errno));
+ ret = PAM_SERVICE_ERR;
+ goto out;
+ }
+ close(fd);
+ if(opts->debug)
+ log(LOG_DEBUG, "created ccache `%s'", filename);
+ if((ret = krb5_cc_resolve(data->ctx, ccname, &data->cc)) != 0) {
+ log(LOG_ERR, "could not resolve ccache `%s': %s", ccname, error_message(ret));
+ unlink(filename);
+ ret = PAM_SERVICE_ERR;
+ goto out;
+ }
+ if((ret = krb5_cc_initialize(data->ctx, data->cc, data->me)) != 0) {
+ log(LOG_ERR, "could not initialize credentials cache `%s': %s", ccname, error_message(ret));
+ unlink(filename);
+ ret = PAM_SERVICE_ERR;
+ goto out;
+ }
+ if((ret = krb5_cc_store_cred(data->ctx, data->cc, &data->initcreds)) != 0) {
+ log(LOG_ERR, "could not store credentials: %s", error_message(ret));
+ unlink(filename);
+ ret = PAM_SERVICE_ERR;
+ goto out;
+ }
+ chown(filename, data->uid, data->gid);
+ pam_putenv(pamh, strdup(buf));
+ if(opts->debug)
+ log(LOG_DEBUG, "successfully initialized ccache");
+ ret = PAM_SUCCESS;
+
+ out:
+ if(kt != NULL)
+ krb5_kt_close(data->ctx, kt);
+ return(ret);
+}
+
+static int delcreds(pam_handle_t *pamh, struct options *opts, struct data *data)
+{
+ if(opts->debug)
+ log(LOG_DEBUG, "deleting credentials");
+ if(data->hascreds) {
+ krb5_free_cred_contents(data->ctx, &data->initcreds);
+ data->hascreds = 0;
+ if(opts->debug)
+ log(LOG_DEBUG, "freed internal creds");
+ }
+ if(data->cc != NULL) {
+ krb5_cc_destroy(data->ctx, data->cc);
+ data->cc = NULL;
+ if(opts->debug)
+ log(LOG_DEBUG, "destroyed ccache");
+ }
+ return(PAM_SUCCESS);