diff options
Diffstat (limited to 'client/open.c')
-rw-r--r-- | client/open.c | 55 |
1 files changed, 49 insertions, 6 deletions
diff --git a/client/open.c b/client/open.c index 65029ff..6c2ce21 100644 --- a/client/open.c +++ b/client/open.c @@ -15,9 +15,10 @@ */ #include <config.h> -#include <portable/system.h> +#include <portable/krb5.h> #include <portable/gssapi.h> #include <portable/socket.h> +#include <portable/system.h> #include <errno.h> @@ -122,6 +123,42 @@ internal_import_name(struct remctl *r, const char *host, /* + * Import the client credentials from a designated Kerberos ticket cache. + * + * This code is used if we have Kerberos libraries available and the GSS-API + * implementation supports gss_krb5_import_cred. In that case, we can tell + * GSS-API which ticket cache to use. Otherwise, we have to either set a + * global GSS-API variable with gss_krb5_ccache_name or just use whatever the + * default is. The other cases are handled in remctl_set_ccache. + */ +static bool +internal_set_cred(struct remctl *r, gss_cred_id_t *gss_cred) +{ + krb5_error_code code; + OM_uint32 major, minor; + + if (r->krb_ctx == NULL) { + code = krb5_init_context(&r->krb_ctx); + if (code != 0) { + internal_krb5_error(r, "opening ticket cache", code); + return false; + } + } + code = krb5_cc_resolve(r->krb_ctx, r->ccache, &r->krb_ccache); + if (code != 0) { + internal_krb5_error(r, "opening ticket cache", code); + return false; + } + major = gss_krb5_import_cred(&minor, r->krb_ccache, NULL, NULL, gss_cred); + if (major != GSS_S_COMPLETE) { + internal_gssapi_error(r, "importing ticket cache", major, minor); + return false; + } + return true; +} + + +/* * Open a new connection to a server. Returns true on success, false on * failure. On failure, sets the error message appropriately. */ @@ -132,6 +169,7 @@ internal_open(struct remctl *r, const char *host, const char *principal) gss_buffer_desc send_tok, recv_tok, *token_ptr; gss_buffer_desc empty_token = { 0, (void *) "" }; gss_name_t name = GSS_C_NO_NAME; + gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL; gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT; OM_uint32 major, minor, init_minor, gss_flags; static const OM_uint32 wanted_gss_flags @@ -144,6 +182,11 @@ internal_open(struct remctl *r, const char *host, const char *principal) if (!internal_import_name(r, host, principal, &name)) goto fail; + /* If the user has specified a Kerberos ticket cache, import it. */ + if (r->ccache != NULL) + if (!internal_set_cred(r, &gss_cred)) + goto fail; + /* * Default to protocol version two, but if some other protocol is already * set in the remctl struct, don't override. This facility is used only @@ -160,7 +203,8 @@ internal_open(struct remctl *r, const char *host, const char *principal) goto fail; } - /* Perform the context-establishment loop. + /* + * Perform the context-establishment loop. * * On each pass through the loop, token_ptr points to the token to send to * the server (or GSS_C_NO_BUFFER on the first pass). Every generated @@ -179,10 +223,9 @@ internal_open(struct remctl *r, const char *host, const char *principal) */ token_ptr = GSS_C_NO_BUFFER; do { - major = gss_init_sec_context(&init_minor, GSS_C_NO_CREDENTIAL, - &gss_context, name, (const gss_OID) GSS_KRB5_MECHANISM, - wanted_gss_flags, 0, NULL, token_ptr, NULL, &send_tok, - &gss_flags, NULL); + major = gss_init_sec_context(&init_minor, gss_cred, &gss_context, + name, (const gss_OID) GSS_KRB5_MECHANISM, wanted_gss_flags, + 0, NULL, token_ptr, NULL, &send_tok, &gss_flags, NULL); if (token_ptr != GSS_C_NO_BUFFER) free(recv_tok.value); |