From 5cfaec38a8e8f1c4b76228ba0a252987af797ca4 Mon Sep 17 00:00:00 2001 From: Tom Yu Date: Fri, 11 Feb 2005 23:09:25 +0000 Subject: [PATCH] Implement principal name and auth flavor fallback for kadm5 client library. Adjust test suites to compensate. ticket: 2913 status: open git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@17099 dc483132-0cff-0310-8789-dd5450dbe970 --- doc/ChangeLog | 5 + doc/kadm5/api-unit-test.tex | 6 +- src/kadmin/testing/util/ChangeLog | 5 + src/kadmin/testing/util/tcl_kadm5.c | 3 + src/lib/kadm5/admin.h | 1 + src/lib/kadm5/clnt/ChangeLog | 10 + src/lib/kadm5/clnt/client_init.c | 607 +++++++++++--------- src/lib/kadm5/unit-test/ChangeLog | 7 + src/tests/dejagnu/krb-standalone/ChangeLog | 7 + src/tests/dejagnu/krb-standalone/kadmin.exp | 14 +- 10 files changed, 404 insertions(+), 261 deletions(-) diff --git a/doc/ChangeLog b/doc/ChangeLog index 0480c449d..c193325d7 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,8 @@ +2005-02-11 Tom Yu + + * kadm5/api-unit-test.tex (ovsec_kadm_init): Update to reflect + changed expected error codes for init 152, 153 tests. + 2005-01-03 Ken Raeburn * implementor.texinfo (Porting Issues): New chapter with a bunch diff --git a/doc/kadm5/api-unit-test.tex b/doc/kadm5/api-unit-test.tex index 3e3f6e2bf..5b1032781 100644 --- a/doc/kadm5/api-unit-test.tex +++ b/doc/kadm5/api-unit-test.tex @@ -588,7 +588,8 @@ credential for CHANGEPW_SERVICE.} \numtest{152}{ \Version{KADM5_API_VERSION_2} -\Reason{init_with_creds fails with KADM5_GSS_ERROR when given an open +\Reason{init_with_creds fails with KRB5_FCC_NOFILE (was + KADM5_GSS_ERROR) when given an open ccache with no credentials.} \Conditions{RPC} \Status{Implemented} @@ -596,7 +597,8 @@ ccache with no credentials.} \numtest{153}{ \Version{KADM5_API_VERSION_2} -\Reason{init_with_creds fails with KADM5_GSS_ERROR when given an open +\Reason{init_with_creds fails with KRB5_CC_NOTFOUND (was + KADM5_GSS_ERROR) when given an open ccache without credentials for ADMIN_SERVICE or CHANGEPW_SERVICE.} \Conditions{RPC} \Status{Implemented} diff --git a/src/kadmin/testing/util/ChangeLog b/src/kadmin/testing/util/ChangeLog index 868eeb980..f34d8f83c 100644 --- a/src/kadmin/testing/util/ChangeLog +++ b/src/kadmin/testing/util/ChangeLog @@ -1,3 +1,8 @@ +2005-02-10 Tom Yu + + * tcl_kadm5.c (unparse_err): Add entries for KRB5_CC_NOTFOUND and + KRB5_FCC_NOFILE, to handle changes in client_init.c. + 2004-07-28 Ken Raeburn * tcl_kadm5.c (parse_flags, parse_keysalts, parse_key_data, diff --git a/src/kadmin/testing/util/tcl_kadm5.c b/src/kadmin/testing/util/tcl_kadm5.c index 21e029bd1..a6b945277 100644 --- a/src/kadmin/testing/util/tcl_kadm5.c +++ b/src/kadmin/testing/util/tcl_kadm5.c @@ -410,6 +410,9 @@ static Tcl_DString *unparse_err(kadm5_ret_t code) case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN: code_string = "KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN"; break; case KRB5_CONFIG_BADFORMAT: code_string = "KRB5_CONFIG_BADFORMAT"; break; + case KRB5_CC_NOTFOUND: code_string = "KRB5_CC_NOTFOUND"; break; + case KRB5_FCC_NOFILE: code_string = "KRB5_FCC_NOFILE"; break; + case EINVAL: code_string = "EINVAL"; break; case ENOENT: code_string = "ENOENT"; break; diff --git a/src/lib/kadm5/admin.h b/src/lib/kadm5/admin.h index 866cfb0bb..4051601ec 100644 --- a/src/lib/kadm5/admin.h +++ b/src/lib/kadm5/admin.h @@ -123,6 +123,7 @@ typedef long kadm5_ret_t; #define KADM5_CONFIG_KPASSWD_PORT 0x080000 #define KADM5_CONFIG_OLD_AUTH_GSSAPI 0x100000 #define KADM5_CONFIG_NO_AUTH 0x200000 +#define KADM5_CONFIG_AUTH_NOFALLBACK 0x400000 /* * permission bits diff --git a/src/lib/kadm5/clnt/ChangeLog b/src/lib/kadm5/clnt/ChangeLog index 6d0a14ecd..fc2dfca2e 100644 --- a/src/lib/kadm5/clnt/ChangeLog +++ b/src/lib/kadm5/clnt/ChangeLog @@ -1,3 +1,13 @@ +2005-02-11 Tom Yu + + * client_init.c (kadm5_get_init_creds, kadm5_gic_iter) + (kadm5_setup_gss, kadm5_rpc_auth): New functions, containing parts + of _kadm5_init_any. + (_kadm5_init_any): Bits broken out into helper functions. + (kadm5_get_init_creds): Fall back from kadmin/fqdn to kadmin/admin + if NULL service name passed in. + (kadm5_rpc_auth): Fall back from RPCSEC_GSS to AUTH_GSSAPI. + 2004-10-25 Tom Yu * client_init.c (_kadm5_init_any): Pass req_flags and cred to diff --git a/src/lib/kadm5/clnt/client_init.c b/src/lib/kadm5/clnt/client_init.c index d3c63bde8..f1031548f 100644 --- a/src/lib/kadm5/clnt/client_init.c +++ b/src/lib/kadm5/clnt/client_init.c @@ -55,8 +55,6 @@ #define ADM_CCACHE "/tmp/ovsec_adm.XXXXXX" -static int old_auth_gssapi = 0; - enum init_type { INIT_PASS, INIT_SKEY, INIT_CREDS }; static kadm5_ret_t _kadm5_init_any(char *client_name, @@ -69,6 +67,32 @@ static kadm5_ret_t _kadm5_init_any(char *client_name, krb5_ui_4 api_version, void **server_handle); +static kadm5_ret_t +kadm5_get_init_creds(kadm5_server_handle_t handle, + char *client_name, enum init_type init_type, + char *pass, krb5_ccache ccache_in, + char *svcname_in, char *realm, + char *full_svcname, unsigned int full_svcname_len); + +static kadm5_ret_t +kadm5_gic_iter(kadm5_server_handle_t handle, + enum init_type init_type, + krb5_ccache ccache, + krb5_principal client, char *pass, + char *svcname, char *realm, + char *full_svcname, unsigned int full_svcname_len); + +static kadm5_ret_t +kadm5_setup_gss(kadm5_server_handle_t handle, + kadm5_config_params *params_in, + char *client_name, char *full_svcname); + +static void +kadm5_rpc_auth(kadm5_server_handle_t handle, + kadm5_config_params *params_in, + gss_cred_id_t gss_client_creds, + gss_name_t gss_target); + kadm5_ret_t kadm5_init_with_creds(char *client_name, krb5_ccache ccache, char *service_name, @@ -120,16 +144,6 @@ kadm5_ret_t kadm5_init_with_skey(char *client_name, char *keytab, api_version, server_handle); } -/* - * Try no preauthentication first; then try the encrypted timestamp - * (stolen from krb5 kinit.c) - */ -static int preauth_search_list[] = { - 0, - KRB5_PADATA_ENC_UNIX_TIME, - -1 -}; - static kadm5_ret_t _kadm5_init_any(char *client_name, enum init_type init_type, char *pass, @@ -143,27 +157,15 @@ static kadm5_ret_t _kadm5_init_any(char *client_name, struct sockaddr_in addr; struct hostent *hp; int fd; - int i; - char full_service_name[BUFSIZ], *ccname_orig; - const char *c_ccname_orig; + char full_svcname[BUFSIZ]; char *realm; - krb5_creds creds; - krb5_ccache ccache = NULL; - krb5_timestamp now; - OM_uint32 gssstat, minor_stat; - gss_buffer_desc input_name; - gss_name_t gss_client; - gss_name_t gss_target; - gss_cred_id_t gss_client_creds = GSS_C_NO_CREDENTIAL; - kadm5_server_handle_t handle; kadm5_config_params params_local; int code = 0; generic_ret *r; - char svcname[MAXHOSTNAMELEN + 8]; initialize_ovk_error_table(); initialize_adb_error_table(); @@ -198,7 +200,6 @@ static kadm5_ret_t _kadm5_init_any(char *client_name, free(handle); return EINVAL; } - memset((char *) &creds, 0, sizeof(creds)); /* * Verify the version numbers before proceeding; we can't use @@ -268,54 +269,136 @@ static kadm5_ret_t _kadm5_init_any(char *client_name, return KADM5_MISSING_KRB5_CONF_PARAMS; } - /* NULL service_name means use host-based. */ - if (service_name == NULL) { + /* + * Get credentials. Also does some fallbacks in case kadmin/fqdn + * principal doesn't exist. + */ + code = kadm5_get_init_creds(handle, client_name, init_type, pass, + ccache_in, service_name, realm, + full_svcname, sizeof(full_svcname)); + if (code) + goto error; + /* + * We have ticket; open the RPC connection. + */ + + hp = gethostbyname(handle->params.admin_server); + if (hp == (struct hostent *) NULL) { + code = KADM5_BAD_SERVER_NAME; + goto cleanup; + } + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = hp->h_addrtype; + (void) memcpy((char *) &addr.sin_addr, (char *) hp->h_addr, + sizeof(addr.sin_addr)); + addr.sin_port = htons((u_short) handle->params.kadmind_port); + + fd = RPC_ANYSOCK; + + handle->clnt = clnttcp_create(&addr, KADM, KADMVERS, &fd, 0, 0); + if (handle->clnt == NULL) { + code = KADM5_RPC_ERROR; +#ifdef DEBUG + clnt_pcreateerror("clnttcp_create"); +#endif + goto error; + } + handle->lhandle->clnt = handle->clnt; + + /* now that handle->clnt is set, we can check the handle */ + if ((code = _kadm5_check_handle((void *) handle))) + goto error; + + /* + * The RPC connection is open; establish the GSS-API + * authentication context. + */ + code = kadm5_setup_gss(handle, params_in, client_name, full_svcname); + if (code) + goto error; + + r = init_1(&handle->api_version, handle->clnt); + if (r == NULL) { + code = KADM5_RPC_ERROR; +#ifdef DEBUG + clnt_perror(handle->clnt, "init_1 null resp"); +#endif + goto error; + } + if (r->code) { + code = r->code; + goto error; + } + + *server_handle = (void *) handle; + + goto cleanup; + +error: + /* + * Note that it is illegal for this code to execute if "handle" + * has not been allocated and initialized. I.e., don't use "goto + * error" before the block of code at the top of the function + * that allocates and initializes "handle". + */ + if (handle->cache_name) + free(handle->cache_name); + if(handle->clnt && handle->clnt->cl_auth) + AUTH_DESTROY(handle->clnt->cl_auth); + if(handle->clnt) + clnt_destroy(handle->clnt); + +cleanup: + if (code) + free(handle); + + return code; +} + +/* + * kadm5_get_init_creds + * + * Get initial credentials for authenticating to server. Perform + * fallback from kadmin/fqdn to kadmin/admin if svcname_in is NULL. + */ +static kadm5_ret_t +kadm5_get_init_creds(kadm5_server_handle_t handle, + char *client_name, enum init_type init_type, + char *pass, krb5_ccache ccache_in, + char *svcname_in, char *realm, + char *full_svcname, unsigned int full_svcname_len) +{ + kadm5_ret_t code; + krb5_principal client; + krb5_ccache ccache; + char svcname[BUFSIZ]; + + client = NULL; + ccache = 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) { - krb5_free_context(handle->context); - free(handle); - return KADM5_MISSING_KRB5_CONF_PARAMS; + code = KADM5_MISSING_KRB5_CONF_PARAMS; + goto error; } - service_name = svcname; + } else { + strncpy(svcname, svcname_in, sizeof(svcname)); + svcname[sizeof(svcname)-1] = '\0'; } /* - * Acquire a service ticket for service_name@realm in the name of + * Acquire a service ticket for svcname@realm in the name of * client_name, 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 ((code = krb5_parse_name(handle->context, client_name, &creds.client))) - goto error; - - if (realm) { - if(strlen(service_name) + strlen(realm) + 1 >= sizeof(full_service_name)) { - goto error; - } - sprintf(full_service_name, "%s@%s", service_name, realm); - } else { - /* krb5_princ_realm(creds.client) is not null terminated */ - if(strlen(service_name) + krb5_princ_realm(handle->context, creds.client)->length + 1 >= sizeof(full_service_name)) { - goto error; - } - strcpy(full_service_name, service_name); - strcat(full_service_name, "@"); - strncat(full_service_name, krb5_princ_realm(handle->context, - creds.client)->data, - krb5_princ_realm(handle->context, creds.client)->length); - } - - if ((code = krb5_parse_name(handle->context, full_service_name, - &creds.server))) + code = krb5_parse_name(handle->context, client_name, &client); + if (code) goto error; - /* XXX temporarily fix a bug in krb5_cc_get_type */ -#undef krb5_cc_get_type -#define krb5_cc_get_type(context, cache) ((cache)->ops->prefix) - - if (init_type == INIT_CREDS) { ccache = ccache_in; handle->cache_name = (char *) @@ -329,161 +412,184 @@ static kadm5_ret_t _kadm5_init_any(char *client_name, krb5_cc_get_type(handle->context, ccache), krb5_cc_get_name(handle->context, ccache)); } else { -#if 0 - handle->cache_name = - (char *) malloc(strlen(ADM_CCACHE)+strlen("FILE:")+1); - if (handle->cache_name == NULL) { - code = ENOMEM; - goto error; - } - sprintf(handle->cache_name, "FILE:%s", ADM_CCACHE); - mktemp(handle->cache_name + strlen("FILE:")); -#else - { - static int counter = 0; - handle->cache_name = malloc(sizeof("MEMORY:kadm5_") - + 3*sizeof(counter)); - sprintf(handle->cache_name, "MEMORY:kadm5_%u", counter++); - } -#endif - - if ((code = krb5_cc_resolve(handle->context, handle->cache_name, - &ccache))) + static int counter = 0; + + handle->cache_name = malloc(sizeof("MEMORY:kadm5_") + + 3*sizeof(counter)); + sprintf(handle->cache_name, "MEMORY:kadm5_%u", counter++); + + code = krb5_cc_resolve(handle->context, handle->cache_name, + &ccache); + if (code) goto error; - - if ((code = krb5_cc_initialize (handle->context, ccache, - creds.client))) + + code = krb5_cc_initialize (handle->context, ccache, client); + if (code) goto error; handle->destroy_cache = 1; } handle->lhandle->cache_name = handle->cache_name; - - if ((code = krb5_timeofday(handle->context, &now))) - goto error; - - /* - * Get a ticket, use the method specified in init_type. - */ - - creds.times.starttime = 0; /* start timer at KDC */ - creds.times.endtime = 0; /* endtime will be limited by service */ - if (init_type == INIT_PASS) { - for (i=0; preauth_search_list[i] >= 0; i++) { - code = krb5_get_in_tkt_with_password(handle->context, - 0, /* no options */ - 0, /* default addresses */ - 0, /* enctypes */ - NULL, /* XXX preauth */ - pass, - ccache, - &creds, - NULL); - if (code != KRB5KDC_ERR_PREAUTH_FAILED && - code != KRB5KDC_ERR_PREAUTH_REQUIRED && - code != KRB5KRB_ERR_GENERIC) - break; - } - } else if (init_type == INIT_SKEY) { - krb5_keytab kt = NULL; - - if (pass && (code = krb5_kt_resolve(handle->context, pass, &kt))) - ; - else { - for (i=0; preauth_search_list[i] >= 0; i++) { - code = krb5_get_in_tkt_with_keytab(handle->context, - 0, /* no options */ - 0, /* default addrs */ - 0, /* enctypes */ - NULL, /* XXX preauth */ - kt, - ccache, - &creds, - NULL); - if (code != KRB5KDC_ERR_PREAUTH_FAILED && - code != KRB5KDC_ERR_PREAUTH_REQUIRED && - code != KRB5KRB_ERR_GENERIC) - break; - } - - if (pass) krb5_kt_close(handle->context, kt); - } + code = kadm5_gic_iter(handle, init_type, ccache, + client, pass, svcname, realm, + full_svcname, full_svcname_len); + if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN + || code == KRB5_CC_NOTFOUND) && svcname_in == NULL) { + /* Retry with old host-independent service princpal. */ + code = kadm5_gic_iter(handle, init_type, ccache, + client, pass, + KADM5_ADMIN_SERVICE, realm, + full_svcname, full_svcname_len); } - /* 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; - if (code != 0) goto error; - -#ifdef ZEROPASSWD - if (pass != NULL) - memset(pass, 0, strlen(pass)); -#endif +error: + if (ccache != NULL && init_type != INIT_CREDS) + krb5_cc_close(handle->context, ccache); + return code; +} - /* - * We have ticket; open the RPC connection. - */ +/* + * kadm5_gic_iter + * + * Perform one iteration of attempting to get credentials. This + * includes searching existing ccache for requested service if + * INIT_CREDS. + */ +static kadm5_ret_t +kadm5_gic_iter(kadm5_server_handle_t handle, + enum init_type init_type, + krb5_ccache ccache, + krb5_principal client, char *pass, + char *svcname, char *realm, + char *full_svcname, unsigned int full_svcname_len) +{ + kadm5_ret_t code; + krb5_context ctx; + krb5_keytab kt; + krb5_get_init_creds_opt opt; + krb5_creds mcreds, outcreds; + + ctx = handle->context; + kt = NULL; + memset(full_svcname, 0, full_svcname_len); + memset(&opt, 0, sizeof(opt)); + memset(&mcreds, 0, sizeof(mcreds)); + memset(&outcreds, 0, sizeof(outcreds)); + + code = ENOMEM; + if (realm) { + if ((strlen(svcname) + strlen(realm) + 1) >= full_svcname_len) + goto error; + sprintf(full_svcname, "%s@%s", svcname, realm); + } else { + /* krb5_princ_realm(client) is not null terminated */ + if ((strlen(svcname) + krb5_princ_realm(ctx, client)->length + 1) + >= full_svcname_len) + goto error; - hp = gethostbyname(handle->params.admin_server); - if (hp == (struct hostent *) NULL) { - code = KADM5_BAD_SERVER_NAME; - goto cleanup; + strcpy(full_svcname, svcname); + strcat(full_svcname, "@"); + strncat(full_svcname, + krb5_princ_realm(ctx, client)->data, + krb5_princ_realm(ctx, client)->length); } - memset(&addr, 0, sizeof(addr)); - addr.sin_family = hp->h_addrtype; - (void) memcpy((char *) &addr.sin_addr, (char *) hp->h_addr, - sizeof(addr.sin_addr)); - addr.sin_port = htons((u_short) handle->params.kadmind_port); - - fd = RPC_ANYSOCK; - - handle->clnt = clnttcp_create(&addr, KADM, KADMVERS, &fd, 0, 0); - if (handle->clnt == NULL) { - code = KADM5_RPC_ERROR; -#ifdef DEBUG - clnt_pcreateerror("clnttcp_create"); -#endif - goto error; + if (init_type != INIT_CREDS) + krb5_get_init_creds_opt_init(&opt); + + if (init_type == INIT_PASS) { + code = krb5_get_init_creds_password(ctx, &outcreds, client, pass, + krb5_prompter_posix, + NULL, 0, + full_svcname, &opt); + if (code) + goto error; + } else if (init_type == INIT_SKEY) { + if (pass) { + code = krb5_kt_resolve(ctx, pass, &kt); + if (code) + goto error; + } + code = krb5_get_init_creds_keytab(ctx, &outcreds, client, kt, + 0, full_svcname, &opt); + if (pass) + krb5_kt_close(ctx, kt); + if (code) + goto error; + } else if (init_type == INIT_CREDS) { + mcreds.client = client; + code = krb5_parse_name(ctx, full_svcname, &mcreds.server); + if (code) + goto error; + code = krb5_cc_retrieve_cred(ctx, ccache, 0, + &mcreds, &outcreds); + krb5_free_principal(ctx, mcreds.server); + if (code) + goto error; } - handle->lhandle->clnt = handle->clnt; + if (init_type != INIT_CREDS) { + /* Caller has initialized ccache. */ + code = krb5_cc_store_cred(ctx, ccache, &outcreds); + if (code) + goto error; + } +error: + krb5_free_cred_contents(ctx, &outcreds); + return code; +} - /* now that handle->clnt is set, we can check the handle */ - if ((code = _kadm5_check_handle((void *) handle))) - goto error; +/* + * kadm5_setup_gss + * + * Acquire GSSAPI credentials and set up RPC auth flavor. + */ +static kadm5_ret_t +kadm5_setup_gss(kadm5_server_handle_t handle, + kadm5_config_params *params_in, + char *client_name, char *full_svcname) +{ + kadm5_ret_t code; + OM_uint32 gssstat, minor_stat; + gss_buffer_desc buf; + gss_name_t gss_client; + gss_name_t gss_target; + gss_cred_id_t gss_client_creds; + const char *c_ccname_orig; + char *ccname_orig; - /* - * The RPC connection is open; establish the GSS-API - * authentication context. - */ + code = KADM5_GSS_ERROR; + gss_client_creds = GSS_C_NO_CREDENTIAL; + ccname_orig = NULL; - /* use the kadm5 cache */ + /* Temporarily use the kadm5 cache. */ gssstat = gss_krb5_ccache_name(&minor_stat, handle->cache_name, &c_ccname_orig); if (gssstat != GSS_S_COMPLETE) { - code = KADM5_GSS_ERROR; - goto error; + code = KADM5_GSS_ERROR; + goto error; } if (c_ccname_orig) ccname_orig = strdup(c_ccname_orig); else - ccname_orig = 0; + ccname_orig = 0; - input_name.value = full_service_name; - input_name.length = strlen((char *)input_name.value) + 1; - gssstat = gss_import_name(&minor_stat, &input_name, + buf.value = full_svcname; + buf.length = strlen((char *)buf.value) + 1; + gssstat = gss_import_name(&minor_stat, &buf, (gss_OID) gss_nt_krb5_name, &gss_target); if (gssstat != GSS_S_COMPLETE) { code = KADM5_GSS_ERROR; goto error; } - input_name.value = client_name; - input_name.length = strlen((char *)input_name.value) + 1; - gssstat = gss_import_name(&minor_stat, &input_name, + buf.value = client_name; + buf.length = strlen((char *)buf.value) + 1; + gssstat = gss_import_name(&minor_stat, &buf, (gss_OID) gss_nt_krb5_name, &gss_client); if (gssstat != GSS_S_COMPLETE) { code = KADM5_GSS_ERROR; @@ -493,105 +599,92 @@ static kadm5_ret_t _kadm5_init_any(char *client_name, gssstat = gss_acquire_cred(&minor_stat, gss_client, 0, GSS_C_NULL_OID_SET, GSS_C_INITIATE, &gss_client_creds, NULL, NULL); - (void) gss_release_name(&minor_stat, &gss_client); if (gssstat != GSS_S_COMPLETE) { code = KADM5_GSS_ERROR; goto error; } - - if (params_in != NULL && - (params_in->mask & KADM5_CONFIG_OLD_AUTH_GSSAPI)) { - handle->clnt->cl_auth = auth_gssapi_create(handle->clnt, - &gssstat, - &minor_stat, - gss_client_creds, - gss_target, - (gss_OID) gss_mech_krb5, - GSS_C_MUTUAL_FLAG - | GSS_C_REPLAY_FLAG, - 0, - NULL, - NULL, - NULL); - } else if (params_in == NULL || - !(params_in->mask & KADM5_CONFIG_NO_AUTH)) { - struct rpc_gss_sec sec; - sec.mech = gss_mech_krb5; - sec.qop = GSS_C_QOP_DEFAULT; - sec.svc = RPCSEC_GSS_SVC_PRIVACY; - sec.cred = gss_client_creds; - sec.req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG; - handle->clnt->cl_auth = authgss_create(handle->clnt, - gss_target, &sec); - } - (void) gss_release_name(&minor_stat, &gss_target); + /* + * Do actual creation of RPC auth handle. Implements auth flavor + * fallback. + */ + kadm5_rpc_auth(handle, params_in, gss_client_creds, gss_target); + +error: + if (gss_client_creds != GSS_C_NO_CREDENTIAL) + (void) gss_release_cred(&minor_stat, &gss_client_creds); + if (gss_client) + gss_release_name(&minor_stat, &gss_client); + if (gss_target) + gss_release_name(&minor_stat, &gss_target); + + /* Revert to prior gss_krb5 ccache. */ if (ccname_orig) { gssstat = gss_krb5_ccache_name(&minor_stat, ccname_orig, NULL); if (gssstat) { - code = KADM5_GSS_ERROR; - goto error; + return KADM5_GSS_ERROR; } free(ccname_orig); } else { gssstat = gss_krb5_ccache_name(&minor_stat, NULL, NULL); if (gssstat) { - code = KADM5_GSS_ERROR; - goto error; + return KADM5_GSS_ERROR; } } - - if (handle->clnt->cl_auth == NULL) { - code = KADM5_GSS_ERROR; - goto error; - } - r = init_1(&handle->api_version, handle->clnt); - if (r == NULL) { - code = KADM5_RPC_ERROR; -#ifdef DEBUG - clnt_perror(handle->clnt, "init_1 null resp"); -#endif - goto error; - } - if (r->code) { - code = r->code; - goto error; + if (handle->clnt->cl_auth == NULL) { + return KADM5_GSS_ERROR; } + return 0; +} - *server_handle = (void *) handle; - - if (init_type != INIT_CREDS) - krb5_cc_close(handle->context, ccache); +/* + * kadm5_rpc_auth + * + * Create RPC auth handle. Do auth flavor fallback if needed. + */ +static void +kadm5_rpc_auth(kadm5_server_handle_t handle, + kadm5_config_params *params_in, + gss_cred_id_t gss_client_creds, + gss_name_t gss_target) +{ + OM_uint32 gssstat, minor_stat; + struct rpc_gss_sec sec; - goto cleanup; - -error: - /* - * Note that it is illegal for this code to execute if "handle" - * has not been allocated and initialized. I.e., don't use "goto - * error" before the block of code at the top of the function - * that allocates and initializes "handle". - */ - if (handle->cache_name) - free(handle->cache_name); - if (handle->destroy_cache && ccache) - krb5_cc_destroy(handle->context, ccache); - if(handle->clnt && handle->clnt->cl_auth) - AUTH_DESTROY(handle->clnt->cl_auth); - if(handle->clnt) - clnt_destroy(handle->clnt); + /* Allow unauthenticated option for testing. */ + if (params_in != NULL && (params_in->mask & KADM5_CONFIG_NO_AUTH)) + return; -cleanup: - krb5_free_cred_contents(handle->context, &creds); - if (gss_client_creds != GSS_C_NO_CREDENTIAL) - (void) gss_release_cred(&minor_stat, &gss_client_creds); + /* Use RPCSEC_GSS by default. */ + if (params_in == NULL || + !(params_in->mask & KADM5_CONFIG_OLD_AUTH_GSSAPI)) { + sec.mech = gss_mech_krb5; + sec.qop = GSS_C_QOP_DEFAULT; + sec.svc = RPCSEC_GSS_SVC_PRIVACY; + sec.cred = gss_client_creds; + sec.req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG; - if (code) - free(handle); + handle->clnt->cl_auth = authgss_create(handle->clnt, + gss_target, &sec); + if (handle->clnt->cl_auth != NULL) + return; + } - return code; + if (params_in != NULL && (params_in->mask & KADM5_CONFIG_AUTH_NOFALLBACK)) + return; + + /* Fall back to old AUTH_GSSAPI. */ + handle->clnt->cl_auth = auth_gssapi_create(handle->clnt, + &gssstat, + &minor_stat, + gss_client_creds, + gss_target, + (gss_OID) gss_mech_krb5, + GSS_C_MUTUAL_FLAG + | GSS_C_REPLAY_FLAG, + 0, NULL, NULL, NULL); } kadm5_ret_t diff --git a/src/lib/kadm5/unit-test/ChangeLog b/src/lib/kadm5/unit-test/ChangeLog index 7b54c00cc..4b0777e89 100644 --- a/src/lib/kadm5/unit-test/ChangeLog +++ b/src/lib/kadm5/unit-test/ChangeLog @@ -1,3 +1,10 @@ +2005-02-10 Tom Yu + + * api.2/init-v2.exp: Handle improved error codes from + client_init.c. + (test152): Expect KRB5_FCC_NOFILE. + (test153): Expect KRB5_CC_NOTFOUND. + 2004-08-20 Tom Yu * Makefile.in (init-test): Don't use local copy of client_init.o diff --git a/src/tests/dejagnu/krb-standalone/ChangeLog b/src/tests/dejagnu/krb-standalone/ChangeLog index 8e0e4470d..5817ad3b5 100644 --- a/src/tests/dejagnu/krb-standalone/ChangeLog +++ b/src/tests/dejagnu/krb-standalone/ChangeLog @@ -1,3 +1,10 @@ +2005-02-10 Tom Yu + + * kadmin.exp (kadmin_add_rnd): Add "flags" arg, defaulting to + empty string. + (kadmin_test): Add test for fallback to kadmin/admin if + kadmin/fqdn is missing. + 2005-01-14 Tom Yu * kadmin.exp (kadmin_list): Check for communication failure. diff --git a/src/tests/dejagnu/krb-standalone/kadmin.exp b/src/tests/dejagnu/krb-standalone/kadmin.exp index c72548114..e3e39168d 100644 --- a/src/tests/dejagnu/krb-standalone/kadmin.exp +++ b/src/tests/dejagnu/krb-standalone/kadmin.exp @@ -128,7 +128,7 @@ proc kadmin_add { pname password } { # # Adds principal $pname with random key. Returns 1 on success. #-- -proc kadmin_add_rnd { pname } { +proc kadmin_add_rnd { pname { flags "" } } { global REALMNAME global KADMIN global KADMIN_LOCAL @@ -137,7 +137,7 @@ proc kadmin_add_rnd { pname } { global tmppwd set good 0 - spawn $KADMIN -p krbtest/admin@$REALMNAME -q "ank -randkey $pname" + spawn $KADMIN -p krbtest/admin@$REALMNAME -q "ank -randkey $flags $pname" expect_after { "Cannot contact any KDC" { fail "kadmin add rnd $pname lost KDC" @@ -952,6 +952,7 @@ proc kdestroy { } { # we get some sort of error. proc kadmin_test { } { + global hostname # Start up the kerberos and kadmind daemons if {![start_kerberos_daemons 0] } { @@ -1049,6 +1050,15 @@ proc kadmin_test { } { if { ![kadmin_list] } { return } + + # test fallback to kadmin/admin + if {![kadmin_delete kadmin/$hostname] \ + || ![kadmin_list] \ + || ![kadmin_add_rnd kadmin/$hostname -allow_tgs_req] \ + || ![kadmin_list]} { + return + } + verbose "kadmin_test succeeded" } -- 2.26.2