Пример #1
0
static void
test_mcache(krb5_context context)
{
    krb5_error_code ret;
    krb5_ccache id, id2;
    const char *nc, *tc;
    char *c;
    krb5_principal p, p2;

    ret = krb5_parse_name(context, "*****@*****.**", &p);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id);
    if (ret)
	krb5_err(context, 1, ret, "krb5_cc_new_unique");

    ret = krb5_cc_initialize(context, id, p);
    if (ret)
	krb5_err(context, 1, ret, "krb5_cc_initialize");

    nc = krb5_cc_get_name(context, id);
    if (nc == NULL)
	krb5_errx(context, 1, "krb5_cc_get_name");

    tc = krb5_cc_get_type(context, id);
    if (tc == NULL)
	krb5_errx(context, 1, "krb5_cc_get_name");

    if (asprintf(&c, "%s:%s", tc, nc) < 0 || c == NULL)
	errx(1, "malloc");

    krb5_cc_close(context, id);

    ret = krb5_cc_resolve(context, c, &id2);
    if (ret)
	krb5_err(context, 1, ret, "krb5_cc_resolve");

    ret = krb5_cc_get_principal(context, id2, &p2);
    if (ret)
	krb5_err(context, 1, ret, "krb5_cc_get_principal");

    if (krb5_principal_compare(context, p, p2) == FALSE)
	krb5_errx(context, 1, "p != p2");

    krb5_cc_destroy(context, id2);
    krb5_free_principal(context, p);
    krb5_free_principal(context, p2);

    ret = krb5_cc_resolve(context, c, &id2);
    if (ret)
	krb5_err(context, 1, ret, "krb5_cc_resolve");

    ret = krb5_cc_get_principal(context, id2, &p2);
    if (ret == 0)
	krb5_errx(context, 1, "krb5_cc_get_principal");

    krb5_cc_destroy(context, id2);
    free(c);
}
Пример #2
0
/* Display the contents of cache. */
static int
show_ccache(krb5_ccache cache)
{
    krb5_cc_cursor cur;
    krb5_creds creds;
    krb5_principal princ;
    krb5_error_code ret;

    ret = krb5_cc_get_principal(context, cache, &princ);
    if (ret) {
        com_err(progname, ret, "");
        return 1;
    }
    ret = krb5_unparse_name(context, princ, &defname);
    if (ret) {
        com_err(progname, ret, _("while unparsing principal name"));
        return 1;
    }

    printf(_("Ticket cache: %s:%s\nDefault principal: %s\n\n"),
           krb5_cc_get_type(context, cache), krb5_cc_get_name(context, cache),
           defname);
    /* XXX Translating would disturb table alignment; skip for now. */
    fputs("Valid starting", stdout);
    fillit(stdout, timestamp_width - sizeof("Valid starting") + 3, (int) ' ');
    fputs("Expires", stdout);
    fillit(stdout, timestamp_width - sizeof("Expires") + 3, (int) ' ');
    fputs("Service principal\n", stdout);

    ret = krb5_cc_start_seq_get(context, cache, &cur);
    if (ret) {
        com_err(progname, ret, _("while starting to retrieve tickets"));
        return 1;
    }
    while ((ret = krb5_cc_next_cred(context, cache, &cur, &creds)) == 0) {
        if (show_config || !krb5_is_config_principal(context, creds.server))
            show_credential(&creds);
        krb5_free_cred_contents(context, &creds);
    }
    krb5_free_principal(context, princ);
    krb5_free_unparsed_name(context, defname);
    defname = NULL;
    if (ret == KRB5_CC_END) {
        ret = krb5_cc_end_seq_get(context, cache, &cur);
        if (ret) {
            com_err(progname, ret, _("while finishing ticket retrieval"));
            return 1;
        }
        return 0;
    } else {
        com_err(progname, ret, _("while retrieving a ticket"));
        return 1;
    }
}
Пример #3
0
static int
print_tickets (krb5_context context,
	       krb5_ccache ccache,
	       krb5_principal principal)
{
    krb5_error_code ret;
    krb5_cc_cursor cursor;
    krb5_creds cred;
    char *str;

    ret = krb5_unparse_name (context, principal, &str);
    if (ret) {
	lreply(500, "krb5_unparse_name: %d", ret);
	return 500;
    }

    lreply(200, "%17s: %s:%s",
	   "Credentials cache",
	   krb5_cc_get_type(context, ccache),
	   krb5_cc_get_name(context, ccache));
    lreply(200, "%17s: %s", "Principal", str);
    free (str);

    ret = krb5_cc_start_seq_get (context, ccache, &cursor);
    if (ret) {
	lreply(500, "krb5_cc_start_seq_get: %d", ret);
	return 500;
    }

    lreply(200, "  Issued               Expires              Principal");

    while ((ret = krb5_cc_next_cred (context,
				     ccache,
				     &cursor,
				     &cred)) == 0) {
	if (print_cred(context, &cred))
	    return 500;
	krb5_free_cred_contents (context, &cred);
    }
    if (ret != KRB5_CC_END) {
	lreply(500, "krb5_cc_get_next: %d", ret);
	return 500;
    }
    ret = krb5_cc_end_seq_get (context, ccache, &cursor);
    if (ret) {
	lreply(500, "krb5_cc_end_seq_get: %d", ret);
	return 500;
    }

    return 200;
}
Пример #4
0
static void
test_init_vs_destroy(krb5_context context, const char *type)
{
    krb5_error_code ret;
    krb5_ccache id, id2;
    krb5_principal p, p2;
    char *n = NULL;

    ret = krb5_parse_name(context, "*****@*****.**", &p);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    ret = krb5_cc_new_unique(context, type, NULL, &id);
    if (ret)
	krb5_err(context, 1, ret, "krb5_cc_new_unique");

    if (asprintf(&n, "%s:%s",
		 krb5_cc_get_type(context, id),
		 krb5_cc_get_name(context, id)) < 0 || n == NULL)
	errx(1, "malloc");
	

    ret = krb5_cc_resolve(context, n, &id2);
    free(n);
    if (ret)
	krb5_err(context, 1, ret, "krb5_cc_resolve");

    krb5_cc_destroy(context, id);

    ret = krb5_cc_initialize(context, id2, p);
    if (ret)
	krb5_err(context, 1, ret, "krb5_cc_initialize");

    ret = krb5_cc_get_principal(context, id2, &p2);
    if (ret)
	krb5_err(context, 1, ret, "krb5_cc_get_principal");

    krb5_cc_destroy(context, id2);
    krb5_free_principal(context, p);
    krb5_free_principal(context, p2);
}
Пример #5
0
krb5_error_code KRB5_CALLCONV
krb5_get_init_creds_opt_set_fast_ccache(krb5_context context,
                                        krb5_get_init_creds_opt *opt,
                                        krb5_ccache ccache)
{
    krb5_error_code retval = 0;
    struct k5buf buf;
    char *cc_name;

    krb5int_buf_init_dynamic(&buf);
    krb5int_buf_add(&buf, krb5_cc_get_type(context, ccache));
    krb5int_buf_add(&buf, ":");
    krb5int_buf_add(&buf, krb5_cc_get_name(context, ccache));
    cc_name = krb5int_buf_data(&buf);
    if (cc_name)
        retval = krb5_get_init_creds_opt_set_fast_ccache_name(context, opt,
                                                              cc_name);
    else
        retval = ENOMEM;
    krb5int_free_buf(&buf);
    return retval;
}
Пример #6
0
Файл: su.c Проект: Sp1l/heimdal
static int
krb5_start_session(void)
{
    krb5_ccache ccache2;
    char *cc_name;
    int ret;

    ret = krb5_cc_new_unique(context, krb5_cc_type_file, NULL, &ccache2);
    if (ret) {
	krb5_cc_destroy(context, ccache);
	return 1;
    }

    ret = krb5_cc_copy_cache(context, ccache, ccache2);
    if (ret) {
	krb5_cc_destroy(context, ccache);
	krb5_cc_destroy(context, ccache2);
	return 1;
    }

    ret = asprintf(&cc_name, "%s:%s", krb5_cc_get_type(context, ccache2),
		   krb5_cc_get_name(context, ccache2));
    if (ret == -1) {
	krb5_cc_destroy(context, ccache);
	krb5_cc_destroy(context, ccache2);
	errx(1, "malloc - out of memory");
    }
    esetenv("KRB5CCNAME", cc_name, 1);

    /* convert creds? */
    if(k_hasafs()) {
	if (k_setpag() == 0)
	    krb5_afslog(context, ccache2, NULL, NULL);
    }

    krb5_cc_close(context, ccache2);
    krb5_cc_destroy(context, ccache);
    return 0;
}
Пример #7
0
static void
test_init_vs_destroy(krb5_context context, const krb5_cc_ops *ops)
{
    krb5_error_code ret;
    krb5_ccache id, id2;
    krb5_principal p, p2;
    char *n;

    ret = krb5_parse_name(context, "*****@*****.**", &p);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    ret = krb5_cc_gen_new(context, ops, &id);
    if (ret)
	krb5_err(context, 1, ret, "krb5_cc_gen_new");

    asprintf(&n, "%s:%s",
	     krb5_cc_get_type(context, id),
	     krb5_cc_get_name(context, id));

    ret = krb5_cc_resolve(context, n, &id2);
    if (ret)
	krb5_err(context, 1, ret, "krb5_cc_resolve");

    krb5_cc_destroy(context, id);

    ret = krb5_cc_initialize(context, id2, p);
    if (ret)
	krb5_err(context, 1, ret, "krb5_cc_initialize");

    ret = krb5_cc_get_principal(context, id2, &p2);
    if (ret)
	krb5_err(context, 1, ret, "krb5_cc_get_principal");

    krb5_cc_destroy(context, id2);
    krb5_free_principal(context, p);
    krb5_free_principal(context, p2);
}
Пример #8
0
static BOOL ads_cleanup_expired_creds(krb5_context context, 
				      krb5_ccache  ccache,
				      krb5_creds  *credsp)
{
	krb5_error_code retval;
	const char *cc_type = krb5_cc_get_type(context, ccache);

	DEBUG(3, ("ads_cleanup_expired_creds: Ticket in ccache[%s:%s] expiration %s\n",
		  cc_type, krb5_cc_get_name(context, ccache),
		  http_timestring(credsp->times.endtime)));

	/* we will probably need new tickets if the current ones
	   will expire within 10 seconds.
	*/
	if (credsp->times.endtime >= (time(NULL) + 10))
		return False;

	/* heimdal won't remove creds from a file ccache, and 
	   perhaps we shouldn't anyway, since internally we 
	   use memory ccaches, and a FILE one probably means that
	   we're using creds obtained outside of our exectuable
	*/
	if (strequal(cc_type, "FILE")) {
		DEBUG(5, ("ads_cleanup_expired_creds: We do not remove creds from a %s ccache\n", cc_type));
		return False;
	}

	retval = krb5_cc_remove_cred(context, ccache, 0, credsp);
	if (retval) {
		DEBUG(1, ("ads_cleanup_expired_creds: krb5_cc_remove_cred failed, err %s\n",
			  error_message(retval)));
		/* If we have an error in this, we want to display it,
		   but continue as though we deleted it */
	}
	return True;
}
Пример #9
0
DWORD
LwTaskAcquireCredsA(
    PCSTR           pszUsername,  /* IN     */
    PCSTR           pszPassword,  /* IN     */
    PLW_TASK_CREDS* ppCreds       /* IN OUT */
    )
{
    DWORD dwError = 0;
    krb5_error_code ret = 0;
    PSTR   pszNewCachePath = NULL;
    PLW_TASK_CREDS pCreds = NULL;

    BAIL_ON_INVALID_POINTER(ppCreds);
    BAIL_ON_INVALID_STRING(pszUsername);

    dwError = LwAllocateMemory(sizeof(*pCreds), (PVOID*)&pCreds);
    BAIL_ON_LW_TASK_ERROR(dwError);

    ret = krb5_init_context(&pCreds->ctx);
    BAIL_ON_KRB_ERROR(pCreds->ctx, ret);

    /* Generates a new filed based credentials cache in /tmp.
     * The file will be owned by root and only accessible by root.
     */
    ret = krb5_cc_new_unique(pCreds->ctx, "FILE", "hint", &pCreds->cc);
    BAIL_ON_KRB_ERROR(pCreds->ctx, ret);

    dwError = LwAllocateStringPrintf(
                    &pszNewCachePath,
                    "%s:%s",
                    krb5_cc_get_type(pCreds->ctx, pCreds->cc),
                    krb5_cc_get_name(pCreds->ctx, pCreds->cc));
    BAIL_ON_LW_TASK_ERROR(dwError);

    dwError = LwKrb5GetTgt(pszUsername, pszPassword, pszNewCachePath, NULL);
    BAIL_ON_LW_TASK_ERROR(dwError);

    dwError = LwKrb5SetDefaultCachePath(
                    pszNewCachePath,
                    &pCreds->pszRestoreCache);
    BAIL_ON_LW_TASK_ERROR(dwError);

    dwError = LwIoCreateKrb5CredsA(
                    pszUsername,
                    pszNewCachePath,
                    &pCreds->pKrb5Creds);
    BAIL_ON_LW_TASK_ERROR(dwError);

    *ppCreds = pCreds;

cleanup:

    LW_SAFE_FREE_STRING(pszNewCachePath);

    return dwError;

error:

    *ppCreds = NULL;

    if (pCreds)
    {
        LwTaskFreeCreds(pCreds);
    }

    goto cleanup;
}
Пример #10
0
OM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred (
     OM_uint32           *minor_status,
     const gss_cred_id_t input_cred_handle,
     const gss_name_t    desired_name,
     const gss_OID       desired_mech,
     gss_cred_usage_t    cred_usage,
     OM_uint32           initiator_time_req,
     OM_uint32           acceptor_time_req,
     gss_cred_id_t       *output_cred_handle,
     gss_OID_set         *actual_mechs,
     OM_uint32           *initiator_time_rec,
     OM_uint32           *acceptor_time_rec)
{
    krb5_context context;
    OM_uint32 ret, lifetime;
    gsskrb5_cred cred, handle;
    krb5_const_principal dname;

    handle = NULL;
    cred = (gsskrb5_cred)input_cred_handle;
    dname = (krb5_const_principal)desired_name;

    GSSAPI_KRB5_INIT (&context);

    if (gss_oid_equal(desired_mech, GSS_KRB5_MECHANISM) == 0) {
	*minor_status = 0;
	return GSS_S_BAD_MECH;
    }

    if (cred == NULL && output_cred_handle == NULL) {
	*minor_status = 0;
	return GSS_S_NO_CRED;
    }

    if (cred == NULL) { /* XXX standard conformance failure */
	*minor_status = 0;
	return GSS_S_NO_CRED;
    }

    /* check if requested output usage is compatible with output usage */
    if (output_cred_handle != NULL) {
	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);
	}
    }

    /* check that we have the same name */
    if (dname != NULL &&
	krb5_principal_compare(context, dname,
			       cred->principal) != FALSE) {
	if (output_cred_handle)
	    HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
	*minor_status = 0;
	return GSS_S_BAD_NAME;
    }

    /* make a copy */
    if (output_cred_handle) {
	krb5_error_code kret;

	handle = calloc(1, sizeof(*handle));
	if (handle == NULL) {
	    HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
	    *minor_status = ENOMEM;
	    return (GSS_S_FAILURE);
	}

	handle->usage = cred_usage;
	handle->endtime = cred->endtime;
	handle->principal = NULL;
	handle->keytab = NULL;
	handle->ccache = NULL;
	HEIMDAL_MUTEX_init(&handle->cred_id_mutex);

	kret = krb5_copy_principal(context, cred->principal,
				  &handle->principal);
	if (kret) {
	    HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
	    free(handle);
	    *minor_status = kret;
	    return GSS_S_FAILURE;
	}

	if (cred->keytab) {
	    char *name = NULL;

	    ret = GSS_S_FAILURE;

	    kret = krb5_kt_get_full_name(context, cred->keytab, &name);
	    if (kret) {
		*minor_status = kret;
		goto failure;
	    }

	    kret = krb5_kt_resolve(context, name,
				   &handle->keytab);
	    krb5_xfree(name);
	    if (kret){
		*minor_status = kret;
		goto failure;
	    }
	}

	if (cred->ccache) {
	    const char *type, *name;
	    char *type_name = NULL;

	    ret = GSS_S_FAILURE;

	    type = krb5_cc_get_type(context, cred->ccache);
	    if (type == NULL){
		*minor_status = ENOMEM;
		goto failure;
	    }

	    if (strcmp(type, "MEMORY") == 0) {
		ret = krb5_cc_new_unique(context, type,
					 NULL, &handle->ccache);
		if (ret) {
		    *minor_status = ret;
		    goto failure;
		}

		ret = krb5_cc_copy_cache(context, cred->ccache,
					 handle->ccache);
		if (ret) {
		    *minor_status = ret;
		    goto failure;
		}

	    } else {
		name = krb5_cc_get_name(context, cred->ccache);
		if (name == NULL) {
		    *minor_status = ENOMEM;
		    goto failure;
		}

		kret = asprintf(&type_name, "%s:%s", type, name);
		if (kret < 0 || type_name == NULL) {
		    *minor_status = ENOMEM;
		    goto failure;
		}

		kret = krb5_cc_resolve(context, type_name,
				       &handle->ccache);
		free(type_name);
		if (kret) {
		    *minor_status = kret;
		    goto failure;
		}
	    }
	}
    }

    HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);

    ret = _gsskrb5_inquire_cred(minor_status, (gss_cred_id_t)cred,
				NULL, &lifetime, NULL, actual_mechs);
    if (ret)
	goto failure;

    if (initiator_time_rec)
	*initiator_time_rec = lifetime;
    if (acceptor_time_rec)
	*acceptor_time_rec = lifetime;

    if (output_cred_handle) {
	*output_cred_handle = (gss_cred_id_t)handle;
    }

    *minor_status = 0;
    return ret;

 failure:

    if (handle) {
	if (handle->principal)
	    krb5_free_principal(context, handle->principal);
	if (handle->keytab)
	    krb5_kt_close(context, handle->keytab);
	if (handle->ccache)
	    krb5_cc_destroy(context, handle->ccache);
	free(handle);
    }
    if (output_cred_handle)
	HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
    return ret;
}
void Krb5CCache::getCacheTypeAndName(std::string& cacheType,
                                     std::string& cacheName) const {
  krb5_context ctx = context_.get();
  cacheType = std::string(krb5_cc_get_type(ctx, ccache_));
  cacheName = std::string(krb5_cc_get_name(ctx, ccache_));
}
Пример #12
0
int
main(int argc, char **argv)
{
    krb5_error_code ret;
    krb5_context context;
    krb5_ccache src_cc = NULL;
    krb5_ccache dst_cc = NULL;
    krb5_cc_cursor cursor;
    krb5_principal me = NULL;
    krb5_creds cred;
    const char *during;
    Ticket t;
    size_t len;
    int make_kvno_absent = 0;
    int opt;

    memset(&cred, 0, sizeof (cred));
    during = "init_context";
    ret = krb5_init_context(&context);
    if (ret) goto err;

    while ((opt = getopt(argc, argv, "c:n")) != -1) {
	switch (opt) {
	case 'c':
	    during = "cc_resolve of source ccache";
	    ret = krb5_cc_resolve(context, optarg, &src_cc);
	    if (ret) goto err;
	    break;
	case 'n':
	    make_kvno_absent++;
	    break;
	case 'h':
	default:
	    fprintf(stderr, "Usage: %s [-n] [-c ccache]\n"
		    "\tThis utility edits a ccache, setting all ticket\n"
		    "\tenc_part kvnos to zero or absent (if -n is set).\n",
		    argv[0]);
	    return 1;
	}
    }

    if (!src_cc) {
	during = "cc_default";
	ret = krb5_cc_default(context, &src_cc);
	if (ret) goto err;
    }

    during = "cc_get_principal";
    ret = krb5_cc_get_principal(context, src_cc, &me);
    if (ret) goto err;

    if (optind != argc) {
	fprintf(stderr, "Usage: %s [-n] [-c ccache]\n"
		"\tThis utility edits a ccache, setting all ticket\n"
		"\tenc_part kvnos to zero or absent (if -n is set).\n",
		argv[0]);
	return 1;
    }

    during = "cc_new_unique of temporary ccache";
    ret = krb5_cc_new_unique(context, krb5_cc_get_type(context, src_cc),
			     NULL, &dst_cc);

    during = "cc_initialize of temporary ccache";
    ret = krb5_cc_initialize(context, dst_cc, me);
    if (ret) goto err;

    during = "cc_start_seq_get";
    ret = krb5_cc_start_seq_get(context, src_cc, &cursor);
    if (ret) goto err;

    while ((ret = krb5_cc_next_cred(context, src_cc, &cursor, &cred)) == 0) {
	krb5_data data;

	during = "decode_Ticket";
	memset(&t, 0, sizeof (t));
	ret = decode_Ticket(cred.ticket.data, cred.ticket.length, &t, &len);
	if (ret == ASN1_MISSING_FIELD)
	    continue;
	if (ret) goto err;
	if (t.enc_part.kvno) {
	    *t.enc_part.kvno = 0;
	    if (make_kvno_absent) {
		free(t.enc_part.kvno);
		t.enc_part.kvno = NULL;
	    }
	    /*
	     * The new Ticket has to need less or same space as before, so
	     * we reuse cred->icket.data.
	     */
	    during = "encode_Ticket";
	    ASN1_MALLOC_ENCODE(Ticket, data.data, data.length, &t, &len, ret);
	    if (ret) {
		free_Ticket(&t);
		goto err;
	    }
	    krb5_data_free(&cred.ticket);
	    cred.ticket = data;
	}
	free_Ticket(&t);
	during = "cc_store_cred";
	ret = krb5_cc_store_cred(context, dst_cc, &cred);
	if (ret) goto err;
	krb5_free_cred_contents(context, &cred);
	memset(&cred, 0, sizeof (cred));
    }
    during = "cc_next_cred";
    if (ret != KRB5_CC_END) goto err;

    during = "cc_end_seq_get";
    ret = krb5_cc_end_seq_get(context, src_cc, &cursor);
    if (ret) goto err;

    during = "cc_move";
    ret = krb5_cc_move(context, dst_cc, src_cc);
    if (ret) goto err;
    dst_cc = NULL;

    during = "cc_switch";
    ret = krb5_cc_switch(context, src_cc);
    if (ret) goto err;

err:
    (void) krb5_free_principal(context, me);
    if (src_cc)
	(void) krb5_cc_close(context, src_cc);
    if (dst_cc)
	(void) krb5_cc_destroy(context, dst_cc);
    if (ret) {
	fprintf(stderr, "Failed while doing %s (%d)\n", during, ret);
	ret = 1;
    }
    return (ret);
}
Пример #13
0
/*
 * Output the ccache contents
 */
