add kadm5_setkey_principal
authorBarry Jaspan <bjaspan@mit.edu>
Wed, 23 Apr 1997 19:53:16 +0000 (19:53 +0000)
committerBarry Jaspan <bjaspan@mit.edu>
Wed, 23 Apr 1997 19:53:16 +0000 (19:53 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@10072 dc483132-0cff-0310-8789-dd5450dbe970

22 files changed:
src/kadmin/cli/kadmin.c
src/kadmin/server/ChangeLog
src/kadmin/server/kadm_rpc_svc.c
src/kadmin/server/server_stubs.c
src/kadmin/testing/proto/ChangeLog
src/kadmin/testing/proto/kdc.conf.proto
src/kadmin/testing/util/ChangeLog
src/kadmin/testing/util/Makefile.in
src/lib/kadm5/ChangeLog
src/lib/kadm5/clnt/ChangeLog
src/lib/kadm5/clnt/client_principal.c
src/lib/kadm5/clnt/client_rpc.c
src/lib/kadm5/kadm_err.et
src/lib/kadm5/kadm_rpc.h
src/lib/kadm5/kadm_rpc_xdr.c
src/lib/kadm5/srv/ChangeLog
src/lib/kadm5/srv/server_acl.c
src/lib/kadm5/srv/server_acl.h
src/lib/kadm5/srv/svr_principal.c
src/lib/kadm5/unit-test/ChangeLog
src/lib/kadm5/unit-test/Makefile.in
src/lib/kadm5/unit-test/setkey-test.c [new file with mode: 0644]

index 1beed3e10319942ba73b7a35f144ba6aae7ff140..a4c1711f53e855887252fb06c5c4604e1dfb609b 100644 (file)
@@ -55,7 +55,8 @@ static struct pflag flags[] = {
 {"requires_hwauth",    15,     KRB5_KDB_REQUIRES_HW_AUTH,      0},
 {"needchange",         10,     KRB5_KDB_REQUIRES_PWCHANGE,     0},
 {"allow_svr",          9,      KRB5_KDB_DISALLOW_SVR,          1},
-{"password_changing_service",  25,     KRB5_KDB_PWCHANGE_SERVICE,      0 }
+{"password_changing_service",  25,     KRB5_KDB_PWCHANGE_SERVICE,      0 },
+{"support_desmd5",     14,     KRB5_KDB_SUPPORT_DESMD5,        0 }
 };
 
 static char *prflags[] = {
@@ -72,7 +73,9 @@ static char *prflags[] = {
     "UNKNOWN_0x00000400",      /* 0x00000400 */
     "UNKNOWN_0x00000800",      /* 0x00000800 */
     "DISALLOW_SVR",            /* 0x00001000 */
-    "PWCHANGE_SERVICE"         /* 0x00002000 */
+    "PWCHANGE_SERVICE",                /* 0x00002000 */
+    "SUPPORT_DESMD5",          /* 0x00004000 */
+    "NEW_PRINC",               /* 0x00008000 */
 };
 
 char *getenv();
index e36f94d8c9f5c5021d970b6017395b12bdc9cdef..ea9cbdb73e1d410e4e5bfea605c3e930f156bb42 100644 (file)
@@ -1,3 +1,7 @@
+Mon Mar 31 17:42:03 1997  Barry Jaspan  <bjaspan@mit.edu>
+
+       * kadm_rpc_svc.c, server_stubs.c: add support for setkey_principal
+
 Tue Feb  4 20:59:31 1997  Tom Yu  <tlyu@mit.edu>
 
        * Makefile.in:
index 9128821d5060ba2390d1974aa09b97278121ba8b..c4b6ebc598bf5f93f7c8c10bc5cbf5d0bdc815c6 100644 (file)
@@ -5,6 +5,9 @@
  * $Source$
  * 
  * $Log$
+ * Revision 1.13  1997/04/23 19:53:11  bjaspan
+ * add kadm5_setkey_principal
+ *
  * Revision 1.12  1996/07/22 20:28:53  marc
  * this commit includes all the changes on the OV_9510_INTEGRATION and
  * OV_MERGE branches.  This includes, but is not limited to, the new openvision
@@ -173,6 +176,12 @@ void kadm_1(rqstp, transp)
          xdr_result = xdr_generic_ret;
          local = (char *(*)()) chpass_principal_1;
          break;
+
+     case SETKEY_PRINCIPAL:
+         xdr_argument = xdr_setkey_arg;
+         xdr_result = xdr_generic_ret;
+         local = (char *(*)()) setkey_principal_1;
+         break;
          
      case CHRAND_PRINCIPAL:
          xdr_argument = xdr_chrand_arg;
@@ -223,7 +232,7 @@ void kadm_1(rqstp, transp)
          break;
 
      default:
-         krb5_klog_syslog(LOG_ERR, "Invalid OVSEC_KADM procedure number: %s, %d",
+         krb5_klog_syslog(LOG_ERR, "Invalid KADM5 procedure number: %s, %d",
                 inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr),
                 rqstp->rq_proc);
          svcerr_noproc(transp);
index 8107160afa34dfb7df7b971452d4fd678c5de197..1d04c03d93d92c0a331dcd75152543afe2a64058 100644 (file)
@@ -611,6 +611,61 @@ chpass_principal_1(chpass_arg *arg, struct svc_req *rqstp)
     return &ret;
 }
 
+generic_ret *
+setkey_principal_1(setkey_arg *arg, struct svc_req *rqstp)
+{
+    static generic_ret             ret;
+    char                           *prime_arg;
+    gss_buffer_desc                client_name,
+                                   service_name;
+    OM_uint32                      minor_stat;
+    kadm5_server_handle_t          handle;
+
+    xdr_free(xdr_generic_ret, &ret);
+
+    if (ret.code = new_server_handle(arg->api_version, rqstp, &handle))
+        return &ret;
+
+    if (ret.code = check_handle((void *)handle)) {
+        free_server_handle(handle);
+        return &ret;
+    }
+
+    ret.api_version = handle->api_version;
+
+    if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+        ret.code = KADM5_FAILURE;
+        return &ret;
+    }
+    krb5_unparse_name(handle->context, arg->princ, &prime_arg);
+
+    if (!(CHANGEPW_SERVICE(rqstp)) &&
+              acl_check(handle->context, rqstp->rq_clntcred,
+                        ACL_SETKEY, arg->princ)) {
+        ret.code = kadm5_setkey_principal((void *)handle, arg->princ,
+                                          arg->keyblocks, arg->n_keys);
+    } else {
+        krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_setkey_principal",
+               prime_arg, client_name.value, service_name.value,
+               inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+        ret.code = KADM5_AUTH_SETKEY;
+    }
+
+    if(ret.code != KADM5_AUTH_SETKEY) {
+       krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_setkey_principal", 
+              prime_arg, ((ret.code == 0) ? "success" :
+                          error_message(ret.code)), 
+              client_name.value, service_name.value,
+              inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+    }
+
+    free_server_handle(handle);
+    free(prime_arg);
+    gss_release_buffer(&minor_stat, &client_name);
+    gss_release_buffer(&minor_stat, &service_name);
+    return &ret;
+}
+
 chrand_ret *
 chrand_principal_1(chrand_arg *arg, struct svc_req *rqstp)
 {
index 1ee19274c80017b4502176be6bd42d1ca5d2a796..175aede603b6f4b297e4cd3ddb3627bb3a70856e 100644 (file)
@@ -1,3 +1,7 @@
+Mon Mar 31 17:42:33 1997  Barry Jaspan  <bjaspan@mit.edu>
+
+       * krb5.conf.proto: add support for setkey_principal (support more enctypes)
+
 Tue Oct 15 16:24:33 1996  Barry Jaspan  <bjaspan@mit.edu>
 
        * krb5.conf.proto: s/localhost/__LOCALHOST__/
index 1797b5a8e8dd9f641d1a9ad720e9e7c917ece08d..18cd5443841b6118192479f425a21910c6c8b378 100644 (file)
@@ -11,6 +11,6 @@
                dict_file = __K5ROOT__/ovsec_adm.dict
                kadmind_port = 1751
                master_key_type = des-cbc-crc
-               supported_enctypes = des-cbc-crc:normal des-cbc-crc:v4
+               supported_enctypes = des-cbc-crc:normal des-cbc-crc:v4 des-cbc-md5:normal des-cbc-raw:normal
        }
 
