From: Greg Hudson Date: Mon, 5 Sep 2011 16:26:48 +0000 (+0000) Subject: Add ccache collection support to tools X-Git-Tag: krb5-1.10-alpha1~218 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=916555623ea3c0cd8976718f0b989280df9260ce;p=krb5.git Add ccache collection support to tools * "kdestroy -A" destroys all caches in collection. * "kinit princ" searches the collection for a matching cache and overwrites it, or creates a new cache in the collection, if the type of the default cache is collection-enabled. The chosen cache also becomes the primary cache for the collection. * "klist -l" lists (in summary form) the caches in the collection. * "klist -A" lists the content of all of the caches in the collection. * "kswitch -c cache" (new command) makes cache the primary cache. * "kswitch -p princ" makes the cache for princ the primary cache. ticket: 6956 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25157 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/doc/rst_source/conf.py b/doc/rst_source/conf.py index 6ea2c6d33..abc63e9ce 100644 --- a/doc/rst_source/conf.py +++ b/doc/rst_source/conf.py @@ -221,6 +221,7 @@ man_pages = [ ('krb_users/user_commands/kinit', 'kinit', u'obtain and cache Kerberos ticket-granting ticket', [u'MIT'], 1), ('krb_users/user_commands/klist', 'klist', u'list cached Kerberos tickets', [u'MIT'], 1), ('krb_users/user_commands/kdestroy', 'kdestroy', u'destroy Kerberos tickets', [u'MIT'], 1), + ('krb_users/user_commands/kswitch', 'kswitch', u'switch primary ticket cache', [u'MIT'], 1), ('krb_users/user_commands/kpasswd', 'kpasswd', u'change a user\'s Kerberos password', [u'MIT'], 1), ('krb_users/user_commands/kvno', 'kvno', u'print key version numbers of Kerberos principals', [u'MIT'], 1), ('krb_users/user_commands/ksu', 'ksu', u'Kerberized super-user', [u'MIT'], 1), diff --git a/doc/rst_source/krb_users/user_commands/index.rst b/doc/rst_source/krb_users/user_commands/index.rst index 5232eb818..4c68c0899 100644 --- a/doc/rst_source/krb_users/user_commands/index.rst +++ b/doc/rst_source/krb_users/user_commands/index.rst @@ -10,6 +10,7 @@ User commands kinit.rst klist.rst kdestroy.rst + kswitch.rst kpasswd.rst kvno.rst ksu.rst diff --git a/doc/rst_source/krb_users/user_commands/kdestroy.rst b/doc/rst_source/krb_users/user_commands/kdestroy.rst index 78a3014a9..b86137afe 100644 --- a/doc/rst_source/krb_users/user_commands/kdestroy.rst +++ b/doc/rst_source/krb_users/user_commands/kdestroy.rst @@ -5,6 +5,7 @@ SYNOPSIS ~~~~~~~~~~~~~ *kdestroy* + [**-A**] [**-q**] [**-c** *cache_name*] @@ -21,6 +22,10 @@ cache is not specified, the default credentials cache is destroyed. OPTIONS ~~~~~~~~~~~~~ + **-A** + Destroys all caches in the collection, if a cache collection is + available. + **-q** Run quietly. Normally *kdestroy* beeps if it fails to destroy the user's tickets. The *-q* flag suppresses this behavior. @@ -45,7 +50,14 @@ ENVIRONMENT *kdestroy* uses the following environment variables: - **KRB5CCNAME** - Location of the Kerberos 5 credentials (ticket) cache. + **KRB5CCNAME** + Location of the default Kerberos 5 credentials (ticket) + cache, in the form *type*:*residual*. If no type prefix is + present, the **FILE** type is assumed. The type of the + default cache may determine the availability of a cache + collection; for instance, a default cache of type **DIR** + causes caches within the directory to be present in the + collection. FILES diff --git a/doc/rst_source/krb_users/user_commands/kinit.rst b/doc/rst_source/krb_users/user_commands/kinit.rst index 3e816d352..49a256470 100644 --- a/doc/rst_source/krb_users/user_commands/kinit.rst +++ b/doc/rst_source/krb_users/user_commands/kinit.rst @@ -129,8 +129,15 @@ OPTIONS use *cache_name* as the Kerberos 5 credentials (ticket) cache name and location; if this option is not used, the default cache name and location are used. - The default credentials cache may vary between systems. If the **KRB5CCNAME** environment variable is set, its - value is used to name the default ticket cache. Any existing contents of the cache are destroyed by kinit. + The default credentials cache may vary between systems. If + the **KRB5CCNAME** environment variable is set, its value is + used to name the default ticket cache. If a principal name + is specified and the type of the default credentials cache + supports a collection (such as the DIR type), an existing + cache containing credentials for the principal is selected + or a new one is created and becomes the new primary cache. + Otherwise, any existing contents of the default cache are + destroyed by kinit. **-S** *service_name* specify an alternate service name to use when getting initial tickets. @@ -162,7 +169,14 @@ ENVIRONMENT *kinit* uses the following environment variables: - **KRB5CCNAME** Location of the Kerberos 5 credentials (ticket) cache. + **KRB5CCNAME** + Location of the default Kerberos 5 credentials (ticket) + cache, in the form *type*:*residual*. If no type prefix is + present, the **FILE** type is assumed. The type of the + default cache may determine the availability of a cache + collection; for instance, a default cache of type **DIR** + causes caches within the directory to be present in the + collection. FILES diff --git a/doc/rst_source/krb_users/user_commands/klist.rst b/doc/rst_source/krb_users/user_commands/klist.rst index 86a514c8e..3886a9ff0 100644 --- a/doc/rst_source/krb_users/user_commands/klist.rst +++ b/doc/rst_source/krb_users/user_commands/klist.rst @@ -7,7 +7,7 @@ SYNOPSIS **klist** [**-e**] - [[**-c**] [**-f**] [**-s**] [**-a** [**-n**]]] + [[**-c**] [**-l**] [**-A**] [**-f**] [**-s**] [**-a** [**-n**]]] [**-k** [**-t**] [**-K**]] [**-V**] [*cache_name* | *keytab_name*] @@ -26,6 +26,14 @@ OPTIONS Displays the encryption types of the session key and the ticket for each credential in the credential cache, or each key in the keytab file. + **-l** + If a cache collection is available, displays a table + summarizing the caches present in the collection. + + **-A** + If a cache collection is available, displays the contents of + all of the caches in the collection. + **-c** List tickets held in a credentials cache. This is the default if neither *-c* nor *-k* is specified. @@ -79,7 +87,14 @@ ENVIRONMENT *klist* uses the following environment variables: - **KRB5CCNAME** - Location of the Kerberos 5 credentials (ticket) cache. + **KRB5CCNAME** + Location of the default Kerberos 5 credentials (ticket) + cache, in the form *type*:*residual*. If no type prefix is + present, the **FILE** type is assumed. The type of the + default cache may determine the availability of a cache + collection; for instance, a default cache of type **DIR** + causes caches within the directory to be present in the + collection. FILES diff --git a/doc/rst_source/krb_users/user_commands/kswitch.rst b/doc/rst_source/krb_users/user_commands/kswitch.rst new file mode 100644 index 000000000..fad2d9aee --- /dev/null +++ b/doc/rst_source/krb_users/user_commands/kswitch.rst @@ -0,0 +1,53 @@ +kswitch - switch primary credential cache +========================================= + + +SYNOPSIS +~~~~~~~~ + +**kswitch** {**-c** *cachename* | **-p** *principal*} + +DESCRIPTION +~~~~~~~~~~~ + +*kswitch* makes the specified credential cache the primary cache for +the collection, if a cache collection is available. + + +OPTIONS +~~~~~~~ + + **-c** *cachename* + Directly specifies the credential cache to be made primary. + + **-p** *principal* + Causes the cache collection to be searched for a cache + containing credentials for *principal*. If one is found, + that collection is made primary. + + +ENVIRONMENT +~~~~~~~~~~~ + +*kswitch* uses the following environment variables: + + **KRB5CCNAME** + Location of the default Kerberos 5 credentials (ticket) + cache, in the form *type*:*residual*. If no type prefix is + present, the **FILE** type is assumed. The type of the + default cache may determine the availability of a cache + collection; for instance, a default cache of type **DIR** + causes caches within the directory to be present in the + collection. + + +FILES +~~~~~ + +/tmp/krb5cc_[uid] - Default location of Kerberos 5 credentials cache ([*uid*] is the decimal UID of the user). + + +SEE ALSO +~~~~~~~~ + +kinit(1), kdestroy(1), klist(1), kerberos(1) diff --git a/src/clients/Makefile.in b/src/clients/Makefile.in index 4ae836194..4beb32a61 100644 --- a/src/clients/Makefile.in +++ b/src/clients/Makefile.in @@ -1,7 +1,7 @@ mydir=clients BUILDTOP=$(REL).. -SUBDIRS= klist kinit kdestroy kpasswd ksu kvno kcpytkt kdeltkt -WINSUBDIRS= klist kinit kdestroy kpasswd kvno kcpytkt kdeltkt +SUBDIRS= klist kinit kdestroy kpasswd ksu kvno kcpytkt kdeltkt kswitch +WINSUBDIRS= klist kinit kdestroy kpasswd kvno kcpytkt kdeltkt kswitch NO_OUTPRE=1 diff --git a/src/clients/kdestroy/kdestroy.M b/src/clients/kdestroy/kdestroy.M index ada2ae3dc..4deaa5fde 100644 --- a/src/clients/kdestroy/kdestroy.M +++ b/src/clients/kdestroy/kdestroy.M @@ -26,7 +26,7 @@ kdestroy \- destroy Kerberos tickets .SH SYNOPSIS .B kdestroy -[\fB\-q\fP] [\fB\-c\fP \fIcache_name] +[\fB\-A\fP] [\fB\-q\fP] [\fB\-c\fP \fIcache_name] .br .SH DESCRIPTION The @@ -37,6 +37,9 @@ the credentials cache is not specified, the default credentials cache is destroyed. .SH OPTIONS .TP +.B \-A +Destroys all caches in the collection, if a cache collection is +available. .B \-q Run quietly. Normally .B kdestroy @@ -65,7 +68,12 @@ file, so that your tickets are destroyed automatically when you log out. uses the following environment variables: .TP "\w'.SM KRB5CCNAME\ \ 'u" .SM KRB5CCNAME -Location of the Kerberos 5 credentials (ticket) cache. +Location of the default Kerberos 5 credentials (ticket) cache, in the +form \fItype\fP:\fIresidual\fP. If no type prefix is present, the +\fBFILE\fP type is assumed. The type of the default cache may +determine the availability of a cache collection; for instance, a +default cache of type \fBDIR\fP causes caches within the directory to +be present in the collection. .SH FILES .TP "\w'/tmp/krb5cc_[uid]\ \ 'u" /tmp/krb5cc_[uid] diff --git a/src/clients/kdestroy/kdestroy.c b/src/clients/kdestroy/kdestroy.c index 73ce04459..abe49533d 100644 --- a/src/clients/kdestroy/kdestroy.c +++ b/src/clients/kdestroy/kdestroy.c @@ -55,7 +55,8 @@ static void usage() { #define KRB_AVAIL_STRING(x) ((x)?"available":"not available") - fprintf(stderr, _("Usage: %s [-q] [-c cache_name]\n"), progname); + fprintf(stderr, _("Usage: %s [-A] [-q] [-c cache_name]\n"), progname); + fprintf(stderr, _("\t-A destroy all credential caches in collection\n")); fprintf(stderr, _("\t-q quiet mode\n")); fprintf(stderr, _("\t-c specify name of credentials cache\n")); exit(2); @@ -70,16 +71,21 @@ main(argc, argv) krb5_error_code retval; int c; krb5_ccache cache = NULL; + krb5_cccol_cursor cursor; char *cache_name = NULL; int code = 0; int errflg = 0; int quiet = 0; + int all = 0; setlocale(LC_MESSAGES, ""); progname = GET_PROGNAME(argv[0]); - while ((c = getopt(argc, argv, "54qc:")) != -1) { + while ((c = getopt(argc, argv, "54Aqc:")) != -1) { switch (c) { + case 'A': + all = 1; + break; case 'q': quiet = 1; break; @@ -117,6 +123,30 @@ main(argc, argv) exit(1); } + if (all) { + code = krb5_cccol_cursor_new(kcontext, &cursor); + if (code) { + com_err(progname, code, _("while listing credential caches")); + exit(1); + } + while ((code = krb5_cccol_cursor_next(kcontext, cursor, + &cache)) == 0 && cache != NULL) { + code = krb5_cc_get_full_name(kcontext, cache, &cache_name); + if (code) { + com_err(progname, code, _("composing ccache name")); + exit(1); + } + code = krb5_cc_destroy(kcontext, cache); + if (code && code != KRB5_FCC_NOFILE) { + com_err(progname, code, _("while destroying cache %s"), + cache_name); + } + krb5_free_string(kcontext, cache_name); + } + krb5_cccol_cursor_free(kcontext, &cursor); + return 0; + } + if (cache_name) { code = krb5_cc_resolve (kcontext, cache_name, &cache); if (code != 0) { diff --git a/src/clients/kinit/kinit.M b/src/clients/kinit/kinit.M index 3d95a62b3..0a919c09f 100644 --- a/src/clients/kinit/kinit.M +++ b/src/clients/kinit/kinit.M @@ -182,7 +182,11 @@ option is not used, the default cache name and location are used. The default credentials cache may vary between systems. If the .B KRB5CCNAME environment variable is set, its value is used to name the default -ticket cache. Any existing contents of the cache are destroyed by +ticket cache. If a principal name is specified and the type of the +default credentials cache supports a collection (such as the DIR +type), an existing cache containing credentials for the principal is +selected or a new one is created and becomes the new primary cache. +Otherwise, any existing contents of the default cache are destroyed by .IR kinit . .TP \fB\-S\fP \fIservice_name\fP @@ -215,7 +219,12 @@ pre-authentication mechanism: uses the following environment variables: .TP "\w'.SM KRB5CCNAME\ \ 'u" .SM KRB5CCNAME -Location of the Kerberos 5 credentials (ticket) cache. +Location of the default Kerberos 5 credentials (ticket) cache, in the +form \fItype\fP:\fIresidual\fP. If no type prefix is present, the +\fBFILE\fP type is assumed. The type of the default cache may +determine the availability of a cache collection; for instance, a +default cache of type \fBDIR\fP causes caches within the directory to +be present in the collection. .SH FILES .TP "\w'/tmp/krb5cc_[uid]\ \ 'u" /tmp/krb5cc_[uid] @@ -227,4 +236,4 @@ default location for the local host's .B keytab file. .SH SEE ALSO -klist(1), kdestroy(1), kerberos(1) +klist(1), kdestroy(1), kswitch(1), kerberos(1) diff --git a/src/clients/kinit/kinit.c b/src/clients/kinit/kinit.c index 802229ae0..1bf7564a1 100644 --- a/src/clients/kinit/kinit.c +++ b/src/clients/kinit/kinit.c @@ -133,6 +133,7 @@ struct k5_data krb5_ccache cc; krb5_principal me; char* name; + krb5_boolean switch_to_cache; }; #ifdef GETOPT_LONG @@ -438,6 +439,8 @@ k5_begin(opts, k5) { krb5_error_code code = 0; int flags = opts->enterprise ? KRB5_PRINCIPAL_PARSE_ENTERPRISE : 0; + krb5_ccache defcache; + const char *deftype; code = krb5_init_context(&k5->ctx); if (code) { @@ -445,8 +448,18 @@ k5_begin(opts, k5) return 0; } errctx = k5->ctx; - if (opts->k5_cache_name) - { + + /* Parse specified principal name now if we got one. */ + if (opts->principal_name) { + if ((code = krb5_parse_name_flags(k5->ctx, opts->principal_name, + flags, &k5->me))) { + com_err(progname, code, _("when parsing name %s"), + opts->principal_name); + return 0; + } + } + + if (opts->k5_cache_name) { code = krb5_cc_resolve(k5->ctx, opts->k5_cache_name, &k5->cc); if (code != 0) { com_err(progname, code, _("resolving ccache %s"), @@ -457,31 +470,48 @@ k5_begin(opts, k5) fprintf(stderr, _("Using specified cache: %s\n"), opts->k5_cache_name); } - } - else - { - if ((code = krb5_cc_default(k5->ctx, &k5->cc))) { + } else { + if ((code = krb5_cc_default(k5->ctx, &defcache))) { com_err(progname, code, _("while getting default ccache")); return 0; } - if (opts->verbose) { - fprintf(stderr, _("Using default cache: %s\n"), - krb5_cc_get_name(k5->ctx, k5->cc)); + deftype = krb5_cc_get_type(k5->ctx, defcache); + if (k5->me != NULL && krb5_cc_support_switch(k5->ctx, deftype)) { + /* Use an existing cache for the specified principal if we can. */ + code = krb5_cc_cache_match(k5->ctx, k5->me, &k5->cc); + if (code != 0 && code != KRB5_CC_NOTFOUND) { + com_err(progname, code, _("while searching for ccache for %s"), + opts->principal_name); + krb5_cc_close(k5->ctx, defcache); + return 0; + } + if (code == KRB5_CC_NOTFOUND) { + code = krb5_cc_new_unique(k5->ctx, deftype, NULL, &k5->cc); + if (code) { + com_err(progname, code, _("while generating new ccache")); + krb5_cc_close(k5->ctx, defcache); + return 0; + } + if (opts->verbose) { + fprintf(stderr, _("Using new cache: %s\n"), + krb5_cc_get_name(k5->ctx, k5->cc)); + } + } else if (opts->verbose) { + fprintf(stderr, _("Using existing cache: %s\n"), + krb5_cc_get_name(k5->ctx, k5->cc)); + } + krb5_cc_close(k5->ctx, defcache); + k5->switch_to_cache = 1; + } else { + k5->cc = defcache; + if (opts->verbose) { + fprintf(stderr, _("Using default cache: %s\n"), + krb5_cc_get_name(k5->ctx, k5->cc)); + } } } - if (opts->principal_name) - { - /* Use specified name */ - if ((code = krb5_parse_name_flags(k5->ctx, opts->principal_name, - flags, &k5->me))) { - com_err(progname, code, _("when parsing name %s"), - opts->principal_name); - return 0; - } - } - else - { + if (!k5->me) { /* No principal name specified */ if (opts->anonymous) { char *defrealm; @@ -756,6 +786,14 @@ k5_kinit(opts, k5) } notix = 0; + if (k5->switch_to_cache) { + code = krb5_cc_switch(k5->ctx, k5->cc); + if (code) { + com_err(progname, code, _("while switching to new ccache")); + goto cleanup; + } + } + cleanup: if (options) krb5_get_init_creds_opt_free(k5->ctx, options); diff --git a/src/clients/klist/klist.M b/src/clients/klist/klist.M index 0f9bb03cc..32aed10ac 100644 --- a/src/clients/klist/klist.M +++ b/src/clients/klist/klist.M @@ -25,7 +25,7 @@ .SH NAME klist \- list cached Kerberos tickets .SH SYNOPSIS -\fBklist\fP [\fB\-e\fP] [[\fB\-c\fP] [\fB\-f\fP] +\fBklist\fP [\fB\-e\fP] [[\fB\-c\fP] [\fB\-l\fP] [\fB\-A\fP] [\fB\-f\fP] [\fB\-s\fP] [\fB\-a\fP [\fB\-n\fP]]] [\fB\-k\fP [\fB\-t\fP] [\fB\-K\fP]] [\fIcache_name\fP | \fIkeytab_name\fP] @@ -50,6 +50,14 @@ nor .B \-k is specified. .TP +.B \-l +If a cache collection is available, displays a table summarizing the +caches present in the collection. +.TP +.B \-A +If a cache collection is available, displays the contents of all of +the caches in the collection. +.TP .B \-f shows the flags present in the credentials, using the following abbreviations: @@ -119,7 +127,12 @@ ticket cache. uses the following environment variables: .TP "\w'.SM KRB5CCNAME\ \ 'u" .SM KRB5CCNAME -Location of the Kerberos 5 credentials (ticket) cache. +Location of the default Kerberos 5 credentials (ticket) cache, in the +form \fItype\fP:\fIresidual\fP. If no type prefix is present, the +\fBFILE\fP type is assumed. The type of the default cache may +determine the availability of a cache collection; for instance, a +default cache of type \fBDIR\fP causes caches within the directory to +be present in the collection. .SH FILES .TP "\w'/tmp/krb5cc_[uid]\ \ 'u" /tmp/krb5cc_[uid] diff --git a/src/clients/klist/klist.c b/src/clients/klist/klist.c index d191f85c8..4757f381a 100644 --- a/src/clients/klist/klist.c +++ b/src/clients/klist/klist.c @@ -54,7 +54,7 @@ extern int optind; int show_flags = 0, show_time = 0, status_only = 0, show_keys = 0; int show_etype = 0, show_addresses = 0, no_resolve = 0, print_version = 0; -int show_adtype = 0; +int show_adtype = 0, show_all = 0, list_all = 0; char *defname; char *progname; krb5_int32 now; @@ -65,7 +65,11 @@ krb5_context kcontext; char * etype_string (krb5_enctype ); void show_credential (krb5_creds *); -void do_ccache (char *); +void list_all_ccaches (void); +int list_ccache (krb5_ccache); +void show_all_ccaches (void); +void do_ccache_name (char *); +int do_ccache (krb5_ccache); void do_keytab (char *); void printtime (time_t); void one_addr (krb5_address *); @@ -79,11 +83,13 @@ static void usage() { #define KRB_AVAIL_STRING(x) ((x)?"available":"not available") - fprintf(stderr, _("Usage: %s [-e] [-V] [[-c] [-d] [-f] [-s] [-a [-n]]] " - "[-k [-t] [-K]] [name]\n"), progname); + fprintf(stderr, _("Usage: %s [-e] [-V] [[-c] [-l] [-A] [-d] [-f] [-s] " + "[-a [-n]]] [-k [-t] [-K]] [name]\n"), progname); fprintf(stderr, _("\t-c specifies credentials cache\n")); fprintf(stderr, _("\t-k specifies keytab\n")); fprintf(stderr, _("\t (Default is credentials cache)\n")); + fprintf(stderr, _("\t-l lists credential caches in collection\n")); + fprintf(stderr, _("\t-A shows content of all credential caches\n")); fprintf(stderr, _("\t-e shows the encryption type\n")); fprintf(stderr, _("\t-V shows the Kerberos version and exits\n")); fprintf(stderr, _("\toptions for credential caches:\n")); @@ -115,7 +121,7 @@ main(argc, argv) name = NULL; mode = DEFAULT; /* V=version so v can be used for verbose later if desired. */ - while ((c = getopt(argc, argv, "dfetKsnack45V")) != -1) { + while ((c = getopt(argc, argv, "dfetKsnack45lAV")) != -1) { switch (c) { case 'd': show_adtype = 1; @@ -155,6 +161,12 @@ main(argc, argv) break; case '5': break; + case 'l': + list_all = 1; + break; + case 'A': + show_all = 1; + break; case 'V': print_version = 1; break; @@ -171,8 +183,11 @@ main(argc, argv) if (mode == DEFAULT || mode == CCACHE) { if (show_time || show_keys) usage(); + if ((show_all && list_all) || (status_only && list_all)) + usage(); } else { - if (show_flags || status_only || show_addresses) + if (show_flags || status_only || show_addresses || + show_all || list_all) usage(); } @@ -213,8 +228,12 @@ main(argc, argv) exit(1); } - if (mode == DEFAULT || mode == CCACHE) - do_ccache(name); + if (list_all) + list_all_ccaches(); + else if (show_all) + show_all_ccaches(); + else if (mode == DEFAULT || mode == CCACHE) + do_ccache_name(name); else do_keytab(name); } @@ -306,20 +325,103 @@ void do_keytab(name) } exit(0); } -void do_ccache(name) - char *name; + +void +list_all_ccaches(void) { - krb5_ccache cache = NULL; - krb5_cc_cursor cur; - krb5_creds creds; - krb5_principal princ; - krb5_flags flags; krb5_error_code code; - int exit_status = 0; + krb5_ccache cache; + krb5_cccol_cursor cursor; + int exit_status; + + code = krb5_cccol_cursor_new(kcontext, &cursor); + if (code) { + if (!status_only) + com_err(progname, code, _("while listing ccache collection")); + exit(1); + } + + /* XXX Translating would disturb table alignment; skip for now. */ + printf("%-30s %s\n", "Principal name", "Cache name"); + printf("%-30s %s\n", "--------------", "----------"); + exit_status = 1; + while (!(code = krb5_cccol_cursor_next(kcontext, cursor, &cache)) && + cache != NULL) { + exit_status = list_ccache(cache) && exit_status; + krb5_cc_close(kcontext, cache); + } + krb5_cccol_cursor_free(kcontext, &cursor); + exit(exit_status); +} + +int +list_ccache(krb5_ccache cache) +{ + krb5_error_code code; + krb5_principal princ = NULL; + char *princname = NULL, *ccname = NULL; + int expired, status = 1; + + code = krb5_cc_get_principal(kcontext, cache, &princ); + if (code) /* Uninitialized cache file, probably. */ + goto cleanup; + code = krb5_unparse_name(kcontext, princ, &princname); + if (code) + goto cleanup; + code = krb5_cc_get_full_name(kcontext, cache, &ccname); + if (code) + goto cleanup; + + status_only = 1; + expired = do_ccache(cache); + + printf("%-30.30s %s", princname, ccname); + if (expired) + printf(" %s", _("(Expired)")); + printf("\n"); + + status = 0; +cleanup: + krb5_free_principal(kcontext, princ); + free(princname); + free(ccname); + return status; +} - if (status_only) - /* exit_status is set back to 0 if a valid tgt is found */ - exit_status = 1; +void +show_all_ccaches(void) +{ + krb5_error_code code; + krb5_ccache cache; + krb5_cccol_cursor cursor; + krb5_boolean first; + int exit_status; + + code = krb5_cccol_cursor_new(kcontext, &cursor); + if (code) { + if (!status_only) + com_err(progname, code, _("while listing ccache collection")); + exit(1); + } + exit_status = 1; + first = TRUE; + while (!(code = krb5_cccol_cursor_next(kcontext, cursor, &cache)) && + cache != NULL) { + if (!first) + printf("\n"); + first = FALSE; + exit_status = do_ccache(cache) && exit_status; + krb5_cc_close(kcontext, cache); + } + krb5_cccol_cursor_free(kcontext, &cursor); + exit(exit_status); +} + +void +do_ccache_name(char *name) +{ + krb5_error_code code; + krb5_ccache cache; if (name == NULL) { if ((code = krb5_cc_default(kcontext, &cache))) { @@ -335,6 +437,21 @@ void do_ccache(name) exit(1); } } + exit(do_ccache(cache)); +} + +int +do_ccache(krb5_ccache cache) +{ + krb5_cc_cursor cur; + krb5_creds creds; + krb5_principal princ; + krb5_flags flags; + krb5_error_code code; + int exit_status = 0; + + /* For status_only, exit_status is reset to 0 if a valid tgt is found. */ + exit_status = (status_only) ? 1 : 0; flags = 0; /* turns off OPENCLOSE mode */ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) { @@ -355,17 +472,17 @@ void do_ccache(name) krb5_cc_get_type(kcontext, cache), krb5_cc_get_name(kcontext, cache)); } - exit(1); + return 1; } if ((code = krb5_cc_get_principal(kcontext, cache, &princ))) { if (!status_only) com_err(progname, code, _("while retrieving principal name")); - exit(1); + return 1; } if ((code = krb5_unparse_name(kcontext, princ, &defname))) { if (!status_only) com_err(progname, code, _("while unparsing principal name")); - exit(1); + return 1; } if (!status_only) { printf(_("Ticket cache: %s:%s\nDefault principal: %s\n\n"), @@ -383,7 +500,7 @@ void do_ccache(name) if ((code = krb5_cc_start_seq_get(kcontext, cache, &cur))) { if (!status_only) com_err(progname, code, _("while starting to retrieve tickets")); - exit(1); + return 1; } while (!(code = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) { if (krb5_is_config_principal(kcontext, creds.server)) @@ -404,23 +521,23 @@ void do_ccache(name) if ((code = krb5_cc_end_seq_get(kcontext, cache, &cur))) { if (!status_only) com_err(progname, code, _("while finishing ticket retrieval")); - exit(1); + return 1; } flags = KRB5_TC_OPENCLOSE; /* turns on OPENCLOSE mode */ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) { if (!status_only) com_err(progname, code, _("while closing ccache")); - exit(1); + return 1; } #ifdef KRB5_KRB4_COMPAT if (name == NULL && !status_only) do_v4_ccache(0); #endif - exit(exit_status); + return exit_status; } else { if (!status_only) com_err(progname, code, _("while retrieving a ticket")); - exit(1); + return 1; } } diff --git a/src/clients/kswitch/Makefile.in b/src/clients/kswitch/Makefile.in new file mode 100644 index 000000000..c82d8d609 --- /dev/null +++ b/src/clients/kswitch/Makefile.in @@ -0,0 +1,39 @@ +mydir=clients$(S)kswitch +BUILDTOP=$(REL)..$(S).. +DEFS= + +SRCS=kswitch.c + +PROG_LIBPATH=-L$(TOPLIBD) +PROG_RPATH=$(KRB5_LIBDIR) + +##WIN32##VERSIONRC = $(BUILDTOP)\windows\version.rc +##WIN32##RCFLAGS=$(CPPFLAGS) -I$(top_srcdir) -D_WIN32 -DRES_ONLY + +##WIN32##KSWITCH=$(OUTPRE)kswitch.exe + +##WIN32##EXERES=$(KSWITCH:.exe=.res) + +##WIN32##$(EXERES): $(VERSIONRC) +##WIN32## $(RC) $(RCFLAGS) -DKSWITCH_APP -fo $@ -r $** + +all-unix:: kswitch +##WIN32##all-windows:: $(KSWITCH) + +kswitch: kswitch.o $(KRB5_BASE_DEPLIBS) + $(CC_LINK) -o $@ kswitch.o $(KRB5_BASE_LIBS) + +##WIN32##$(KSWITCH): $(OUTPRE)kswitch.obj $(BUILDTOP)\util\windows\$(OUTPRE)getopt.obj $(KLIB) $(CLIB) $(EXERES) +##WIN32## link $(EXE_LINKOPTS) -out:$@ $** +##WIN32## $(_VC_MANIFEST_EMBED_EXE) + +clean-unix:: + $(RM) kswitch.o kswitch + +install-unix:: + for f in kswitch; do \ + $(INSTALL_PROGRAM) $$f \ + $(DESTDIR)$(CLIENT_BINDIR)/`echo $$f|sed '$(transform)'`; \ + $(INSTALL_DATA) $(srcdir)/$$f.M \ + $(DESTDIR)$(CLIENT_MANDIR)/`echo $$f|sed '$(transform)'`.1; \ + done diff --git a/src/clients/kswitch/deps b/src/clients/kswitch/deps new file mode 100644 index 000000000..734317139 --- /dev/null +++ b/src/clients/kswitch/deps @@ -0,0 +1,14 @@ +# +# Generated makefile dependencies follow. +# +$(OUTPRE)kswitch.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ + $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ + $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \ + $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \ + $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \ + $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \ + $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ + $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ + $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/krb5/preauth_plugin.h \ + $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ + kswitch.c diff --git a/src/clients/kswitch/kswitch.M b/src/clients/kswitch/kswitch.M new file mode 100644 index 000000000..407697551 --- /dev/null +++ b/src/clients/kswitch/kswitch.M @@ -0,0 +1,61 @@ +.\" clients/kswitch/kswitch.M +.\" +.\" Copyright 2011 by the Massachusetts Institute of Technology. +.\" +.\" Export of this software from the United States of America may +.\" require a specific license from the United States Government. +.\" It is the responsibility of any person or organization contemplating +.\" export to obtain such a license before exporting. +.\" +.\" WITHIN THAT CONSTRAINT, permission to use, copy, modify, and +.\" distribute this software and its documentation for any purpose and +.\" without fee is hereby granted, provided that the above copyright +.\" notice appear in all copies and that both that copyright notice and +.\" this permission notice appear in supporting documentation, and that +.\" the name of M.I.T. not be used in advertising or publicity pertaining +.\" to distribution of the software without specific, written prior +.\" permission. Furthermore if you modify this software you must label +.\" your software as modified software and not distribute it in such a +.\" fashion that it might be confused with the original M.I.T. software. +.\" M.I.T. makes no representations about the suitability of +.\" this software for any purpose. It is provided "as is" without express +.\" or implied warranty. +.\" " +.TH KSWITCH 1 +.SH NAME +kswitch \- switch primary credential cache +.SH SYNOPSIS +\fBkswitch\fP {\fB\-c\fP \fIcachename\fP | \fB\-p\fP \fIprincipal\fP} +.SH DESCRIPTION +.I kswitch +makes the specified credential cache the primary cache for the +collection, if a cache collection is available. +.SH OPTIONS +.TP +.B \-c +.I cachename +directly specifies the credential cache to be made primary. +.TP +.B \-p +.I principal +causes the cache collection to be searched for a cache containing +credentials for \fIprincipal\fP. If one is found, that collection is +made primary. +.SH ENVIRONMENT +.B kswitch +uses the following environment variables: +.TP "\w'.SM KRB5CCNAME\ \ 'u" +.SM KRB5CCNAME +Location of the default Kerberos 5 credentials (ticket) cache, in the +form \fItype\fP:\fIresidual\fP. If no type prefix is present, the +\fBFILE\fP type is assumed. The type of the default cache may +determine the availability of a cache collection; for instance, a +default cache of type \fBDIR\fP causes caches within the directory to +be present in the collection. +.SH FILES +.TP "\w'/tmp/krb5cc_[uid]\ \ 'u" +/tmp/krb5cc_[uid] +default location of Kerberos 5 credentials cache +([uid] is the decimal UID of the user). +.SH SEE ALSO +kinit(1), kdestroy(1), klist(1), kerberos(1) diff --git a/src/clients/kswitch/kswitch.c b/src/clients/kswitch/kswitch.c new file mode 100644 index 000000000..42cc9d664 --- /dev/null +++ b/src/clients/kswitch/kswitch.c @@ -0,0 +1,127 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* clients/kswitch/kswitch.c - Switch primary credential cache */ +/* + * Copyright 2011 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +#include "k5-int.h" + +extern int optind; +extern char *optarg; + +#ifndef _WIN32 +#define GET_PROGNAME(x) (strrchr((x), '/') ? strrchr((x), '/')+1 : (x)) +#else +#define GET_PROGNAME(x) max(max(strrchr((x), '/'), strrchr((x), '\\')) + 1,(x)) +#endif + +static char *progname; + +static void +usage(void) +{ + fprintf(stderr, _("Usage: %s {-c cache_name | -p principal}\n"), progname); + fprintf(stderr, _("\t-c specify name of credentials cache\n")); + fprintf(stderr, _("\t-p specify name of principal\n")); + exit(2); +} + +int +main(int argc, char **argv) +{ + krb5_context context; + krb5_error_code ret; + int c; + krb5_ccache cache = NULL; + krb5_principal princ = NULL; + const char *cache_name = NULL, *princ_name = NULL; + krb5_boolean errflag = FALSE; + + setlocale(LC_MESSAGES, ""); + progname = GET_PROGNAME(argv[0]); + + while ((c = getopt(argc, argv, "c:p:")) != -1) { + switch (c) { + case 'c': + case 'p': + if (cache_name || princ_name) { + fprintf(stderr, _("Only one -c or -p option allowed\n")); + errflag = TRUE; + } else if (c == 'c') { + cache_name = optarg; + } else { + princ_name = optarg; + } + break; + case '?': + default: + errflag = TRUE; + break; + } + } + + if (optind != argc) + errflag = TRUE; + + if (!cache_name && !princ_name) { + fprintf(stderr, _("One of -c or -p must be specified\n")); + errflag = TRUE; + } + + if (errflag) + usage(); + + ret = krb5_init_context(&context); + if (ret) { + com_err(progname, ret, _("while initializing krb5")); + exit(1); + } + + if (cache_name) { + ret = krb5_cc_resolve(context, cache_name, &cache); + if (ret != 0) { + com_err(progname, ret, _("while resolving %s"), cache_name); + exit(1); + } + } else { + ret = krb5_parse_name(context, princ_name, &princ); + if (ret) { + com_err(progname, ret, _("while parsing principal name %s"), + princ_name); + exit(1); + } + ret = krb5_cc_cache_match(context, princ, &cache); + if (ret) { + com_err(progname, ret, _("while searching for ccache for %s"), + princ_name); + exit(1); + } + } + + ret = krb5_cc_switch(context, cache); + if (ret != 0) { + com_err(progname, ret, _("while switching to credential cache")); + exit(1); + } + return 0; +} diff --git a/src/configure.in b/src/configure.in index c765c91e3..38889cf52 100644 --- a/src/configure.in +++ b/src/configure.in @@ -1239,7 +1239,7 @@ dnl ccapi ccapi/lib ccapi/lib/unix ccapi/server ccapi/server/unix ccapi/test plugins/authdata/greet_server clients clients/klist clients/kinit clients/kvno - clients/kdestroy clients/kpasswd clients/ksu + clients/kdestroy clients/kpasswd clients/ksu clients/kswitch kadmin kadmin/cli kadmin/dbutil kadmin/ktutil kadmin/server kadmin/testing kadmin/testing/scripts kadmin/testing/util diff --git a/src/lib/krb5/ccache/cccursor.c b/src/lib/krb5/ccache/cccursor.c index 2efaa322c..23681f99f 100644 --- a/src/lib/krb5/ccache/cccursor.c +++ b/src/lib/krb5/ccache/cccursor.c @@ -181,7 +181,7 @@ krb5_cc_cache_match(krb5_context context, krb5_principal client, { krb5_error_code ret; krb5_cccol_cursor cursor; - krb5_ccache cache; + krb5_ccache cache = NULL; krb5_principal princ; char *name; krb5_boolean eq; diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in index 987238cfb..0d6f0b795 100644 --- a/src/tests/Makefile.in +++ b/src/tests/Makefile.in @@ -68,6 +68,7 @@ check-pytests:: $(RUNPYTEST) $(srcdir)/t_keyrollover.py $(PYTESTFLAGS) $(RUNPYTEST) $(srcdir)/t_renew.py $(PYTESTFLAGS) $(RUNPYTEST) $(srcdir)/t_renprinc.py $(PYTESTFLAGS) + $(RUNPYTEST) $(srcdir)/t_cccol.py $(PYTESTFLAGS) clean:: $(RM) kdc.conf diff --git a/src/tests/t_cccol.py b/src/tests/t_cccol.py new file mode 100644 index 000000000..d8db275ce --- /dev/null +++ b/src/tests/t_cccol.py @@ -0,0 +1,77 @@ +# Copyright (C) 2011 by the Massachusetts Institute of Technology. +# All rights reserved. + +# Export of this software from the United States of America may +# require a specific license from the United States Government. +# It is the responsibility of any person or organization contemplating +# export to obtain such a license before exporting. +# +# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and +# distribute this software and its documentation for any purpose and +# without fee is hereby granted, provided that the above copyright +# notice appear in all copies and that both that copyright notice and +# this permission notice appear in supporting documentation, and that +# the name of M.I.T. not be used in advertising or publicity pertaining +# to distribution of the software without specific, written prior +# permission. Furthermore if you modify this software you must label +# your software as modified software and not distribute it in such a +# fashion that it might be confused with the original M.I.T. software. +# M.I.T. makes no representations about the suitability of +# this software for any purpose. It is provided "as is" without express +# or implied warranty. + +#!/usr/bin/python +from k5test import * + +realm = K5Realm(start_kadmind=False, create_user=False, create_host=False) + +# Make a directory collection and use it for client commands in both realms. +ccdir = os.path.join(realm.testdir, 'cc') +ccname = 'DIR:' + ccdir +os.mkdir(ccdir) +realm.env_client['KRB5CCNAME'] = ccname + +realm.addprinc('alice', password('alice')) +realm.addprinc('bob', password('bob')) +realm.addprinc('carol', password('carol')) + +realm.kinit('alice', password('alice')) +output = realm.run_as_client([klist]) +if 'Default principal: alice@' not in output: + fail('Initial kinit failed to get credentials for alice.') +realm.run_as_client([kdestroy]) +output = realm.run_as_client([klist], expected_code=1) +if 'No credentials cache found' not in output: + fail('Initial kdestroy failed to destroy primary cache.') +output = realm.run_as_client([klist, '-l'], expected_code=1) +if not output.endswith('---\n') or output.count('\n') != 2: + fail('Initial kdestroy failed to empty cache collection.') + +realm.kinit('alice', password('alice')) +realm.kinit('carol', password('carol')) +output = realm.run_as_client([klist, '-l']) +if '---\ncarol@' not in output or '\nalice@' not in output: + fail('klist -l did not show expected output after two kinits.') +realm.kinit('alice', password('alice')) +output = realm.run_as_client([klist, '-l']) +if '---\nalice@' not in output or output.count('\n') != 4: + fail('klist -l did not show expected output after re-kinit for alice.') +realm.kinit('bob', password('bob')) +output = realm.run_as_client([klist, '-A']) +if 'bob@' not in output.splitlines()[1] or 'alice@' not in output or \ + 'carol' not in output or output.count('Default principal:') != 3: + fail('klist -A did not show expected output after kinit for bob.') +realm.run_as_client([kswitch, '-p', 'carol']) +output = realm.run_as_client([klist, '-l']) +if '---\ncarol@' not in output or output.count('\n') != 5: + fail('klist -l did not show expected output after kswitch to carol.') +realm.run_as_client([kdestroy]) +output = realm.run_as_client([klist, '-l']) +if 'carol@' in output or 'bob@' not in output or output.count('\n') != 4: + fail('kdestroy failed to remove only primary ccache.') +realm.run_as_client([kdestroy, '-A']) +output = realm.run_as_client([klist, '-l'], expected_code=1) +if not output.endswith('---\n') or output.count('\n') != 2: + fail('kdestroy -a failed to empty cache collection.') + +success('Credential cache collection tests.') diff --git a/src/util/k5test.py b/src/util/k5test.py index cc3a7a1d6..ba4f8302b 100644 --- a/src/util/k5test.py +++ b/src/util/k5test.py @@ -181,6 +181,7 @@ Scripts may use the following functions and variables: - ktutil - kinit - klist + - kswitch - kvno - kdestroy - kpasswd @@ -1074,6 +1075,7 @@ kdb5_util = os.path.join(buildtop, 'kadmin', 'dbutil', 'kdb5_util') ktutil = os.path.join(buildtop, 'kadmin', 'ktutil', 'ktutil') kinit = os.path.join(buildtop, 'clients', 'kinit', 'kinit') klist = os.path.join(buildtop, 'clients', 'klist', 'klist') +kswitch = os.path.join(buildtop, 'clients', 'kswitch', 'kswitch') kvno = os.path.join(buildtop, 'clients', 'kvno', 'kvno') kdestroy = os.path.join(buildtop, 'clients', 'kdestroy', 'kdestroy') kpasswd = os.path.join(buildtop, 'clients', 'kpasswd', 'kpasswd') diff --git a/src/util/testrealm.py b/src/util/testrealm.py index 30466314c..30b3256ed 100644 --- a/src/util/testrealm.py +++ b/src/util/testrealm.py @@ -39,6 +39,7 @@ progpaths = [ os.path.join('clients', 'kpasswd'), os.path.join('clients', 'ksu'), os.path.join('clients', 'kvno'), + os.path.join('clients', 'kswitch'), 'slave' ]