int do_ccache(krb5_ccache cache) {
	char		*ccname = NULL;
	krb5_creds	creds;
	krb5_cc_cursor	cursor;
	krb5_principal	princ = NULL;
	char		*princname = NULL;
	krb5_flags	flags = 0;
	krb5_error_code	retval;
	int		status = 1;

	asprintf(&ccname, "%s:%s",
		krb5_cc_get_type(ctx, cache),
		krb5_cc_get_name(ctx, cache));
	if (!ccname)
		goto cleanup;

	if (show_ccname_only && !show_collection) {
		// With just -N, always show the name...
		printf("%s\n", ccname);
		status = 0;
		goto cleanup;
	}

	retval = krb5_cc_set_flags(ctx, cache, flags);
	if (retval) {
		if (quiet_errors)
			;
		else if (retval == KRB5_FCC_NOFILE)
			com_err(progname, retval, "(ticket cache %s)", ccname);
		else
			com_err(progname, retval, "while setting cache flags (ticket cache %s)", ccname);
		goto cleanup;
	}

	retval = krb5_cc_get_principal(ctx, cache, &princ);
	if (retval) {
		if (quiet_errors)
			;
		else if (retval == KRB5_FCC_NOFILE)
			com_err(progname, retval, "(ticket cache %s)", ccname);
		else
			com_err(progname, retval, "while obtaining default principal (ticket cache %s)", ccname);
		goto cleanup;
	}

	if (show_nothing) {
		status = 0;
		goto cleanup;
	}

	retval = krb5_unparse_name(ctx, princ, &princname);
	if (retval)
		goto cleanup;

	if (show_ccname_only && show_collection) {
		// ...with -l -N, only show names pointing to valid ccaches.
		printf("%s\n", ccname);
		status = 0;
		goto cleanup;
	}

	if (show_defname_only) {
		printf("%s\n", princname);
		status = 0;
		goto cleanup;
	}

	if (!show_names_only) {
		if (show_collection == 1) {
			// only show the header
			printf("cache\t%s\t%s\n", ccname, princname);
			status = 0;
			goto cleanup;
		} else {
			// TODO: should the format be merged into the one above?
			// separate cache/principal kept for now, for compat reasons
			printf("cache\t%s\n", ccname);
			printf("principal\t%s\n", princname);
		}
		printf("CREDENTIALS\tclient_name\tserver_name\tstart_time\texpiry_time\trenew_time\tflags\tticket_data\n");
	}

	retval = krb5_cc_start_seq_get(ctx, cache, &cursor);
	if (retval) {
		com_err(progname, retval, "while starting to retrieve tickets");
		goto cleanup;
	}

	for (;;) {
		retval = krb5_cc_next_cred(ctx, cache, &cursor, &creds);
		if (retval)
			break;
		show_cred(&creds);
		krb5_free_cred_contents(ctx, &creds);
	}

	if (retval == KRB5_CC_END) {
		krb5_cc_end_seq_get(ctx, cache, &cursor);
		status = 0;
	} else {
		com_err(progname, retval, "while retrieving a ticket");
	}

cleanup:
	if (princ)
		krb5_free_principal(ctx, princ);
	if (princname)
		krb5_free_unparsed_name(ctx, princname);
	if (ccname)
		free(ccname);
	return status;
}
Пример #14
0
static krb5_error_code
renew_validate(krb5_context context,
	       int renew,
	       int validate,
	       krb5_ccache cache,
	       const char *server,
	       krb5_deltat life)
{
    krb5_error_code ret;
    krb5_ccache tempccache = NULL;
    krb5_creds in, *out = NULL;
    krb5_kdc_flags flags;

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

    ret = krb5_cc_get_principal(context, cache, &in.client);
    if (ret) {
	krb5_warn(context, ret, "krb5_cc_get_principal");
	return ret;
    }
    ret = get_server(context, in.client, server, &in.server);
    if (ret) {
	krb5_warn(context, ret, "get_server");
	goto out;
    }

    if (renew) {
	/*
	 * no need to check the error here, it's only to be
	 * friendly to the user
	 */
	krb5_get_credentials(context, KRB5_GC_CACHED, cache, &in, &out);
    }

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

    if (forwardable_flag != -1)
	flags.b.forwardable       = forwardable_flag;
    else if (out)
	flags.b.forwardable 	  = out->flags.b.forwardable;

    if (proxiable_flag != -1)
	flags.b.proxiable         = proxiable_flag;
    else if (out)
	flags.b.proxiable 	  = out->flags.b.proxiable;

    if (anonymous_flag)
	flags.b.request_anonymous = anonymous_flag;
    if (life)
	in.times.endtime = time(NULL) + life;

    if (out) {
	krb5_free_creds(context, out);
	out = NULL;
    }


    ret = krb5_get_kdc_cred(context,
			    cache,
			    flags,
			    NULL,
			    NULL,
			    &in,
			    &out);
    if (ret) {
	krb5_warn(context, ret, "krb5_get_kdc_cred");
	goto out;
    }

    ret = krb5_cc_new_unique(context, krb5_cc_get_type(context, cache),
			     NULL, &tempccache);
    if (ret) {
	krb5_warn(context, ret, "krb5_cc_new_unique");
	goto out;
    }

    ret = krb5_cc_initialize(context, tempccache, in.client);
    if (ret) {
	krb5_warn(context, ret, "krb5_cc_initialize");
	goto out;
    }

    ret = krb5_cc_store_cred(context, tempccache, out);
    if (ret) {
	krb5_warn(context, ret, "krb5_cc_store_cred");
	goto out;
    }

    /*
     * We want to preserve cc configs as some are security-relevant, and
     * anyways it's the friendly thing to do.
     */
    ret = copy_configs(context, tempccache, cache, out->server);
    if (ret)
	goto out;

    ret = krb5_cc_move(context, tempccache, cache);
    if (ret) {
	krb5_warn(context, ret, "krb5_cc_move");
	goto out;
    }
    tempccache = NULL;

out:
    if (tempccache)
	krb5_cc_close(context, tempccache);
    if (out)
	krb5_free_creds(context, out);
    krb5_free_cred_contents(context, &in);
    return ret;
}
Пример #15
0
static void
test_mcache(krb5_context context)
{
    krb5_error_code ret;
    krb5_ccache id, id2;
    const char *nc, *tc;
    char *n, *t, *c;
    krb5_principal p, p2;

    ret = krb5_parse_name(context, "*****@*****.**", &p);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    ret = krb5_cc_gen_new(context, &krb5_mcc_ops, &id);
    if (ret)
	krb5_err(context, 1, ret, "krb5_cc_gen_new");

    ret = krb5_cc_initialize(context, id, p);
    if (ret)
	krb5_err(context, 1, ret, "krb5_cc_initialize");

    nc = krb5_cc_get_name(context, id);
    if (nc == NULL)
	krb5_errx(context, 1, "krb5_cc_get_name");

    tc = krb5_cc_get_type(context, id);
    if (tc == NULL)
	krb5_errx(context, 1, "krb5_cc_get_name");

    n = estrdup(nc);
    t = estrdup(tc);

    asprintf(&c, "%s:%s", t, n);

    krb5_cc_close(context, id);

    ret = krb5_cc_resolve(context, c, &id2);
    if (ret)
	krb5_err(context, 1, ret, "krb5_cc_resolve");

    ret = krb5_cc_get_principal(context, id2, &p2);
    if (ret)
	krb5_err(context, 1, ret, "krb5_cc_get_principal");

    if (krb5_principal_compare(context, p, p2) == FALSE)
	krb5_errx(context, 1, "p != p2");

    krb5_cc_destroy(context, id2);
    krb5_free_principal(context, p);
    krb5_free_principal(context, p2);

    ret = krb5_cc_resolve(context, c, &id2);
    if (ret)
	krb5_err(context, 1, ret, "krb5_cc_resolve");

    ret = krb5_cc_get_principal(context, id2, &p2);
    if (ret == 0)
	krb5_errx(context, 1, "krb5_cc_get_principal");

    krb5_cc_destroy(context, id2);
}
Пример #16
0
static void
store_tickets(struct passwd *pwd, int ticket_newfiles, int ticket_store,
    int token_install)
{
	char cc_file[MAXPATHLEN];
	krb5_ccache ccache_store;
#ifdef KRB524
	int get_krb4_ticket = 0;
	char krb4_ticket_file[MAXPATHLEN];
#endif

	if (ticket_newfiles)
		snprintf(cc_file, sizeof(cc_file), "FILE:/tmp/krb5cc_%d",
		    pwd->pw_uid);
	else
		snprintf(cc_file, sizeof(cc_file), "%s",
		    krb5_cc_default_name(context));

	if (ticket_store) {
		ret = krb5_cc_resolve(context, cc_file, &ccache_store);
		if (ret != 0) {
			krb5_syslog(context, LOG_ERR, ret,
			    "krb5_cc_gen_new");
			exit(1);
		}

		ret = krb5_cc_copy_cache(context, ccache, ccache_store);
		if (ret != 0)
			krb5_syslog(context, LOG_ERR, ret,
			    "krb5_cc_copy_cache");

		chown(krb5_cc_get_name(context, ccache_store),
		    pwd->pw_uid, pwd->pw_gid);

		fprintf(back, BI_SETENV " KRB5CCNAME %s:%s\n",
		    krb5_cc_get_type(context, ccache_store),
		    krb5_cc_get_name(context, ccache_store));

#ifdef KRB524
		get_krb4_ticket = krb5_config_get_bool_default (context,
		    NULL, get_krb4_ticket, "libdefaults",
		    "krb4_get_tickets", NULL);
		if (get_krb4_ticket) {
			CREDENTIALS c;
			krb5_creds cred;
			krb5_cc_cursor cursor;

			ret = krb5_cc_start_seq_get(context, ccache, &cursor);
			if (ret != 0) {
				krb5_syslog(context, LOG_ERR, ret,
				    "start seq");
				exit(1);
			}

			ret = krb5_cc_next_cred(context, ccache,
			    &cursor, &cred);
			if (ret != 0) {
				krb5_syslog(context, LOG_ERR, ret,
				    "next cred");
				exit(1);
			}

			ret = krb5_cc_end_seq_get(context, ccache,
			    &cursor);
			if (ret != 0) {
				krb5_syslog(context, LOG_ERR, ret,
				    "end seq");
				exit(1);
			}

			ret = krb524_convert_creds_kdc_ccache(context, ccache,
			    &cred, &c);
			if (ret != 0) {
				krb5_syslog(context, LOG_ERR, ret,
				    "convert");
			} else {
				snprintf(krb4_ticket_file,
				    sizeof(krb4_ticket_file),
				    "%s%d", TKT_ROOT, pwd->pw_uid);
				krb_set_tkt_string(krb4_ticket_file);
				tf_setup(&c, c.pname, c.pinst);
				chown(krb4_ticket_file,
				    pwd->pw_uid, pwd->pw_gid);
			}
		}
#endif
	}

	/* Need to chown the ticket file */
#ifdef KRB524
	if (get_krb4_ticket)
		fprintf(back, BI_SETENV " KRBTKFILE %s\n",
		    krb4_ticket_file);
#endif
}
Пример #17
0
static void
print_tickets (krb5_context context,
	       krb5_ccache ccache,
	       krb5_principal principal,
	       int do_verbose,
	       int do_flags,
	       int do_hidden)
{
    krb5_error_code ret;
    char *str, *name;
    krb5_cc_cursor cursor;
    krb5_creds creds;
    krb5_deltat sec;

    rtbl_t ct = NULL;

    ret = krb5_unparse_name (context, principal, &str);
    if (ret)
	krb5_err (context, 1, ret, "krb5_unparse_name");

    printf ("%17s: %s:%s\n",
	    N_("Credentials cache", ""),
	    krb5_cc_get_type(context, ccache),
	    krb5_cc_get_name(context, ccache));
    printf ("%17s: %s\n", N_("Principal", ""), str);

    ret = krb5_cc_get_friendly_name(context, ccache, &name);
    if (ret == 0) {
	if (strcmp(name, str) != 0)
	    printf ("%17s: %s\n", N_("Friendly name", ""), name);
	free(name);
    }
    free (str);

    if(do_verbose) {
	printf ("%17s: %d\n", N_("Cache version", ""),
		krb5_cc_get_version(context, ccache));
    } else {
        krb5_cc_set_flags(context, ccache, KRB5_TC_NOTICKET);
    }

    ret = krb5_cc_get_kdc_offset(context, ccache, &sec);

    if (ret == 0 && do_verbose && sec != 0) {
	char buf[BUFSIZ];
	int val;
	int sig;

	val = sec;
	sig = 1;
	if (val < 0) {
	    sig = -1;
	    val = -val;
	}
	
	unparse_time (val, buf, sizeof(buf));

	printf ("%17s: %s%s\n", N_("KDC time offset", ""),
		sig == -1 ? "-" : "", buf);
    }

    printf("\n");

    ret = krb5_cc_start_seq_get (context, ccache, &cursor);
    if (ret)
	krb5_err(context, 1, ret, "krb5_cc_start_seq_get");

    if(!do_verbose) {
	ct = rtbl_create();
	rtbl_add_column(ct, COL_ISSUED, 0);
	rtbl_add_column(ct, COL_EXPIRES, 0);
	if(do_flags)
	    rtbl_add_column(ct, COL_FLAGS, 0);
	rtbl_add_column(ct, COL_PRINCIPAL, 0);
	rtbl_set_separator(ct, "  ");
    }
    while ((ret = krb5_cc_next_cred (context,
				     ccache,
				     &cursor,
				     &creds)) == 0) {
	if (!do_hidden && krb5_is_config_principal(context, creds.server)) {
	    ;
	}else if(do_verbose){
	    print_cred_verbose(context, &creds);
	}else{
	    print_cred(context, &creds, ct, do_flags);
	}
	krb5_free_cred_contents (context, &creds);
    }
    if(ret != KRB5_CC_END)
	krb5_err(context, 1, ret, "krb5_cc_get_next");
    ret = krb5_cc_end_seq_get (context, ccache, &cursor);
    if (ret)
	krb5_err (context, 1, ret, "krb5_cc_end_seq_get");
    if(!do_verbose) {
	rtbl_format(ct, stdout);
	rtbl_destroy(ct);
    }
}
Пример #18
0
static krb5_error_code
get_new_tickets(krb5_context context,
		krb5_principal principal,
		krb5_ccache ccache,
		krb5_deltat ticket_life,
		int interactive)
{
    krb5_error_code ret;
    krb5_get_init_creds_opt *opt;
    krb5_creds cred;
    char passwd[256];
    krb5_deltat start_time = 0;
    krb5_deltat renew = 0;
    const char *renewstr = NULL;
    krb5_enctype *enctype = NULL;
    krb5_ccache tempccache;
    krb5_init_creds_context icc;
    krb5_keytab kt = NULL;
    int will_use_keytab =  (use_keytab || keytab_str);
    krb5_prompter_fct prompter = NULL;
    int need_prompt;

    passwd[0] = '\0';

    if (password_file) {
	FILE *f;

	if (strcasecmp("STDIN", password_file) == 0)
	    f = stdin;
	else
	    f = fopen(password_file, "r");
	if (f == NULL)
	    krb5_errx(context, 1, "Failed to open the password file %s",
		      password_file);

	if (fgets(passwd, sizeof(passwd), f) == NULL)
	    krb5_errx(context, 1,
		      N_("Failed to read password from file %s", ""),
		      password_file);
	if (f != stdin)
	    fclose(f);
	passwd[strcspn(passwd, "\n")] = '\0';
    }

#if defined(__APPLE__) && !defined(__APPLE_TARGET_EMBEDDED__)
    if (passwd[0] == '\0' && !will_use_keytab && home_directory_flag) {
	const char *realm;
	OSStatus osret;
	UInt32 length;
	void *buffer;
	char *name;

	realm = krb5_principal_get_realm(context, principal);

	ret = krb5_unparse_name_flags(context, principal,
				      KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name);
	if (ret)
	    goto nopassword;

	osret = SecKeychainFindGenericPassword(NULL, (UInt32)strlen(realm), realm,
					       (UInt32)strlen(name), name,
					       &length, &buffer, &passwordItem);
	free(name);
	if (osret != noErr)
	    goto nopassword;

	if (length < sizeof(passwd) - 1) {
	    memcpy(passwd, buffer, length);
	    passwd[length] = '\0';
	}
	SecKeychainItemFreeContent(NULL, buffer);
    nopassword:
	do { } while(0);
    }
#endif

    need_prompt = !(pk_user_id || ent_user_id || anonymous_flag || will_use_keytab || passwd[0] != '\0') && interactive;
    if (need_prompt)
	prompter = krb5_prompter_posix;
    else
	prompter = krb5_prompter_print_only;

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

    ret = krb5_get_init_creds_opt_alloc (context, &opt);
    if (ret)
	krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc");

    krb5_get_init_creds_opt_set_default_flags(context, "kinit",
	krb5_principal_get_realm(context, principal), opt);

    if(forwardable_flag != -1)
	krb5_get_init_creds_opt_set_forwardable (opt, forwardable_flag);

    if(proxiable_flag != -1)
	krb5_get_init_creds_opt_set_proxiable (opt, proxiable_flag);
    if(anonymous_flag)
	krb5_get_init_creds_opt_set_anonymous (opt, anonymous_flag);
    if (pac_flag != -1)
	krb5_get_init_creds_opt_set_pac_request(context, opt,
						pac_flag ? TRUE : FALSE);
    if (canonicalize_flag)
	krb5_get_init_creds_opt_set_canonicalize(context, opt, TRUE);
    if (pk_enterprise_flag || enterprise_flag || canonicalize_flag || windows_flag)
	krb5_get_init_creds_opt_set_win2k(context, opt, TRUE);
    if (pk_user_id || ent_user_id || anonymous_flag) {
	ret = krb5_get_init_creds_opt_set_pkinit(context, opt,
						 principal,
						 pk_user_id,
						 pk_x509_anchors,
						 NULL,
						 NULL,
						 pk_use_enckey ? 2 : 0 |
						 anonymous_flag ? 4 : 0,
						 interactive ? krb5_prompter_posix : krb5_prompter_print_only,
						 NULL,
						 passwd);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_get_init_creds_opt_set_pkinit");
	if (ent_user_id)
	    krb5_get_init_creds_opt_set_pkinit_user_cert(context, opt, ent_user_id);
    }

    if (addrs_flag != -1)
	krb5_get_init_creds_opt_set_addressless(context, opt,
						addrs_flag ? FALSE : TRUE);

    if (renew_life == NULL && renewable_flag)
	renewstr = "1 month";
    if (renew_life)
	renewstr = renew_life;
    if (renewstr) {
	renew = parse_time (renewstr, "s");
	if (renew < 0)
	    errx (1, "unparsable time: %s", renewstr);

	krb5_get_init_creds_opt_set_renew_life (opt, renew);
    }

    if(ticket_life != 0)
	krb5_get_init_creds_opt_set_tkt_life (opt, ticket_life);

    if(start_str) {
	int tmp = parse_time (start_str, "s");
	if (tmp < 0)
	    errx (1, N_("unparsable time: %s", ""), start_str);

	start_time = tmp;
    }

    if(etype_str.num_strings) {
	int i;

	enctype = malloc(etype_str.num_strings * sizeof(*enctype));
	if(enctype == NULL)
	    errx(1, "out of memory");
	for(i = 0; i < etype_str.num_strings; i++) {
	    ret = krb5_string_to_enctype(context,
					 etype_str.strings[i],
					 &enctype[i]);
	    if(ret)
		krb5_err(context, 1, ret, "unrecognized enctype: %s",
			 etype_str.strings[i]);
	}
	krb5_get_init_creds_opt_set_etype_list(opt, enctype,
					       etype_str.num_strings);
    }

    ret = krb5_init_creds_init(context, principal,
			       prompter, NULL,
			       start_time, opt, &icc);
    if (ret)
	krb5_err (context, 1, ret, "krb5_init_creds_init");

    if (server_str) {
	ret = krb5_init_creds_set_service(context, icc, server_str);
	if (ret)
	    krb5_err (context, 1, ret, "krb5_init_creds_set_service");
    }

    if (kdc_hostname)
	krb5_init_creds_set_kdc_hostname(context, icc, kdc_hostname);

    if (fast_armor_cache_string) {
	krb5_ccache fastid;
	
	ret = krb5_cc_resolve(context, fast_armor_cache_string, &fastid);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_cc_resolve(FAST cache)");
	
	ret = krb5_init_creds_set_fast_ccache(context, icc, fastid);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_init_creds_set_fast_ccache");
    }

    if(will_use_keytab) {
	if(keytab_str)
	    ret = krb5_kt_resolve(context, keytab_str, &kt);
	else
	    ret = krb5_kt_default(context, &kt);
	if (ret)
	    krb5_err (context, 1, ret, "resolving keytab");

	ret = krb5_init_creds_set_keytab(context, icc, kt);
	if (ret)
	    krb5_err (context, 1, ret, "krb5_init_creds_set_keytab");
    }

    if (passwd[0] == '\0' && need_prompt) {
	char *p, *prompt;

	krb5_unparse_name(context, principal, &p);
	asprintf (&prompt, N_("%s's Password: "******""), p);
	free(p);

	if (UI_UTIL_read_pw_string(passwd, sizeof(passwd)-1, prompt, 0)){
	    memset(passwd, 0, sizeof(passwd));
	    errx(1, "failed to read password");
	}
	free (prompt);
    }

    if (passwd[0]) {
	ret = krb5_init_creds_set_password(context, icc, passwd);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_init_creds_set_password");
    }

    ret = krb5_init_creds_get(context, icc);

#ifdef __APPLE__
    /*
     * Save password in Keychain
     */
    if (ret == 0 && keychain_flag && passwordItem == NULL) {
	krb5_error_code ret2;
	const char *realm;
	char *name;

	realm = krb5_principal_get_realm(context, principal);
	ret2 = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name);
	if (ret2 == 0) {
	    (void)SecKeychainAddGenericPassword(NULL,
						(UInt32)strlen(realm), realm,
						(UInt32)strlen(name), name,
						(UInt32)strlen(passwd), passwd,
						NULL);
	    free(name);
	}
    }