index f011d939a67210999b1c981e08f1eadc3ce1f12e..cb0960fba07034989366483ce276fc2ae83672ad 100644 (file)
@@ -1,3 +1,7 @@
+Mon Mar 31 17:43:06 1997  Barry Jaspan  <bjaspan@mit.edu>
+
+       * Makefile.in: be more verbose if Tcl is unavailable
+
 Wed Feb  5 22:57:53 1997  Tom Yu  <tlyu@mit.edu>
 
        * Makefile.in:
index cc58358366ddb125309aac94959c5798f061762b..6c6cf630b3836a49d4b1f8eafd3031dfeae54c01 100644 (file)
@@ -14,7 +14,9 @@ DO_ALL=@DO_ALL@
 all:: all-$(DO_ALL)
 
 all-::
-       @echo "Tcl is not installed on this system. The kadm5 test suite cannot be run."
+       @echo "+++"
+       @echo "+++ WARNING: Tcl not available.  The kadm5 tests will not be run."
+       @echo "+++"
 
 all-tcl:: $(CLNTPROG) $(SRVPROG)
 
index 2aa7cc99b06d295710a796c61bc09f7a8e1041d7..dc016db5746b0f1b8d766e4ae96f08df10ecd04a 100644 (file)
@@ -1,3 +1,8 @@
+Mon Mar 31 17:41:11 1997  Barry Jaspan  <bjaspan@mit.edu>
+
+       * kadm_err.et, kadm_rpc.h, kadm_rpc_xdr.c: add support for
+       setkey_principal
+
 Thu Jan 16 19:01:00 1997  Tom Yu  <tlyu@mit.edu>
 
        * Makefile.in (all-prerecurse): Update to use double-colon rules.
