Implement principal name and auth flavor fallback for kadm5 client
authorTom Yu <tlyu@mit.edu>
Fri, 11 Feb 2005 23:09:25 +0000 (23:09 +0000)
committerTom Yu <tlyu@mit.edu>
Fri, 11 Feb 2005 23:09:25 +0000 (23:09 +0000)
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
doc/kadm5/api-unit-test.tex
src/kadmin/testing/util/ChangeLog
src/kadmin/testing/util/tcl_kadm5.c
src/lib/kadm5/admin.h
src/lib/kadm5/clnt/ChangeLog
src/lib/kadm5/clnt/client_init.c
src/lib/kadm5/unit-test/ChangeLog
src/tests/dejagnu/krb-standalone/ChangeLog
src/tests/dejagnu/krb-standalone/kadmin.exp

index 0480c449d06eec1667d551acba94dd26a378d53d..c193325d7d6a375129ae6b798f8047de4c6d3a3c 100644 (file)
@@ -1,3 +1,8 @@
+2005-02-11  Tom Yu  <tlyu@mit.edu>
+
+       * 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  <raeburn@mit.edu>
 
        * implementor.texinfo (Porting Issues): New chapter with a bunch
index 3e3f6e2bf6b226953a4a67956543393b90a6ae1f..5b103278148e5b0e6fd47179fae95a85acebd329 100644 (file)
@@ -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}
index 868eeb98014ca9711c603b8dfedb67f0c83242fd..f34d8f83c30d0d3faf81ad6da915e07962f3a247 100644 (file)
@@ -1,3 +1,8 @@
+2005-02-10  Tom Yu  <tlyu@mit.edu>
+
+       * 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  <raeburn@mit.edu>
 
        * tcl_kadm5.c (parse_flags, parse_keysalts, parse_key_data,
index 21e029bd1ed2421d967a7987e82033c26cfccd52..a6b945277c72b9905c880f0d845550bf2396cbf9 100644 (file)
@@ -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;
 
index 866cfb0bb5888641e9e61417de7b1568d90e01be..4051601ecaa7ff0c7de6c77c304462a79958036c 100644 (file)
@@ -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
index 6d0a14ecd993252459398501ba9736404728fb74..fc2dfca2e3ed87c1d64a93abfe87184343aa18fe 100644 (file)
@@ -1,3 +1,13 @@
+2005-02-11  Tom Yu  <tlyu@mit.edu>
+
+       * 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  <tlyu@mit.edu>
 
        * client_init.c (_kadm5_init_any): Pass req_flags and cred to
index d3c63bde81a1a7efab145f7ac2109941d087914f..f1031548f14604b3ac76c4654675ce192efa766d 100644 (file)
@@ -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
index 7b54c00cc3bf5539c632ae8951604fb0bd0614ec..4b0777e89dc5767815d56a74405584f55b3f90a6 100644 (file)
@@ -1,3 +1,10 @@
+2005-02-10  Tom Yu  <tlyu@mit.edu>
+
+       * 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  <tlyu@mit.edu>
 
        * Makefile.in (init-test): Don't use local copy of client_init.o
index 8e0e4470d9b757abfec804633ba11799a15a0eac..5817ad3b5040a5435b49b08a2b8aa5383534e44e 100644 (file)
@@ -1,3 +1,10 @@
+2005-02-10  Tom Yu  <tlyu@mit.edu>
+
+       * 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  <tlyu@mit.edu>
 
        * kadmin.exp (kadmin_list): Check for communication failure.
index c72548114fdd5c4bc4d99894fd016da915c5b1c3..e3e39168dbae4645c07300b0b70b2533b605951b 100644 (file)
@@ -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"
 }