#endif

    memset(passwd, 0, sizeof(passwd));

    switch(ret){
    case 0:
	break;
    case KRB5_LIBOS_PWDINTR: /* don't print anything if it was just C-c:ed */
	exit(1);
    case KRB5KRB_AP_ERR_BAD_INTEGRITY:
    case KRB5KRB_AP_ERR_MODIFIED:
    case KRB5KDC_ERR_PREAUTH_FAILED:
    case KRB5_GET_IN_TKT_LOOP:
#ifdef __APPLE__
	if (passwordItem)
	    SecKeychainItemDelete(passwordItem);
#endif
	krb5_errx(context, 1, N_("Password incorrect", ""));
    case KRB5KRB_AP_ERR_V4_REPLY:
	krb5_errx(context, 1, N_("Looks like a Kerberos 4 reply", ""));
    case KRB5KDC_ERR_KEY_EXPIRED:
	krb5_errx(context, 1, N_("Password expired", ""));
    default:
	krb5_err(context, 1, ret, "krb5_get_init_creds");
    }

    ret = krb5_init_creds_get_creds(context, icc, &cred);
    if (ret)
	krb5_err(context, 1, ret, "krb5_init_creds_get_creds");

    krb5_process_last_request(context, opt, icc);

    ret = krb5_cc_new_unique(context, krb5_cc_get_type(context, ccache),
			     NULL, &tempccache);
    if (ret)
	krb5_err (context, 1, ret, "krb5_cc_new_unique");

    ret = krb5_init_creds_store(context, icc, tempccache);
    if (ret)
	krb5_err(context, 1, ret, "krb5_init_creds_store");

    ret = krb5_init_creds_store_config(context, icc, tempccache);
    if (ret)
	krb5_warn(context, ret, "krb5_init_creds_store_config");

    ret = krb5_init_creds_warn_user(context, icc);
    if (ret)
	krb5_warn(context, ret, "krb5_init_creds_warn_user");