index 0497aba54b4cbbd66d7b18cd4aa749a623bb7db7..3635a324f262a260f5425d0e21c583dc035da7f3 100644 (file)
@@ -1,3 +1,8 @@
+Mon Mar 31 17:40:48 1997  Barry Jaspan  <bjaspan@mit.edu>
+
+       * client_principal.c, client_rpc.c: add support for
+       setkey_principal
+
 Sat Feb 22 01:35:19 1997  Sam Hartman  <hartmans@tertius.mit.edu>
 
        * Makefile.in (SHLIB_EXPDEPS): s/.so/$(SHLIBEXT)
index 14cd55d803431f9088c98a336c203c1845da317d..adcbb291f18c00f0eeaf6bb82d56ffc444e0aad4 100644 (file)
@@ -261,6 +261,31 @@ kadm5_chpass_principal(void *server_handle,
     return r->code;
 }
 
+kadm5_ret_t
+kadm5_setkey_principal(void *server_handle,
+                      krb5_principal princ,
+                      krb5_keyblock *keyblocks,
+                      int n_keys)
+{
+    setkey_arg         arg;
+    generic_ret                *r;
+    kadm5_server_handle_t handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    arg.princ = princ;
+    arg.keyblocks = keyblocks;
+    arg.n_keys = n_keys;
+    arg.api_version = handle->api_version;
+
+    if(princ == NULL || keyblocks == NULL)
+       return EINVAL;
+    r = setkey_principal_1(&arg, handle->clnt);
+    if(r == NULL)
+       return KADM5_RPC_ERROR;        
+    return r->code;
+}
+
 kadm5_ret_t
 kadm5_randkey_principal(void *server_handle,
                        krb5_principal princ,
index 547844a2c95e9497708225acf6628ae5041cbff0..ecb5943b36fd0d009903aa4267f9539f5620a6d5 100644 (file)
@@ -106,6 +106,20 @@ chpass_principal_1(argp, clnt)
        return (&res);
 }
 