#ifdef __APPLE__
    /*
     * Set for this case, default to * so that all processes can use
     * this cache.
     */
    {
	heim_array_t bundleacl = heim_array_create();
	heim_string_t ace;

	if (bundle_acl_strings.num_strings > 0) {
	    int i;
	    for (i = 0; i < bundle_acl_strings.num_strings; i++) {
		ace = heim_string_create(bundle_acl_strings.strings[i]);
		heim_array_append_value(bundleacl, ace);
		heim_release(ace);
	    }
	} else {
	    ace = heim_string_create("*");
	    heim_array_append_value(bundleacl, ace);
	    heim_release(ace);
	}
	krb5_cc_set_acl(context, tempccache, "kHEIMAttrBundleIdentifierACL", bundleacl);
	heim_release(bundleacl);
    }
#endif

    ret = krb5_cc_move(context, tempccache, ccache);
    if (ret) {
	(void)krb5_cc_destroy(context, tempccache);
	krb5_err (context, 1, ret, "krb5_cc_move");
    }

    if (switch_cache_flags)
	krb5_cc_switch(context, ccache);

    if (ok_as_delegate_flag || windows_flag || use_referrals_flag) {
	unsigned char d = 0;
	krb5_data data;

	if (ok_as_delegate_flag || windows_flag)
	    d |= 1;
	if (use_referrals_flag || windows_flag)
	    d |= 2;

	data.length = 1;
	data.data = &d;

	krb5_cc_set_config(context, ccache, NULL, "realm-config", &data);
    }

    if (enctype)
	free(enctype);

    krb5_init_creds_free(context, icc);
    krb5_get_init_creds_opt_free(context, opt);

    if (kt)
	krb5_kt_close(context, kt);

#ifdef __APPLE__
    if (passwordItem)
	CFRelease(passwordItem);