+generic_ret *
+setkey_principal_1(argp, clnt)
+       setkey_arg *argp;
+       CLIENT *clnt;
+{
+       static generic_ret res;
+
+       memset((char *)&res, 0, sizeof(res));
+       if (clnt_call(clnt, SETKEY_PRINCIPAL, xdr_setkey_arg, argp, xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) {
+               return (NULL);
+       }
+       return (&res);
+}
+
 chrand_ret *
 chrand_principal_1(argp, clnt)
        chrand_arg *argp;
index fbddc237dcea4ed25673d94479259ca1d644b62b..a43a9b5576fd872cc92ff1fe4840d66ac4f7cc49 100644 (file)
@@ -54,4 +54,6 @@ error_code KADM5_GSS_ERROR, "GSS-API (or Kerberos) error"
 error_code KADM5_BAD_TL_TYPE, "Programmer error!  Illegal tagged data list type"
 error_code KADM5_MISSING_CONF_PARAMS, "Required parameters in kdc.conf missing"
 error_code KADM5_BAD_SERVER_NAME, "Bad krb5 admin server hostname"
+error_code KADM5_AUTH_SETKEY, "Operation requires ``set-key'' privilege"
+error_code KADM5_SETKEY_DUP_ENCTYPES, "Multiple values for single or folded enctype"
 end
index b0f97e6cb9033b04ed3c460ae7ef85ab63e56dd6..82bf3d57c96580e5cb69d895246a14b4aa114718 100644 (file)
@@ -66,6 +66,15 @@ struct chpass_arg {
 typedef struct chpass_arg chpass_arg;
 bool_t xdr_chpass_arg();
 
+struct setkey_arg {
+       krb5_ui_4 api_version;
+       krb5_principal princ;
+        krb5_keyblock *keyblocks;
+        int n_keys;
+};
+typedef struct setkey_arg setkey_arg;
+bool_t xdr_setkey_arg();
+
 struct chrand_arg {
        krb5_ui_4 api_version;
        krb5_principal princ;
@@ -202,4 +211,6 @@ extern generic_ret *init_1();
 extern gprincs_ret *get_princs_1();
 #define GET_POLS ((krb5_ui_4) 15)
 extern gpols_ret *get_pols_1();
+#define SETKEY_PRINCIPAL ((krb5_ui_4) 16)
+extern generic_ret *setkey_principal_1();
                    
index 67b94c921b572a96a179c4322e7005cafc45bbfb..fd253043d54a7f00e9bb4f5542ad77c8b36ba8cb 100644 (file)
@@ -585,6 +585,23 @@ xdr_chpass_arg(XDR *xdrs, chpass_arg *objp)
        return (TRUE);
 }
 
+bool_t
+xdr_setkey_arg(XDR *xdrs, setkey_arg *objp)
+{
+       if (!xdr_ui_4(xdrs, &objp->api_version)) {
+               return (FALSE);
+       }
+       if (!xdr_krb5_principal(xdrs, &objp->princ)) {
+               return (FALSE);
+       }
+       if (!xdr_array(xdrs, (caddr_t *) &objp->keyblocks,
+                      (unsigned int *) &objp->n_keys, ~0,
+                      sizeof(krb5_keyblock), xdr_krb5_keyblock)) {
+               return (FALSE);
+       }
+       return (TRUE);
+}
+
 bool_t
 xdr_chrand_arg(XDR *xdrs, chrand_arg *objp)
 {
index d462a0d773f168432001acfce6ccd87ad1d6abf6..fcca8b1a30b54257a149bfd0f93df94e9a65376e 100644 (file)
@@ -1,3 +1,8 @@
+Mon Mar 31 17:40:24 1997  Barry Jaspan  <bjaspan@mit.edu>
+
+       * server_acl.c, server_acl.h, svr_pricipal.c: add support for
+       setkey_principal
+
 Sun Mar  9 13:40:33 1997  Tom Yu  <tlyu@mit.edu>
 
        * svr_principal.c (add_to_history): Don't call realloc() on a NULL
index 6f5c01499b58229ae8140e168e2257791cd8ca46..35da5dd8083f41dea2dddb1f93023f55c1cb3cf1 100644 (file)
@@ -56,6 +56,7 @@ static const aop_t acl_op_table[] = {
     { 'c',     ACL_CHANGEPW },
     { 'i',     ACL_INQUIRE },
     { 'l',     ACL_LIST },
+    { 's',     ACL_SETKEY },
     { 'x',     ACL_ALL_MASK },
     { '*',     ACL_ALL_MASK },
     { '\0',    0 }
index 9dfc8daba7f67f96c0a8418b797503e0473d6496..4323d63190777f4fde6fe69c63f007999e97574f 100644 (file)
@@ -56,6 +56,7 @@
 #define        ACL_INQUIRE             32
 /* #define ACL_EXTRACT         64 */
 #define        ACL_LIST                128
+#define ACL_SETKEY             256
 #define        ACL_RENAME              (ACL_ADD+ACL_DELETE)
 
 #define        ACL_ALL_MASK            (ACL_ADD        | \
index 5ff1b4976d7791442a486ba3cb9a32b7ff0fe875..e7bfe039437ec84533467a51449f140b970dac70 100644 (file)
@@ -86,6 +86,21 @@ static krb5_tl_data *dup_tl_data(krb5_tl_data *tl)
      return n;
 }
 
+/* This is in lib/kdb/kdb_cpw.c, but is static */
+static void cleanup_key_data(context, count, data)
+   krb5_context          context;
+   int                   count;
+   krb5_key_data       * data;
+{
+     int i, j;
+     
+     for (i = 0; i < count; i++)
+         for (j = 0; j < data[i].key_data_ver; j++)
+              if (data[i].key_data_length[j])
+                   free(data[i].key_data_contents[j]);
+     free(data);
+}
+
 kadm5_ret_t
 kadm5_create_principal(void *server_handle,
                            kadm5_principal_ent_t entry, long mask,
@@ -1246,6 +1261,133 @@ done:
     return ret;
 }
 
+kadm5_ret_t
+kadm5_setkey_principal(void *server_handle,
+                      krb5_principal principal,
+                      krb5_keyblock *keyblocks,
+                      int n_keys)
+{
+    krb5_db_entry              kdb;
+    osa_princ_ent_rec          adb;
+    krb5_int32                 now;
+    kadm5_policy_ent_rec       pol;
+    krb5_key_data              *key_data;
+    int                                i, kvno, ret, last_pwd, have_pol = 0;
+    int                                deskeys;
+    kadm5_server_handle_t      handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    if (principal == NULL || keyblocks == NULL)
+       return EINVAL;
+    if (hist_princ && /* this will be NULL when initializing the databse */
+       ((krb5_principal_compare(handle->context,
+                                principal, hist_princ)) == TRUE))
+       return KADM5_PROTECT_PRINCIPAL;
+
+    for (i = 0, deskeys = 0; i < n_keys; i++) {
+      if (keyblocks[i].enctype == ENCTYPE_DES_CBC_MD4 ||
+         keyblocks[i].enctype == ENCTYPE_DES_CBC_MD5 ||
+         keyblocks[i].enctype == ENCTYPE_DES_CBC_RAW ||
+         keyblocks[i].enctype == ENCTYPE_DES_CBC_CRC)
+       deskeys++;
+      if (deskeys > 1)
+       return KADM5_SETKEY_DUP_ENCTYPES;
+    }
+
+    if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
+       return(ret);
+    
+    for (kvno = 0, i=0; i<kdb.n_key_data; i++)
+        if (kdb.key_data[i].key_data_kvno > kvno)
+             kvno = kdb.key_data[i].key_data_kvno;
+
+    if (kdb.key_data != NULL)
+        cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
+    
+    kdb.key_data = (krb5_key_data*)malloc(n_keys*sizeof(krb5_key_data));
+    if (kdb.key_data == NULL)
+        return ENOMEM;
+    memset(kdb.key_data, 0, n_keys*sizeof(krb5_key_data));
+    kdb.n_key_data = n_keys;
+
+    for (i = 0; i < n_keys; i++) {
+        if (ret = krb5_dbekd_encrypt_key_data(handle->context,
+                                              &master_encblock,
+                                              &keyblocks[i], NULL,
+                                              kvno + 1,
+                                              &kdb.key_data[i]))
+             return ret;
+    }
+
+    kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
+
+    if (ret = krb5_timeofday(handle->context, &now))
+       goto done;
+
+    if ((adb.aux_attributes & KADM5_POLICY)) {
+       if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
+                                   &pol)) != KADM5_OK) 
+          goto done;
+       have_pol = 1;
+
+#if 0
+       /*
+         * The spec says this check is overridden if the caller has
+         * modify privilege.  The admin server therefore makes this
+         * check itself (in chpass_principal_wrapper, misc.c).  A
+         * local caller implicitly has all authorization bits.
+         */
+       if (ret = krb5_dbe_lookup_last_pwd_change(handle->context,
+                                                 &kdb, &last_pwd))
+            goto done;
+       if((now - last_pwd) < pol.pw_min_life &&
+          !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
+            ret = KADM5_PASS_TOOSOON;
+            goto done;
+       }
+#endif
+#if 0
+       /*
+        * Should we be checking/updating pw history here?
+        */
+       if(pol.pw_history_num > 1) {
+           if(adb.admin_history_kvno != hist_kvno) {
+               ret = KADM5_BAD_HIST_KEY;
+               goto done;
+           }
+
+           if (ret = check_pw_reuse(handle->context,
+                                    &hist_encblock,
+                                    kdb.n_key_data, kdb.key_data,
+                                    adb.old_key_len, adb.old_keys))
+               goto done;
+       }
+#endif
+       
+       if (pol.pw_max_life)
+          kdb.pw_expiration = now + pol.pw_max_life;
+       else
+          kdb.pw_expiration = 0;
+    } else {
+       kdb.pw_expiration = 0;
+    }
+
+    if (ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now))
+        goto done;
+
+    if ((ret = kdb_put_entry(handle, &kdb, &adb)))
+       goto done;
+
+    ret = KADM5_OK;
+done:
+    kdb_free_entry(handle, &kdb, &adb);
+    if (have_pol)
+        kadm5_free_policy_ent(handle->lhandle, &pol);
+
+    return ret;
+}
+
 /*
  * Allocate an array of n_key_data krb5_keyblocks, fill in each
  * element with the results of decrypting the nth key in key_data with
index 7ec91fa001e2fc894e5991b6800bcc802df4f5d7..4401065c92cd3fc9aee581b74ffb415f4d3b4618 100644 (file)
@@ -1,3 +1,7 @@
+Mon Mar 31 17:39:52 1997  Barry Jaspan  <bjaspan@mit.edu>
+
+       * Makefile.in, setkey-test.c: add support for setkey
+
 Wed Mar 12 15:49:46 1997  Barry Jaspan  <bjaspan@mit.edu>
 
        * Makefile.in (unit-test-server-body): depend on test-randkey, not
index 656a6ea2bb07396c17842c91dc0b4b67c0bfabb9..dd0522c80245e7e21b0156977d079c14760f503f 100644 (file)
@@ -4,6 +4,7 @@ PROG_RPATH=$(KRB5_LIBDIR)
 
 all:: init-test destroy-test client-handle-test client-iter-test
 all:: randkey-test server-handle-test lock-test server-iter-test 
+all:: server-setkey-test client-setkey-test
 
 #
 # The client-side test programs.
@@ -28,6 +29,10 @@ client-iter-test: iter-test.o $(KADMLCNT_DEPLIBS) $(KRB5_BASE_DEPLIBS)
        $(CC_LINK) -o client-iter-test iter-test.o \
                $(KADMCLNT_LIBS) $(KRB5_BASE_LIBS)
 
+client-setkey-test: setkey-test.o $(KADMCLNT_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+       $(CC_LINK) -o client-setkey-test setkey-test.o \
+               $(KADMCLNT_LIBS) $(KRB5_BASE_LIBS)
+
 #
 # The server-side test programs.
 #
@@ -48,6 +53,13 @@ server-iter-test: iter-test.o $(KADMSRV_DEPLIBS) $(KRB5_BASE_DEPLIBS)
        $(CC_LINK) -o server-iter-test iter-test.o \
                $(KADMSRV_LIBS) $(KRB5_BASE_LIBS)
 
+setkey-test.o: $(SRCTOP)/lib/kadm5/unit-test/setkey-test.c
+       $(CC) $(CFLAGS) -UUSE_KADM5_API_VERSION -DUSE_KADM5_API_VERSION=2 -c $(SRCTOP)/lib/kadm5/unit-test/setkey-test.c
+
+server-setkey-test: setkey-test.o $(KADMSRV_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+       $(CC_LINK) -o server-setkey-test setkey-test.o \
+               $(KADMSRV_LIBS) $(KRB5_BASE_LIBS)
+
 #
 # The unit-test targets
 #
diff --git a/src/lib/kadm5/unit-test/setkey-test.c b/src/lib/kadm5/unit-test/setkey-test.c
new file mode 100644 (file)
index 0000000..e329fce
--- /dev/null
@@ -0,0 +1,212 @@
+#include <stdio.h>
+#include <krb5.h>
+#include <kadm5/admin.h>
+
+krb5_keyblock test1[] = {
+     0, ENCTYPE_DES_CBC_CRC, 0, 0,
+     -1,
+};
+krb5_keyblock test2[] = {
+     0, ENCTYPE_DES_CBC_RAW, 0, 0,
+     -1,
+};
+krb5_keyblock test3[] = {
+     0, ENCTYPE_DES_CBC_MD5, 0, 0,
+     -1,
+};
+
+krb5_keyblock *tests[] = { 
+  test1, test2, test3, NULL
+};
+
+int keyblocks_equal(krb5_keyblock *kb1, krb5_keyblock *kb2)
+{
+  return (kb1->enctype == kb2->enctype &&
+         kb1->length == kb2->length &&
+         memcmp(kb1->contents, kb2->contents, kb1->length) == 0);
+}
+
+krb5_data tgtname = {
+    0,
+    KRB5_TGS_NAME_SIZE,
+    KRB5_TGS_NAME
+};
+
+unsigned int ktypes[] = { 0, 0 };
+
+extern krb5_kt_ops krb5_ktf_writable_ops;
+
+main(int argc, char **argv)
+{
+  krb5_context context;
+  krb5_keytab kt;
+  krb5_keytab_entry ktent;
+  krb5_encrypt_block eblock;
+  krb5_creds my_creds;
+  kadm5_principal_ent_rec princ_ent;
+  krb5_principal princ, server;
+  char pw[16];
+  char *whoami, *principal, *authprinc;
+  krb5_data pwdata;
+  void *handle;
+  int ret, i, test, encnum;
+
+  whoami = argv[0];
+
+  if (argc != 2 && argc != 3) {
+    fprintf(stderr, "Usage: %s principal [authuser]\n", whoami);
+    exit(1);
+  }
+  principal = argv[1];
+  authprinc = argv[2] ? argv[2] : argv[0];
+
+  /*
+   * Setup.  Initialize data structures, open keytab, open connection
+   * to kadm5 server.
+   */
+
+  memset((char *) &context, 0, sizeof(context));
+  krb5_init_context(&context);
+
+  ret = krb5_parse_name(context, principal, &princ);
+  if (ret) {
+    com_err(whoami, ret, "while parsing principal name %s", principal);
+    exit(1);
+  }
+    
+  if((ret = krb5_build_principal_ext(context, &server,
+                                    krb5_princ_realm(kcontext, princ)->length,
+                                    krb5_princ_realm(kcontext, princ)->data,
+                                    tgtname.length, tgtname.data,
+                                    krb5_princ_realm(kcontext, princ)->length,
+                                    krb5_princ_realm(kcontext, princ)->data,
+                                    0))) {
+       com_err(whoami, ret, "while building server name");
+       exit(1);
+  }
+
+  /* register the WRFILE keytab type  */
+  if (ret = krb5_kt_register(context, &krb5_ktf_writable_ops)) {
+       com_err(whoami, ret,
+              "while registering writable key table functions");
+       exit(1);
+  }
+
+  ret = krb5_kt_default(context, &kt);
+  if (ret) {
+       com_err(whoami, ret, "while opening keytab");
+       exit(1);
+  }
+
+  ret = kadm5_init(authprinc, NULL, KADM5_ADMIN_SERVICE, NULL,
+                  KADM5_STRUCT_VERSION, KADM5_API_VERSION_2,
+                  &handle);
+  if (ret) {
+    com_err(whoami, ret, "while initializing connection");
+    exit(1);
+  }
+
+  /* these pw's don't need to be secure, just different every time */
+  srandom(getpid() ^ time(0));
+  pwdata.data = pw;
+  pwdata.length = sizeof(pw);
+  
+  /*
+   * For each test:
+   *
+   * For each enctype in the test, construct a random password/key.
+   * Assign all keys to principal with kadm5_setkey_principal.  Add
+   * each key to the keytab, and acquire an initial ticket with the
+   * keytab (XXX can I specify the enctype & kvno explicitly?).  If
+   * krb5_get_in_tkt_with_keytab succeeds, then the keys were set
+   * successfully.
+   */
+  for (test = 0; tests[test] != NULL; test++) {
+       krb5_keyblock *testp = tests[test];
+       printf("+ Test %d:\n", test);
+
+       for (encnum = 0; testp[encnum].magic != -1; encnum++) {
+           for (i = 0; i < sizeof(pw); i++)
+                pw[i] = (random() % 26) + '0'; /* XXX */
+
+           krb5_use_enctype(context, &eblock, testp[encnum].enctype);
+           if (ret = krb5_string_to_key(context, &eblock, &testp[encnum],
+                                        &pwdata, NULL)) {
+                com_err(whoami, ret, "while converting string to key");
+                exit(1);
+           }
+       }
+       
+       /* now, encnum == # of keyblocks in testp */
+       ret = kadm5_setkey_principal(handle, princ, testp, encnum);
+       if (ret) {
+           com_err(whoami, ret, "while setting keys");
+           exit(1);
+       }
+
+       ret = kadm5_get_principal(handle, princ, &princ_ent, KADM5_KVNO);
+       if (ret) {
+           com_err(whoami, ret, "while retrieving principal");
+           exit(1);
+       }
+
+       for (encnum = 0; testp[encnum].magic != -1; encnum++) {
+           printf("+   enctype %d\n", testp[encnum].enctype);
+                  
+           memset((char *) &ktent, 0, sizeof(ktent));
+           ktent.principal = princ;
+           ktent.key = testp[encnum];
+           ktent.vno = princ_ent.kvno;
+
+           ret = krb5_kt_add_entry(context, kt, &ktent);
+           if (ret) {
+                com_err(whoami, ret, "while adding keytab entry");
+                exit(1);
+           }
+
+           memset((char *)&my_creds, 0, sizeof(my_creds));
+           my_creds.client = princ;
+           my_creds.server = server;
+           
+           ktypes[0] = testp[encnum].enctype;
+           ret = krb5_get_in_tkt_with_keytab(context,
+                                             0 /* options */,
+                                             NULL /* addrs */,
+                                             ktypes,
+                                             NULL /* preauth */,
+                                             kt, 0,
+                                             &my_creds, 0);
+           if (ret) {
+                com_err(whoami, ret, "while acquiring initial ticket");
+                exit(1);
+           }
+
+           /* since I can't specify enctype explicitly ... */
+           ret = krb5_kt_remove_entry(context, kt, &ktent);
+           if (ret) {
+                com_err(whoami, ret, "while removing keytab entry");
+                exit(1);
+           }
+       }
+  }
+  
+  ret = krb5_kt_close(context, kt);
+  if (ret) {
+       com_err(whoami, ret, "while closing keytab");
+       exit(1);
+  }
+
+  ret = kadm5_destroy(handle);
+  if (ret) {
+       com_err(whoami, ret, "while closing kadmin connection");
+       exit(1);
+  }
+
+  return 0;
+}
+
+  
+  
+    
+    
+