#endif

    return 0;
}
Пример #19
0
static int
create_krb5_cred(krb5_context ctx, char *realm, char *user, char *password,
                 char *ktname, krb5_ccache *ccache, gss_cred_id_t *gsscred,
                 char **errmsg) {
    int rc = 0, len = 0;
    unsigned int minor_stat = 0, major_stat = 0;
    const char *errmsg_tmp = NULL;
    const char *cctype = NULL;
    char *cname = NULL;
    krb5_ccache defcc = NULL;
    krb5_creds creds;
    krb5_principal princ = NULL;
    krb5_keytab keytab = NULL;
    gss_key_value_element_desc elems[2];
    gss_key_value_set_desc store;
    gss_name_t sname = NULL;
    gss_buffer_desc pr_name;

    pr_name.value = NULL;
    pr_name.length = 0;

    store.count = 0;
    store.elements = elems;

    if (user == NULL || realm == NULL) return 1;
    len = strlen(realm);

    if (len == 0 || strlen(user) == 0) return 0;

    DEBUG("create_krb5_cred (ctx:%p, realm:%s, user:%s, password:%s, ktname: %s,"
        " ccache:%p, gsscred:%p)", ctx, realm, user, "****", ktname, ccache, gsscred);

    rc = krb5_cc_default(ctx, &defcc);
    if (rc != 0) goto end;

    cctype = krb5_cc_get_type(ctx, defcc);

    rc = krb5_cc_new_unique(ctx, cctype, NULL, ccache);
    if (rc != 0) goto end;

    rc = krb5_build_principal(ctx, &princ, len, realm, user, NULL);
    if (rc != 0) goto end;

    rc = krb5_cc_initialize(ctx, *ccache, princ);
    if (rc != 0) goto end;

    if (password != NULL && strlen(password) > 0) {
        rc = krb5_get_init_creds_password(ctx, &creds, princ, password,
                                          0, NULL, 0, NULL, NULL);
        if (rc != 0) goto end;

        rc = krb5_cc_store_cred(ctx, *ccache, &creds);
        if (rc != 0) goto end;

        rc = krb5_cc_get_full_name(ctx, *ccache, &cname);
        if (rc != 0) goto end;
        
        store.elements[store.count].key = "ccache";
        store.elements[store.count].value = cname;
        store.count++;
    }

    if (ktname != NULL && strlen(ktname) > 0) {
        rc = krb5_kt_resolve(ctx, ktname, &keytab);
        if (rc != 0) goto end;

        rc = krb5_get_init_creds_keytab(ctx, &creds, princ, keytab, 0, NULL, NULL);
        if (rc != 0) goto end;
        
        rc = krb5_cc_store_cred(ctx, *ccache, &creds);
        if (rc != 0) goto end;

        rc = krb5_cc_get_full_name(ctx, *ccache, &cname);
        if (rc != 0) goto end;

        store.elements[store.count].key = "client_keytab";
        store.elements[store.count].value = ktname;
        store.count++;

        store.elements[store.count].key = "ccache";
        store.elements[store.count].value = cname;
        store.count++;

        rc = krb5_unparse_name(ctx, princ, (char**)&pr_name.value);
        if (rc != 0) goto end;
        pr_name.length = strlen(pr_name.value);

        major_stat = gss_import_name(&minor_stat, &pr_name,
                                     GSS_KRB5_NT_PRINCIPAL_NAME, &sname);
        if (major_stat != 0) goto end;
    }

    // Does not work with GSS-SPENGO.
    //major_stat = gss_krb5_import_cred(&minor_stat, *ccache, princ, NULL, gsscred);
    major_stat = gss_acquire_cred_from(&minor_stat, sname, 0, GSS_C_NO_OID_SET,
                                       GSS_C_INITIATE, &store, gsscred,
                                       NULL, NULL);

end:
    if (keytab != NULL) krb5_kt_close(ctx, keytab);
    if (princ != NULL) krb5_free_principal(ctx, princ);
    if (defcc != NULL) krb5_cc_close(ctx, defcc);
    if (cname != NULL) free(cname);
    if (pr_name.value != NULL) krb5_free_unparsed_name(ctx, pr_name.value);
    if (sname != NULL) {
        major_stat = gss_release_name(&minor_stat, &sname);
    }

    if (rc != 0) {
        /* Create error message with the error code. */
        errmsg_tmp = krb5_get_error_message(ctx, rc);
        if (errmsg != NULL && errmsg_tmp != NULL) {
            len = strlen(errmsg_tmp) + 26;
            *errmsg = (char *)malloc(len);
            if (*errmsg == NULL) {
                krb5_free_error_message(ctx, errmsg_tmp);
                return -1;
            }
            snprintf(*errmsg, len,"%s. (KRB5_ERROR 0x%08x)", errmsg_tmp, rc);
        }
        krb5_free_error_message(ctx, errmsg_tmp);
    }
    if (major_stat != 0) return major_stat;
    return rc;
}
Пример #20
0
/*
  we can't use krb5_mk_req because w2k wants the service to be in a particular format
*/
static krb5_error_code ads_krb5_mk_req(krb5_context context, 
				       krb5_auth_context *auth_context, 
				       const krb5_flags ap_req_options,
				       const char *principal,
				       krb5_ccache ccache, 
				       krb5_data *outbuf, 
				       time_t *expire_time)
{
	krb5_error_code 	  retval;
	krb5_principal	  server;
	krb5_creds 		* credsp;
	krb5_creds 		  creds;
	krb5_data in_data;
	BOOL creds_ready = False;
	int i = 0, maxtries = 3;
	
	retval = smb_krb5_parse_name(context, principal, &server);
	if (retval) {
		DEBUG(1,("ads_krb5_mk_req: Failed to parse principal %s\n", principal));
		return retval;
	}
	
	/* obtain ticket & session key */
	ZERO_STRUCT(creds);
	if ((retval = krb5_copy_principal(context, server, &creds.server))) {
		DEBUG(1,("ads_krb5_mk_req: krb5_copy_principal failed (%s)\n", 
			 error_message(retval)));
		goto cleanup_princ;
	}
	
	if ((retval = krb5_cc_get_principal(context, ccache, &creds.client))) {
		/* This can commonly fail on smbd startup with no ticket in the cache.
		 * Report at higher level than 1. */
		DEBUG(3,("ads_krb5_mk_req: krb5_cc_get_principal failed (%s)\n", 
			 error_message(retval)));
		goto cleanup_creds;
	}

	while (!creds_ready && (i < maxtries)) {

		if ((retval = krb5_get_credentials(context, 0, ccache, 
						   &creds, &credsp))) {
			DEBUG(1,("ads_krb5_mk_req: krb5_get_credentials failed for %s (%s)\n",
				 principal, error_message(retval)));
			goto cleanup_creds;
		}

		/* cope with ticket being in the future due to clock skew */
		if ((unsigned)credsp->times.starttime > time(NULL)) {
			time_t t = time(NULL);
			int time_offset =(int)((unsigned)credsp->times.starttime-t);
			DEBUG(4,("ads_krb5_mk_req: Advancing clock by %d seconds to cope with clock skew\n", time_offset));
			krb5_set_real_time(context, t + time_offset + 1, 0);
		}

		if (!ads_cleanup_expired_creds(context, ccache, credsp)) {
			creds_ready = True;
		}

		i++;
	}

	DEBUG(10,("ads_krb5_mk_req: Ticket (%s) in ccache (%s:%s) is valid until: (%s - %u)\n",
		  principal, krb5_cc_get_type(context, ccache), krb5_cc_get_name(context, ccache),
		  http_timestring((unsigned)credsp->times.endtime), 
		  (unsigned)credsp->times.endtime));

	if (expire_time) {
		*expire_time = (time_t)credsp->times.endtime;
	}

	in_data.length = 0;
	retval = krb5_mk_req_extended(context, auth_context, ap_req_options, 
				      &in_data, credsp, outbuf);
	if (retval) {
		DEBUG(1,("ads_krb5_mk_req: krb5_mk_req_extended failed (%s)\n", 
			 error_message(retval)));
	}
	
	krb5_free_creds(context, credsp);

cleanup_creds:
	krb5_free_cred_contents(context, &creds);

cleanup_princ:
	krb5_free_principal(context, server);

	return retval;
}
Пример #21
0
/* Get initial credentials for authenticating to server.  Perform fallback from
 * kadmin/fqdn to kadmin/admin if svcname_in is NULL. */
static kadm5_ret_t
get_init_creds(kadm5_server_handle_t handle, krb5_principal client,
               enum init_type init_type, char *pass, krb5_ccache ccache_in,
               char *svcname_in, char *realm, krb5_principal *server_out)
{
    kadm5_ret_t code;
    krb5_ccache ccache = NULL;
    char svcname[BUFSIZ];

    *server_out = NULL;

    /* NULL svcname means use host-based. */
    if (svcname_in == NULL) {
        code = kadm5_get_admin_service_name(handle->context,
                                            handle->params.realm,
                                            svcname, sizeof(svcname));
        if (code)
            goto error;
    } else {
        strncpy(svcname, svcname_in, sizeof(svcname));
        svcname[sizeof(svcname)-1] = '\0';
    }

    /*
     * Acquire a service ticket for svcname@realm for client, using password
     * pass (which could be NULL), and create a ccache to store them in.  If
     * INIT_CREDS, use the ccache we were provided instead.
     */
    if (init_type == INIT_CREDS) {
        ccache = ccache_in;
        if (asprintf(&handle->cache_name, "%s:%s",
                     krb5_cc_get_type(handle->context, ccache),
                     krb5_cc_get_name(handle->context, ccache)) < 0) {
            handle->cache_name = NULL;
            code = ENOMEM;
            goto error;
        }
    } else {
        static int counter = 0;

        if (asprintf(&handle->cache_name, "MEMORY:kadm5_%u", counter++) < 0) {
            handle->cache_name = NULL;
            code = ENOMEM;
            goto error;
        }
        code = krb5_cc_resolve(handle->context, handle->cache_name,
                               &ccache);
        if (code)
            goto error;

        code = krb5_cc_initialize (handle->context, ccache, client);
        if (code)
            goto error;

        handle->destroy_cache = 1;
    }
    handle->lhandle->cache_name = handle->cache_name;

    code = gic_iter(handle, init_type, ccache, client, pass, svcname, realm,
                    server_out);
    if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
         || code == KRB5_CC_NOTFOUND) && svcname_in == NULL) {
        /* Retry with old host-independent service principal. */
        code = gic_iter(handle, init_type, ccache, client, pass,
                        KADM5_ADMIN_SERVICE, realm, server_out);
    }
    /* Improved error messages */
    if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) code = KADM5_BAD_PASSWORD;
    if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN)
        code = KADM5_SECURE_PRINC_MISSING;

error:
    if (ccache != NULL && init_type != INIT_CREDS)
        krb5_cc_close(handle->context, ccache);
    return code;
}
Пример #22
0
int
main(int argc, char **argv)
{
    int f;
    char tf[1024];
    char *p;

    char *path;
    char **args;
    unsigned int i;
    int optind = 0;

    setprogname(argv[0]);
    if(getarg(getargs, num_args, argc, argv, &optind))
	usage(1);
    if(help_flag)
	usage(0);
    if(version_flag) {
	print_version(NULL);
	exit(0);
    }

    argc -= optind;
    argv += optind;

#ifdef KRB5
    {
	krb5_error_code ret;
	krb5_context context;
	krb5_ccache id;
	const char *name;

	ret = krb5_init_context(&context);
	if (ret) /* XXX should this really call exit ? */
	    errx(1, "no kerberos 5 support");

	ret = krb5_cc_new_unique(context, typename_arg, NULL, &id);
	if (ret)
	    krb5_err(context, 1, ret, "Failed generating credential cache");

	name = krb5_cc_get_name(context, id);
	if (name == NULL)
	    krb5_errx(context, 1, "Generated credential cache have no name");

	snprintf(tf, sizeof(tf), "%s:%s", krb5_cc_get_type(context, id), name);

	ret = krb5_cc_close(context, id);
	if (ret)
	    krb5_err(context, 1, ret, "Failed closing credential cache");

	krb5_free_context(context);

	esetenv("KRB5CCNAME", tf, 1);
    }
#endif

    snprintf (tf, sizeof(tf), "%s_XXXXXX", TKT_ROOT);
    f = mkstemp (tf);
    if (f < 0)
	err(1, "mkstemp failed");
    close (f);
    unlink (tf);
    esetenv("KRBTKFILE", tf, 1);

    i = 0;

    args = (char **) malloc((argc + 10)*sizeof(char *));
    if (args == NULL)
	errx (1, "Out of memory allocating %lu bytes",
	      (unsigned long)((argc + 10)*sizeof(char *)));

    if(*argv == NULL) {
	path = getenv("SHELL");
	if(path == NULL){
	    struct passwd *pw = k_getpwuid(geteuid());
	    if (pw == NULL)
		errx(1, "no such user: %d", (int)geteuid());
	    path = strdup(pw->pw_shell);
	}
    } else {
	path = strdup(*argv++);
    }
    if (path == NULL)
	errx (1, "Out of memory copying path");

    p=strrchr(path, '/');
    if(p)
	args[i] = strdup(p+1);
    else
	args[i] = strdup(path);

    if (args[i++] == NULL)
	errx (1, "Out of memory copying arguments");

    while(*argv)
	args[i++] = *argv++;

    args[i++] = NULL;

    if(k_hasafs())
	k_setpag();

    unsetenv("PAGPID");
    execvp(path, args);
    if (errno == ENOENT || c_flag) {
	char **sh_args = malloc ((i + 2) * sizeof(char *));
	unsigned int j;

	if (sh_args == NULL)
	    errx (1, "Out of memory copying sh arguments");
	for (j = 1; j < i; ++j)
	    sh_args[j + 2] = args[j];
	sh_args[0] = "sh";
	sh_args[1] = "-c";
	sh_args[2] = path;
	execv ("/bin/sh", sh_args);
    }
    err (1, "execvp");
}
Пример #23
0
int
kswitch(struct kswitch_options *opt, int argc, char **argv)
{
    krb5_error_code ret;
    krb5_ccache id = NULL;

    if (opt->cache_string && opt->principal_string)
	krb5_errx(kcc_context, 1,
		  N_("Both --cache and --principal given, choose one", ""));

    if (opt->interactive_flag) {
	krb5_cc_cache_cursor cursor;
	krb5_ccache *ids = NULL;
	size_t i, len = 0;
	char *name;
	rtbl_t ct;

	ct = rtbl_create();

	rtbl_add_column_by_id(ct, 0, "#", 0);
	rtbl_add_column_by_id(ct, 1, "Principal", 0);
	rtbl_set_column_affix_by_id(ct, 1, "    ", "");
        rtbl_add_column_by_id(ct, 2, "Type", 0);
        rtbl_set_column_affix_by_id(ct, 2, "  ", "");

	ret = krb5_cc_cache_get_first(kcc_context, NULL, &cursor);
	if (ret)
	    krb5_err(kcc_context, 1, ret, "krb5_cc_cache_get_first");

	while (krb5_cc_cache_next(kcc_context, cursor, &id) == 0) {
	    krb5_principal p;
	    char num[10];

	    ret = krb5_cc_get_principal(kcc_context, id, &p);
	    if (ret)
		continue;

	    ret = krb5_unparse_name(kcc_context, p, &name);
	    krb5_free_principal(kcc_context, p);

	    snprintf(num, sizeof(num), "%d", (int)(len + 1));
	    rtbl_add_column_entry_by_id(ct, 0, num);
	    rtbl_add_column_entry_by_id(ct, 1, name);
            rtbl_add_column_entry_by_id(ct, 2, krb5_cc_get_type(kcc_context, id));
	    free(name);

	    ids = erealloc(ids, (len + 1) * sizeof(ids[0]));
	    ids[len] = id;
	    len++;
	}
	krb5_cc_cache_end_seq_get(kcc_context, cursor);

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

	name = readline("Select number: ");
	if (name) {
	    i = atoi(name);
	    if (i == 0)
		krb5_errx(kcc_context, 1, "Cache number '%s' is invalid", name);
	    if (i > len)
		krb5_errx(kcc_context, 1, "Cache number '%s' is too large", name);

	    id = ids[i - 1];
	    ids[i - 1] = NULL;
	} else
	    krb5_errx(kcc_context, 1, "No cache selected");
	for (i = 0; i < len; i++)
	    if (ids[i])
		krb5_cc_close(kcc_context, ids[i]);

    } else if (opt->principal_string) {
	krb5_principal p;

	ret = krb5_parse_name(kcc_context, opt->principal_string, &p);
	if (ret)
	    krb5_err(kcc_context, 1, ret, "krb5_parse_name: %s",
		     opt->principal_string);

	ret = krb5_cc_cache_match(kcc_context, p, &id);
	if (ret)
	    krb5_err(kcc_context, 1, ret,
		     N_("Did not find principal: %s", ""),
		     opt->principal_string);

	krb5_free_principal(kcc_context, p);

    } else if (opt->cache_string) {
	const krb5_cc_ops *ops;
	char *str;

	ops = krb5_cc_get_prefix_ops(kcc_context, opt->type_string);
	if (ops == NULL)
	    krb5_err(kcc_context, 1, 0, "krb5_cc_get_prefix_ops");

	asprintf(&str, "%s:%s", ops->prefix, opt->cache_string);
	if (str == NULL)
	    krb5_errx(kcc_context, 1, N_("out of memory", ""));

	ret = krb5_cc_resolve(kcc_context, str, &id);
	if (ret)
	    krb5_err(kcc_context, 1, ret, "krb5_cc_resolve: %s", str);

	free(str);
    } else {
	krb5_errx(kcc_context, 1, "missing option for kswitch");
    }

    ret = krb5_cc_switch(kcc_context, id);
    if (ret)
	krb5_err(kcc_context, 1, ret, "krb5_cc_switch");

    return 0;
}
Пример #24
0
DWORD
LsaSetSMBCreds(
    IN PCSTR pszUserPrincipalName,
    IN PCSTR pszPassword,
    IN BOOLEAN bSetDefaultCachePath,
    OUT PLSA_CREDS_FREE_INFO* ppFreeInfo
    )
{
    DWORD dwError = 0;
    krb5_error_code ret = 0;
    PSTR pszNewCachePath = NULL;
    PCSTR  pszCacheName = NULL;
    PCSTR  pszCacheType = NULL;
    krb5_context ctx = 0;
    krb5_ccache cc = 0;
    LW_PIO_CREDS pNewCreds = NULL;
    LW_PIO_CREDS pOldCreds = NULL;
    PLSA_CREDS_FREE_INFO pFreeInfo = NULL;
    PSTR pszOldCachePath = NULL;
    BOOLEAN bSwitchedPath = FALSE;

    BAIL_ON_INVALID_POINTER(ppFreeInfo);
    BAIL_ON_INVALID_STRING(pszUserPrincipalName);

    ret = krb5_init_context(&ctx);
    BAIL_ON_KRB_ERROR(ctx, ret);

    /* Generates a new filed based credentials cache in /tmp. The file will
     * be owned by root and only accessible by root.
     */
    ret = krb5_cc_new_unique(
            ctx,
            "FILE",
            "hint",
            &cc);
    BAIL_ON_KRB_ERROR(ctx, ret);

    pszCacheType = krb5_cc_get_type(ctx, cc);
    pszCacheName = krb5_cc_get_name(ctx, cc);
    dwError = LwAllocateStringPrintf(&pszNewCachePath, "%s:%s", pszCacheType, pszCacheName);
    BAIL_ON_LSA_ERROR(dwError);

    dwError = LwKrb5GetTgt(
                pszUserPrincipalName,
                pszPassword,
                pszNewCachePath,
                NULL);
    BAIL_ON_LSA_ERROR(dwError);

    if (bSetDefaultCachePath)
    {
        LSA_LOG_DEBUG("Switching default credentials path for new access token"); 
        dwError = LwKrb5SetThreadDefaultCachePath(
                  pszNewCachePath,
                  &pszOldCachePath);
        BAIL_ON_LSA_ERROR(dwError);
        bSwitchedPath = TRUE;
    }

    dwError = LwIoCreateKrb5CredsA(
        pszUserPrincipalName,
        pszNewCachePath,
        &pNewCreds);
    BAIL_ON_LSA_ERROR(dwError);

    dwError = LwAllocateMemory(sizeof(*pFreeInfo), (PVOID*)&pFreeInfo);
    BAIL_ON_LSA_ERROR(dwError);

    dwError = LwIoGetThreadCreds(&pOldCreds);
    BAIL_ON_LSA_ERROR(dwError);

    dwError = LwIoSetThreadCreds(pNewCreds);
    BAIL_ON_LSA_ERROR(dwError);

    pFreeInfo->ctx = ctx;
    pFreeInfo->cc = cc;
    pFreeInfo->pRestoreCreds = pOldCreds;
    pFreeInfo->pszRestoreCache = pszOldCachePath;
    pFreeInfo->bKrbCreds = TRUE;
    pOldCreds = NULL;

cleanup:
    *ppFreeInfo = pFreeInfo;
    if (pOldCreds != NULL)
    {
        LwIoDeleteCreds(pOldCreds);
    }

    if (pNewCreds != NULL)
    {
        LwIoDeleteCreds(pNewCreds);
    }
    LW_SAFE_FREE_STRING(pszNewCachePath);

    return dwError;

error:
    if (ctx != NULL)
    {
        if (cc != NULL)
        {
            krb5_cc_destroy(ctx, cc);
        }
        krb5_free_context(ctx);
    }

    if (pFreeInfo)
    {
        LwFreeMemory(pFreeInfo);
        pFreeInfo = NULL;
    }
    if (bSwitchedPath)
    {
        LwKrb5SetThreadDefaultCachePath(
                  pszOldCachePath,
                  NULL);
        LW_SAFE_FREE_STRING(pszOldCachePath);
    }

    goto cleanup;
}
Пример #25
0
std::string Krb5CCache::getName() {
  krb5_context ctx = context_.get();
  return std::string(krb5_cc_get_type(ctx, ccache_)) + ":" +
         std::string(krb5_cc_get_name(ctx, ccache_));
}
Пример #26
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;
}
Пример #27
0
int
main(int argc, char **argv)
{
    krb5_error_code ret;
    krb5_context context;
    krb5_ccache  ccache;
    krb5_principal principal = NULL;
    int optidx = 0;
    krb5_deltat ticket_life = 0;
#ifdef HAVE_SIGACTION
    struct sigaction sa;
#endif

    setprogname(argv[0]);

    setlocale(LC_ALL, "");
    bindtextdomain("heimdal_kuser", HEIMDAL_LOCALEDIR);
    textdomain("heimdal_kuser");

    ret = krb5_init_context(&context);
    if (ret == KRB5_CONFIG_BADFORMAT)
	errx(1, "krb5_init_context failed to parse configuration file");
    else if (ret)
	errx(1, "krb5_init_context failed: %d", ret);

    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;

    /*
     * Open the keytab now, we use the keytab to determine the principal's
     * realm when the requested principal has no realm.
     */
    if (use_keytab || keytab_str) {
	if (keytab_str)
	    ret = krb5_kt_resolve(context, keytab_str, &kt);
	else
	    ret = krb5_kt_default(context, &kt);
	if (ret)
	    krb5_err(context, 1, ret, "resolving keytab");
    }

    if (pk_enterprise_flag) {
	ret = krb5_pk_enterprise_cert(context, pk_user_id,
				      argv[0], &principal,
				      &ent_user_id);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_pk_enterprise_certs");

	pk_user_id = NULL;

    } else if (anonymous_flag) {

	ret = krb5_make_principal(context, &principal, argv[0],
				  KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME,
				  NULL);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_make_principal");
	krb5_principal_set_type(context, principal, KRB5_NT_WELLKNOWN);

    } else if (use_keytab || keytab_str) {
	get_princ_kt(context, &principal, argv[0]);
    } else {
	get_princ(context, &principal, argv[0]);
    }

    if (fcache_version)
	krb5_set_fcache_version(context, fcache_version);

    if (renewable_flag == -1)
	/* this seems somewhat pointless, but whatever */
	krb5_appdefault_boolean(context, "kinit",
				krb5_principal_get_realm(context, principal),
				"renewable", FALSE, &renewable_flag);
    if (do_afslog == -1)
	krb5_appdefault_boolean(context, "kinit",
				krb5_principal_get_realm(context, principal),
				"afslog", TRUE, &do_afslog);

    if (cred_cache)
	ret = krb5_cc_resolve(context, cred_cache, &ccache);
    else {
	if (argc > 1) {
	    char s[1024];
	    ret = krb5_cc_new_unique(context, NULL, NULL, &ccache);
	    if (ret)
		krb5_err(context, 1, ret, "creating cred cache");
	    snprintf(s, sizeof(s), "%s:%s",
		     krb5_cc_get_type(context, ccache),
		     krb5_cc_get_name(context, ccache));
	    setenv("KRB5CCNAME", s, 1);
	} else {
	    ret = krb5_cc_cache_match(context, principal, &ccache);
	    if (ret) {
		const char *type;
		ret = krb5_cc_default(context, &ccache);
		if (ret)
		    krb5_err(context, 1, ret,
			     N_("resolving credentials cache", ""));

		/*
		 * Check if the type support switching, and we do,
		 * then do that instead over overwriting the current
		 * default credential
		 */
		type = krb5_cc_get_type(context, ccache);
		if (krb5_cc_support_switch(context, type)) {
		    krb5_cc_close(context, ccache);
		    ret = get_switched_ccache(context, type, principal,
					      &ccache);
		}
	    }
	}
    }
    if (ret)
	krb5_err(context, 1, ret, N_("resolving credentials cache", ""));

#ifndef NO_AFS
    if (argc > 1 && k_hasafs())
	k_setpag();
#endif

    if (lifetime) {
	int tmp = parse_time(lifetime, "s");
	if (tmp < 0)
	    errx(1, N_("unparsable time: %s", ""), lifetime);

	ticket_life = tmp;
    }

    if (addrs_flag == 0 && extra_addresses.num_strings > 0)
	krb5_errx(context, 1,
		  N_("specifying both extra addresses and "
		     "no addresses makes no sense", ""));
    {
	int i;
	krb5_addresses addresses;
	memset(&addresses, 0, sizeof(addresses));
	for(i = 0; i < extra_addresses.num_strings; i++) {
	    ret = krb5_parse_address(context, extra_addresses.strings[i],
				     &addresses);
	    if (ret == 0) {
		krb5_add_extra_addresses(context, &addresses);
		krb5_free_addresses(context, &addresses);
	    }
	}
	free_getarg_strings(&extra_addresses);
    }

    if (renew_flag || validate_flag) {
	ret = renew_validate(context, renew_flag, validate_flag,
			     ccache, server_str, ticket_life);

#ifndef NO_AFS
	if (ret == 0 && server_str == NULL && do_afslog && k_hasafs())
	    krb5_afslog(context, ccache, NULL, NULL);
#endif

	exit(ret != 0);
    }

    ret = get_new_tickets(context, principal, ccache, ticket_life, 1);
    if (ret)
	exit(1);

#ifndef NO_AFS
    if (ret == 0 && server_str == NULL && do_afslog && k_hasafs())
	krb5_afslog(context, ccache, NULL, NULL);
#endif

    if (argc > 1) {
	struct renew_ctx ctx;
	time_t timeout;

	timeout = ticket_lifetime(context, ccache, principal,
				  server_str, NULL) / 2;

	ctx.context = context;
	ctx.ccache = ccache;
	ctx.principal = principal;
	ctx.ticket_life = ticket_life;
	ctx.timeout = timeout;

#ifdef HAVE_SIGACTION
	memset(&sa, 0, sizeof(sa));
	sigemptyset(&sa.sa_mask);
	sa.sa_handler = handle_siginfo;

	sigaction(SIGINFO, &sa, NULL);
#endif

	ret = simple_execvp_timed(argv[1], argv+1,
				  renew_func, &ctx, timeout);
#define EX_NOEXEC	126
#define EX_NOTFOUND	127
	if (ret == EX_NOEXEC)
	    krb5_warnx(context, N_("permission denied: %s", ""), argv[1]);
	else if (ret == EX_NOTFOUND)
	    krb5_warnx(context, N_("command not found: %s", ""), argv[1]);

	krb5_cc_destroy(context, ccache);
#ifndef NO_AFS
	if (k_hasafs())
	    k_unlog();
#endif
    } else {
	krb5_cc_close(context, ccache);
	ret = 0;
    }
    krb5_free_principal(context, principal);
    if (kt)
	krb5_kt_close(context, kt);
    krb5_free_context(context);
    return ret;
}
Пример #28
0
static void
cc_test(krb5_context context, const char *name, krb5_flags flags)
{
    krb5_ccache id, id2;
    krb5_creds creds;
    krb5_error_code kret;
    krb5_cc_cursor cursor;
    krb5_principal tmp;

    const char *c_name;
    char newcache[300];
    char *save_type;

    kret = init_test_cred(context);
    CHECK(kret, "init_creds");

    kret = krb5_cc_resolve(context, name, &id);
    CHECK(kret, "resolve");
    kret = krb5_cc_initialize(context, id, test_creds.client);
    CHECK(kret, "initialize");

    c_name = krb5_cc_get_name(context, id);
    CHECK_STR(c_name, "get_name");

    c_name = krb5_cc_get_type(context, id);
    CHECK_STR(c_name, "get_type");
    save_type=strdup(c_name);
    CHECK_STR(save_type, "copying type");

    kret = krb5_cc_store_cred(context, id, &test_creds);
    CHECK(kret, "store");

    kret = krb5_cc_get_principal(context, id, &tmp);
    CHECK(kret, "get_principal");

    CHECK_BOOL(krb5_realm_compare(context, tmp, test_creds.client) != TRUE,
               "realms do not match", "realm_compare");


    CHECK_BOOL(krb5_principal_compare(context, tmp, test_creds.client) != TRUE,
               "principals do not match", "principal_compare");

    krb5_free_principal(context, tmp);

    kret = krb5_cc_set_flags (context, id, flags);
    CHECK(kret, "set_flags");

    kret = krb5_cc_start_seq_get(context, id, &cursor);
    CHECK(kret, "start_seq_get");
    kret = 0;
    while (kret != KRB5_CC_END) {
        if(debug) printf("Calling next_cred\n");
        kret = krb5_cc_next_cred(context, id, &cursor, &creds);
        if(kret == KRB5_CC_END) {
            if(debug) printf("next_cred: ok at end\n");
        }
        else {
            CHECK(kret, "next_cred");
            krb5_free_cred_contents(context, &creds);
        }

    }
    kret = krb5_cc_end_seq_get(context, id, &cursor);
    CHECK(kret, "end_seq_get");

    kret = krb5_cc_close(context, id);
    CHECK(kret, "close");


    /* ------------------------------------------------- */
    kret = krb5_cc_resolve(context, name, &id);
    CHECK(kret, "resolve2");

    {
        /* Copy the cache test*/
        snprintf(newcache, sizeof(newcache), "%s.new", name);
        kret = krb5_cc_resolve(context, newcache, &id2);
        CHECK(kret, "resolve of new cache");

        /* This should fail as the new creds are not initialized */
        kret = krb5_cc_copy_creds(context, id, id2);
        CHECK_FAIL(KRB5_FCC_NOFILE, kret, "copy_creds");

        kret = krb5_cc_initialize(context, id2, test_creds.client);
        CHECK(kret, "initialize of id2");

        kret = krb5_cc_copy_creds(context, id, id2);
        CHECK(kret, "copy_creds");

        kret = krb5_cc_destroy(context, id2);
        CHECK(kret, "destroy new cache");
    }

    /* Destroy the first cache */
    kret = krb5_cc_destroy(context, id);
    CHECK(kret, "destroy");

    /* ----------------------------------------------------- */
    /* Tests the generate new code */
    kret = krb5_cc_new_unique(context, save_type,
                              NULL, &id2);
    CHECK(kret, "new_unique");

    kret = krb5_cc_initialize(context, id2, test_creds.client);
    CHECK(kret, "initialize");

    kret = krb5_cc_store_cred(context, id2, &test_creds);
    CHECK(kret, "store");

    kret = krb5_cc_destroy(context, id2);
    CHECK(kret, "destroy id2");

    free(save_type);
    free_test_cred(context);

}
Пример #29
0
static krb5_error_code
get_new_tickets(krb5_context context,
		krb5_principal principal,
		krb5_ccache ccache,
		krb5_deltat ticket_life,
		int interactive)
{
    krb5_error_code ret;
    krb5_creds cred;
    char passwd[256];
    krb5_deltat start_time = 0;
    krb5_deltat renew = 0;
    const char *renewstr = NULL;
    krb5_enctype *enctype = NULL;
    krb5_ccache tempccache = NULL;
    krb5_init_creds_context ctx = NULL;
    krb5_get_init_creds_opt *opt = NULL;
    krb5_prompter_fct prompter = krb5_prompter_posix;
#ifndef NO_NTLM
    struct ntlm_buf ntlmkey;
    memset(&ntlmkey, 0, sizeof(ntlmkey));
#endif
    passwd[0] = '\0';

    if (!interactive)
	prompter = NULL;

    if (password_file) {
	FILE *f;

	if (strcasecmp("STDIN", password_file) == 0)
	    f = stdin;
	else
	    f = fopen(password_file, "r");
	if (f == NULL) {
	    krb5_warnx(context, "Failed to open the password file %s",
		       password_file);
	    return errno;
	}

	if (fgets(passwd, sizeof(passwd), f) == NULL) {
	    krb5_warnx(context, N_("Failed to read password from file %s", ""),
		       password_file);
	    fclose(f);
	    return EINVAL; /* XXX Need a better error */
	}
	if (f != stdin)
	    fclose(f);
	passwd[strcspn(passwd, "\n")] = '\0';
    }

#ifdef __APPLE__
    if (passwd[0] == '\0') {
	const char *realm;
	OSStatus osret;
	UInt32 length;
	void *buffer;
	char *name;

	realm = krb5_principal_get_realm(context, principal);

	ret = krb5_unparse_name_flags(context, principal,
				      KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name);
	if (ret)
	    goto nopassword;

	osret = SecKeychainFindGenericPassword(NULL, strlen(realm), realm,
					       strlen(name), name,
					       &length, &buffer, NULL);
	free(name);
	if (osret == noErr && length < sizeof(passwd) - 1) {
	    memcpy(passwd, buffer, length);
	    passwd[length] = '\0';
	}
    nopassword:
	do { } while(0);
    }
#endif

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

    ret = krb5_get_init_creds_opt_alloc(context, &opt);
    if (ret) {
	krb5_warn(context, ret, "krb5_get_init_creds_opt_alloc");
	goto out;
    }

    krb5_get_init_creds_opt_set_default_flags(context, "kinit",
	krb5_principal_get_realm(context, principal), opt);

    if (forwardable_flag != -1)
	krb5_get_init_creds_opt_set_forwardable(opt, forwardable_flag);
    if (proxiable_flag != -1)
	krb5_get_init_creds_opt_set_proxiable(opt, proxiable_flag);
    if (anonymous_flag)
	krb5_get_init_creds_opt_set_anonymous(opt, anonymous_flag);
    if (pac_flag != -1)
	krb5_get_init_creds_opt_set_pac_request(context, opt,
						pac_flag ? TRUE : FALSE);
    if (canonicalize_flag)
	krb5_get_init_creds_opt_set_canonicalize(context, opt, TRUE);
    if (pk_enterprise_flag || enterprise_flag || canonicalize_flag || windows_flag)
	krb5_get_init_creds_opt_set_win2k(context, opt, TRUE);
    if (pk_user_id || ent_user_id || anonymous_flag) {
	ret = krb5_get_init_creds_opt_set_pkinit(context, opt,
						 principal,
						 pk_user_id,
						 pk_x509_anchors,
						 NULL,
						 NULL,
						 pk_use_enckey ? 2 : 0 |
						 anonymous_flag ? 4 : 0,
						 prompter,
						 NULL,
						 passwd);
	if (ret) {
	    krb5_warn(context, ret, "krb5_get_init_creds_opt_set_pkinit");
	    goto out;
	}
	if (ent_user_id)
	    krb5_get_init_creds_opt_set_pkinit_user_certs(context, opt, ent_user_id);
    }

    if (addrs_flag != -1)
	krb5_get_init_creds_opt_set_addressless(context, opt,
						addrs_flag ? FALSE : TRUE);

    if (renew_life == NULL && renewable_flag)
	renewstr = "1 month";
    if (renew_life)
	renewstr = renew_life;
    if (renewstr) {
	renew = parse_time(renewstr, "s");
	if (renew < 0)
	    errx(1, "unparsable time: %s", renewstr);

	krb5_get_init_creds_opt_set_renew_life(opt, renew);
    }

    if (ticket_life != 0)
	krb5_get_init_creds_opt_set_tkt_life(opt, ticket_life);

    if (start_str) {
	int tmp = parse_time(start_str, "s");
	if (tmp < 0)
	    errx(1, N_("unparsable time: %s", ""), start_str);

	start_time = tmp;
    }

    if (etype_str.num_strings) {
	int i;

	enctype = malloc(etype_str.num_strings * sizeof(*enctype));
	if (enctype == NULL)
	    errx(1, "out of memory");
	for(i = 0; i < etype_str.num_strings; i++) {
	    ret = krb5_string_to_enctype(context,
					 etype_str.strings[i],
					 &enctype[i]);
	    if (ret)
		errx(1, "unrecognized enctype: %s", etype_str.strings[i]);
	}
	krb5_get_init_creds_opt_set_etype_list(opt, enctype,
					       etype_str.num_strings);
    }

    ret = krb5_init_creds_init(context, principal, prompter, NULL, start_time, opt, &ctx);
    if (ret) {
	krb5_warn(context, ret, "krb5_init_creds_init");
	goto out;
    }

    if (server_str) {
	ret = krb5_init_creds_set_service(context, ctx, server_str);
	if (ret) {
	    krb5_warn(context, ret, "krb5_init_creds_set_service");
	    goto out;
	}
    }

    if (fast_armor_cache_string) {
	krb5_ccache fastid;
	
	ret = krb5_cc_resolve(context, fast_armor_cache_string, &fastid);
	if (ret) {
	    krb5_warn(context, ret, "krb5_cc_resolve(FAST cache)");
	    goto out;
	}
	
	ret = krb5_init_creds_set_fast_ccache(context, ctx, fastid);
	if (ret) {
	    krb5_warn(context, ret, "krb5_init_creds_set_fast_ccache");
	    goto out;
	}
    }

    if (use_keytab || keytab_str) {
	ret = krb5_init_creds_set_keytab(context, ctx, kt);
	if (ret) {
	    krb5_warn(context, ret, "krb5_init_creds_set_keytab");
	    goto out;
	}
    } else if (pk_user_id || ent_user_id || anonymous_flag) {

    } else if (!interactive && passwd[0] == '\0') {
	static int already_warned = 0;

	if (!already_warned)
	    krb5_warnx(context, "Not interactive, failed to get "
	      "initial ticket");
	krb5_get_init_creds_opt_free(context, opt);
	already_warned = 1;
	return 0;
    } else {

	if (passwd[0] == '\0') {
	    char *p, *prompt;
	    int aret = 0;

	    ret = krb5_unparse_name(context, principal, &p);
	    if (ret)
		errx(1, "failed to generate passwd prompt: not enough memory");

	    aret = asprintf(&prompt, N_("%s's Password: "******""), p);
	    free(p);
	    if (aret == -1)
		errx(1, "failed to generate passwd prompt: not enough memory");

	    if (UI_UTIL_read_pw_string(passwd, sizeof(passwd)-1, prompt, 0)){
		memset(passwd, 0, sizeof(passwd));
		errx(1, "failed to read password");
	    }
	    free(prompt);
	}

	if (passwd[0]) {
	    ret = krb5_init_creds_set_password(context, ctx, passwd);
	    if (ret) {
		krb5_warn(context, ret, "krb5_init_creds_set_password");
		goto out;
	    }
	}
    }

    ret = krb5_init_creds_get(context, ctx);

#ifndef NO_NTLM
    if (ntlm_domain && passwd[0])
	heim_ntlm_nt_key(passwd, &ntlmkey);
#endif
    memset(passwd, 0, sizeof(passwd));

    switch(ret){
    case 0:
	break;
    case KRB5_LIBOS_PWDINTR: /* don't print anything if it was just C-c:ed */
	exit(1);
    case KRB5KRB_AP_ERR_BAD_INTEGRITY:
    case KRB5KRB_AP_ERR_MODIFIED:
    case KRB5KDC_ERR_PREAUTH_FAILED:
    case KRB5_GET_IN_TKT_LOOP:
	krb5_warnx(context, N_("Password incorrect", ""));
	goto out;
    case KRB5KRB_AP_ERR_V4_REPLY:
	krb5_warnx(context, N_("Looks like a Kerberos 4 reply", ""));
	goto out;
    case KRB5KDC_ERR_KEY_EXPIRED:
	krb5_warnx(context, N_("Password expired", ""));
	goto out;
    default:
	krb5_warn(context, ret, "krb5_get_init_creds");
	goto out;
    }

    krb5_process_last_request(context, opt, ctx);

    ret = krb5_init_creds_get_creds(context, ctx, &cred);
    if (ret) {
	krb5_warn(context, ret, "krb5_init_creds_get_creds");
	goto out;
    }

    if (ticket_life != 0) {
	if (abs(cred.times.endtime - cred.times.starttime - ticket_life) > 30) {
	    char life[64];
	    unparse_time_approx(cred.times.endtime - cred.times.starttime,
				life, sizeof(life));
	    krb5_warnx(context, N_("NOTICE: ticket lifetime is %s", ""), life);
	}
    }
    if (renew_life) {
	if (abs(cred.times.renew_till - cred.times.starttime - renew) > 30) {
	    char life[64];
	    unparse_time_approx(cred.times.renew_till - cred.times.starttime,
				life, sizeof(life));
	    krb5_warnx(context,
		       N_("NOTICE: ticket renewable lifetime is %s", ""),
		       life);
	}
    }
    krb5_free_cred_contents(context, &cred);

    ret = krb5_cc_new_unique(context, krb5_cc_get_type(context, ccache),
			     NULL, &tempccache);
    if (ret) {
	krb5_warn(context, ret, "krb5_cc_new_unique");
	goto out;
    }

    ret = krb5_init_creds_store(context, ctx, tempccache);
    if (ret) {
	krb5_warn(context, ret, "krb5_init_creds_store");
	goto out;
    }

    krb5_init_creds_free(context, ctx);
    ctx = NULL;

    ret = krb5_cc_move(context, tempccache, ccache);
    if (ret) {
	krb5_warn(context, ret, "krb5_cc_move");
	goto out;
    }
    tempccache = NULL;

    if (switch_cache_flags)
	krb5_cc_switch(context, ccache);

#ifndef NO_NTLM
    if (ntlm_domain && ntlmkey.data)
	store_ntlmkey(context, ccache, ntlm_domain, &ntlmkey);
#endif

    if (ok_as_delegate_flag || windows_flag || use_referrals_flag) {
	unsigned char d = 0;
	krb5_data data;

	if (ok_as_delegate_flag || windows_flag)
	    d |= 1;
	if (use_referrals_flag || windows_flag)
	    d |= 2;

	data.length = 1;
	data.data = &d;

	krb5_cc_set_config(context, ccache, NULL, "realm-config", &data);
    }

out:
    krb5_get_init_creds_opt_free(context, opt);
    if (ctx)
	krb5_init_creds_free(context, ctx);
    if (tempccache)
	krb5_cc_close(context, tempccache);

    if (enctype)
	free(enctype);

    return ret;
}
Пример #30
0
int
main(int argc, char **argv)
{
    krb5_ccache ccinitial, ccu1, ccu2;
    krb5_principal princ1, princ2, princ3;
    const char *collection_name, *typename;
    char *initial_primary_name, *unique1_name, *unique2_name;

    /*
     * Get the collection name from the command line.  This is a ccache name
     * with collection semantics, like DIR:/path/to/directory.  This test
     * program assumes that the collection is empty to start with.
     */
    assert(argc == 2);
    collection_name = argv[1];

    /*
     * Set the default ccache for the context to be the collection name, so the
     * library can find the collection.
     */
    check(krb5_init_context(&ctx));
    check(krb5_cc_set_default_name(ctx, collection_name));

    /*
     * Resolve the collection name.  Since the collection is empty, this should
     * generate a subsidiary name of an uninitialized cache.  Getting the name
     * of the resulting cache should give us the subsidiary name, not the
     * collection name.  This resulting subsidiary name should be consistent if
     * we resolve the collection name again, and the collection should still be
     * empty since we haven't initialized the cache.
     */
    check(krb5_cc_resolve(ctx, collection_name, &ccinitial));
    check(krb5_cc_get_full_name(ctx, ccinitial, &initial_primary_name));
    assert(strcmp(initial_primary_name, collection_name) != 0);
    check_primary_name(collection_name, initial_primary_name);
    check_collection(NULL, 0);
    check_princ(collection_name, NULL);
    check_princ(initial_primary_name, NULL);

    /*
     * Before initializing the primary ccache, generate and initialize two
     * unique caches of the collection's type.  Check that the cache names
     * resolve to the generated caches and appear in the collection.  (They
     * might appear before being initialized; that's not currently considered
     * important).  The primary cache for the collection should remain as the
     * unitialized cache from the previous step.
     */
    typename = krb5_cc_get_type(ctx, ccinitial);
    check(krb5_cc_new_unique(ctx, typename, NULL, &ccu1));
    check(krb5_cc_get_full_name(ctx, ccu1, &unique1_name));
    check(krb5_parse_name(ctx, "princ1@X", &princ1));
    check(krb5_cc_initialize(ctx, ccu1, princ1));
    check_princ(unique1_name, princ1);
    check_match(princ1, unique1_name);
    check_collection(NULL, 1, unique1_name);
    check(krb5_cc_new_unique(ctx, typename, NULL, &ccu2));
    check(krb5_cc_get_full_name(ctx, ccu2, &unique2_name));
    check(krb5_parse_name(ctx, "princ2@X", &princ2));
    check(krb5_cc_initialize(ctx, ccu2, princ2));
    check_princ(unique2_name, princ2);
    check_match(princ1, unique1_name);
    check_match(princ2, unique2_name);
    check_collection(NULL, 2, unique1_name, unique2_name);
    assert(strcmp(unique1_name, initial_primary_name) != 0);
    assert(strcmp(unique1_name, collection_name) != 0);
    assert(strcmp(unique2_name, initial_primary_name) != 0);
    assert(strcmp(unique2_name, collection_name) != 0);
    assert(strcmp(unique2_name, unique1_name) != 0);
    check_primary_name(collection_name, initial_primary_name);

    /*
     * Initialize the initial primary cache.  Make sure it didn't change names,
     * that the previously retrieved name and the collection name both resolve
     * to the initialized cache, and that it now appears first in the
     * collection.
     */
    check(krb5_parse_name(ctx, "princ3@X", &princ3));
    check(krb5_cc_initialize(ctx, ccinitial, princ3));
    check_name(ccinitial, initial_primary_name);
    check_princ(initial_primary_name, princ3);
    check_princ(collection_name, princ3);
    check_match(princ3, initial_primary_name);
    check_collection(initial_primary_name, 2, unique1_name, unique2_name);

    /*
     * Switch the primary cache to each cache we have open.  One each switch,
     * check the primary name, check that the collection resolves to the
     * expected cache, and check that the new primary name appears first in the
     * collection.
     */
    check(krb5_cc_switch(ctx, ccu1));
    check_primary_name(collection_name, unique1_name);
    check_princ(collection_name, princ1);
    check_collection(unique1_name, 2, initial_primary_name, unique2_name);
    check(krb5_cc_switch(ctx, ccu2));
    check_primary_name(collection_name, unique2_name);
    check_princ(collection_name, princ2);
    check_collection(unique2_name, 2, initial_primary_name, unique1_name);
    check(krb5_cc_switch(ctx, ccinitial));
    check_primary_name(collection_name, initial_primary_name);
    check_princ(collection_name, princ3);
    check_collection(initial_primary_name, 2, unique1_name, unique2_name);

    /*
     * Temporarily set the context default ccache to a subsidiary name, and
     * check that iterating over the collection yields that subsidiary cache
     * and no others.
     */
    check(krb5_cc_set_default_name(ctx, unique1_name));
    check_collection(unique1_name, 0);
    check(krb5_cc_set_default_name(ctx, collection_name));

    /*
     * Destroy the primary cache.  Make sure this causes both the initial
     * primary name and the collection name to resolve to an uninitialized
     * cache.  Make sure the primary name doesn't change and doesn't appear in
     * the collection any more.
     */
    check(krb5_cc_destroy(ctx, ccinitial));
    check_princ(initial_primary_name, NULL);
    check_princ(collection_name, NULL);
    check_primary_name(collection_name, initial_primary_name);
    check_match(princ1, unique1_name);
    check_match(princ2, unique2_name);
    check_match(princ3, NULL);
    check_collection(NULL, 2, unique1_name, unique2_name);

    /*
     * Switch to the first unique cache after destroying the primary cache.
     * Check that the collection name resolves to this cache and that the new
     * primary name appears first in the collection.
     */
    check(krb5_cc_switch(ctx, ccu1));
    check_primary_name(collection_name, unique1_name);
    check_princ(collection_name, princ1);
    check_collection(unique1_name, 1, unique2_name);

    /*
     * Destroy the second unique cache (which is not the current primary),
     * check that it is on longer initialized, and check that it no longer
     * appears in the collection.  Check that destroying the non-primary cache
     * doesn't affect the primary name.
     */
    check(krb5_cc_destroy(ctx, ccu2));
    check_princ(unique2_name, NULL);
    check_match(princ2, NULL);
    check_collection(unique1_name, 0);
    check_primary_name(collection_name, unique1_name);
    check_match(princ1, unique1_name);
    check_princ(collection_name, princ1);

    /*
     * Destroy the first unique cache.  Check that the collection is empty and
     * still has the same primary name.
     */
    check(krb5_cc_destroy(ctx, ccu1));
    check_princ(unique1_name, NULL);
    check_princ(collection_name, NULL);
    check_primary_name(collection_name, unique1_name);
    check_match(princ1, NULL);
    check_collection(NULL, 0);

    krb5_free_string(ctx, initial_primary_name);
    krb5_free_string(ctx, unique1_name);
    krb5_free_string(ctx, unique2_name);
    krb5_free_principal(ctx, princ1);
    krb5_free_principal(ctx, princ2);
    krb5_free_principal(ctx, princ3);
    krb5_free_context(ctx);
    return 0;
}