]> git.ipfire.org Git - thirdparty/krb5.git/commitdiff
Merge trunk at 22736
authorLuke Howard <lukeh@padl.com>
Sun, 13 Sep 2009 07:49:54 +0000 (07:49 +0000)
committerLuke Howard <lukeh@padl.com>
Sun, 13 Sep 2009 07:49:54 +0000 (07:49 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/users/lhoward/authdata@22737 dc483132-0cff-0310-8789-dd5450dbe970

127 files changed:
src/Makefile.in
src/clients/kinit/kinit.M
src/clients/kpasswd/ksetpwd.c
src/clients/kvno/kvno.M
src/clients/kvno/kvno.c
src/configure.in
src/include/k5-int.h
src/include/kdb.h
src/include/kdb_ext.h
src/include/krb5/krb5.hin
src/kadmin/cli/kadmin.c
src/kadmin/testing/scripts/env-setup.shin
src/kadmin/testing/util/tcl_kadm5.c
src/kdc/do_tgs_req.c
src/kdc/kdc_authdata.c
src/kdc/kdc_preauth.c
src/kdc/kdc_util.c
src/kdc/kdc_util.h
src/lib/crypto/Makefile.in
src/lib/crypto/builtin/Makefile.in
src/lib/crypto/builtin/aes/Makefile.in
src/lib/crypto/builtin/arcfour/Makefile.in
src/lib/crypto/builtin/des/Makefile.in
src/lib/crypto/builtin/enc_provider/Makefile.in [new file with mode: 0644]
src/lib/crypto/builtin/enc_provider/aes.c [new file with mode: 0644]
src/lib/crypto/builtin/enc_provider/deps [new file with mode: 0644]
src/lib/crypto/builtin/enc_provider/des.c [new file with mode: 0644]
src/lib/crypto/builtin/enc_provider/des3.c [new file with mode: 0644]
src/lib/crypto/builtin/enc_provider/enc_provider.h [new file with mode: 0644]
src/lib/crypto/builtin/enc_provider/rc4.c [new file with mode: 0644]
src/lib/crypto/builtin/md4/Makefile.in
src/lib/crypto/builtin/md5/Makefile.in
src/lib/crypto/builtin/sha1/Makefile.in
src/lib/crypto/crypto_tests/Makefile.in
src/lib/crypto/krb/Makefile.in
src/lib/crypto/krb/deps
src/lib/crypto/krb/hash_provider/hash_crc32.c
src/lib/crypto/krb/hash_provider/hash_md4.c
src/lib/crypto/krb/hash_provider/hash_md5.c
src/lib/crypto/krb/hash_provider/hash_sha1.c
src/lib/crypto/krb/yarrow/Makefile.in
src/lib/crypto/krb/yarrow/deps
src/lib/crypto/openssl/enc_provider/deps [new file with mode: 0644]
src/lib/crypto/openssl/enc_provider/des.c [new file with mode: 0644]
src/lib/crypto/openssl/enc_provider/des3.c [new file with mode: 0644]
src/lib/crypto/openssl/enc_provider/enc_provider.h [new file with mode: 0644]
src/lib/crypto/openssl/enc_provider/rc4.c [new file with mode: 0644]
src/lib/crypto/openssl/hmac.c [new file with mode: 0644]
src/lib/crypto/openssl/md4/deps [new file with mode: 0644]
src/lib/crypto/openssl/md4/md4.c [new file with mode: 0644]
src/lib/crypto/openssl/md4/rsa-md4.h [new file with mode: 0644]
src/lib/crypto/openssl/md5/deps [new file with mode: 0644]
src/lib/crypto/openssl/md5/md5.c [new file with mode: 0644]
src/lib/crypto/openssl/md5/rsa-md5.h [new file with mode: 0644]
src/lib/crypto/openssl/pbkdf2.c [new file with mode: 0644]
src/lib/crypto/openssl/sha1/deps [new file with mode: 0644]
src/lib/crypto/openssl/sha1/shs.c [new file with mode: 0644]
src/lib/crypto/openssl/sha1/shs.h [new file with mode: 0644]
src/lib/gssapi/generic/gssapi_ext.h
src/lib/gssapi/krb5/Makefile.in
src/lib/gssapi/krb5/accept_sec_context.c
src/lib/gssapi/krb5/acquire_cred.c
src/lib/gssapi/krb5/copy_ccache.c
src/lib/gssapi/krb5/gssapiP_krb5.h
src/lib/gssapi/krb5/gssapi_krb5.c
src/lib/gssapi/krb5/init_sec_context.c
src/lib/gssapi/krb5/krb5_gss_glue.c
src/lib/gssapi/krb5/s4u_gss_glue.c [new file with mode: 0644]
src/lib/gssapi/krb5/val_cred.c
src/lib/gssapi/libgssapi_krb5.exports
src/lib/gssapi/mechglue/Makefile.in
src/lib/gssapi/mechglue/g_accept_sec_context.c
src/lib/gssapi/mechglue/g_acquire_cred.c
src/lib/gssapi/mechglue/g_acquire_cred_imp_name.c [new file with mode: 0644]
src/lib/gssapi/mechglue/g_glue.c
src/lib/gssapi/mechglue/g_initialize.c
src/lib/gssapi/mechglue/g_set_context_option.c
src/lib/gssapi/mechglue/mglueP.h
src/lib/gssapi/spnego/gssapiP_spnego.h
src/lib/gssapi/spnego/spnego_mech.c
src/lib/kadm5/str_conv.c
src/lib/kadm5/unit-test/config/unix.exp
src/lib/kadm5/unit-test/lib/lib.t
src/lib/krb5/asn.1/asn1_k_decode.c
src/lib/krb5/asn.1/asn1_k_decode.h
src/lib/krb5/asn.1/asn1_k_encode.c
src/lib/krb5/asn.1/krb5_decode.c
src/lib/krb5/krb/Makefile.in
src/lib/krb5/krb/gc_frm_kdc.c
src/lib/krb5/krb/gc_via_tkt.c
src/lib/krb5/krb/get_creds.c
src/lib/krb5/krb/get_in_tkt.c
src/lib/krb5/krb/int-proto.h
src/lib/krb5/krb/kfree.c
src/lib/krb5/krb/preauth2.c
src/lib/krb5/krb/s4u_creds.c [new file with mode: 0644]
src/lib/krb5/krb/send_tgs.c
src/lib/krb5/krb/srv_dec_tkt.c
src/lib/krb5/libkrb5.exports
src/lib/krb5/os/sendto_kdc.c
src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c
src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c
src/slave/kproplog.c
src/tests/asn.1/krb5_decode_leak.c
src/tests/asn.1/krb5_decode_test.c
src/tests/asn.1/krb5_encode_test.c
src/tests/asn.1/ktest.c
src/tests/asn.1/ktest.h
src/tests/asn.1/ktest_equal.c
src/tests/asn.1/ktest_equal.h
src/tests/asn.1/reference_encode.out
src/tests/asn.1/trval_reference.out
src/tests/gssapi/Makefile.in
src/tests/gssapi/t_s4u.c [new file with mode: 0644]
src/tests/mk_migr/db2_backend/README_for_mkmdb2 [new file with mode: 0644]
src/tests/mk_migr/db2_backend/input_conf/kadm5_template_db2.acl [new file with mode: 0644]
src/tests/mk_migr/db2_backend/input_conf/kdc_template_db2.conf [new file with mode: 0644]
src/tests/mk_migr/db2_backend/input_conf/krb5_template_db2.conf [new file with mode: 0644]
src/tests/mk_migr/db2_backend/mkmdb2.py [new file with mode: 0644]
src/tests/mk_migr/ldap_backend/README_for_mkmldap [new file with mode: 0644]
src/tests/mk_migr/ldap_backend/input_conf/debconfile [new file with mode: 0644]
src/tests/mk_migr/ldap_backend/input_conf/kadm5_template_ldap.acl [new file with mode: 0644]
src/tests/mk_migr/ldap_backend/input_conf/kdc_template_ldap.conf [new file with mode: 0644]
src/tests/mk_migr/ldap_backend/input_conf/krb5_template_ldap.conf [new file with mode: 0644]
src/tests/mk_migr/ldap_backend/mkmldap.py [new file with mode: 0644]
src/util/collected-client-lib/Makefile.in
src/util/support/fake-addrinfo.c

index bd67ad677c58adbb9d4553673e5be131ab2206d7..d74e9e535c14eb387f5821a4dbfcf6cc1edd2f44 100644 (file)
@@ -195,7 +195,7 @@ WINMAKEFILES=Makefile \
        include\Makefile \
        lib\Makefile lib\crypto\Makefile \
        lib\crypto\krb\crc32\Makefile lib\crypto\builtin\des\Makefile \
-       lib\crypto\krb\dk\Makefile lib\crypto\krb\enc_provider\Makefile \
+       lib\crypto\krb\dk\Makefile lib\crypto\builtin\enc_provider\Makefile \
        lib\crypto\krb\hash_provider\Makefile \
        lib\crypto\krb\keyhash_provider\Makefile \
        lib\crypto\krb\raw\Makefile lib\crypto\old\Makefile \
@@ -268,7 +268,7 @@ WINMAKEFILES=Makefile \
 ##DOS##        $(WCONFIG) config < $@.in > $@
 ##DOS##lib\crypto\krb\dk\Makefile: lib\crypto\krb\dk\Makefile.in $(MKFDEP)
 ##DOS##        $(WCONFIG) config < $@.in > $@
-##DOS##lib\crypto\krb\enc_provider\Makefile: lib\crypto\krb\enc_provider\Makefile.in $(MKFDEP)
+##DOS##lib\crypto\builtin\enc_provider\Makefile: lib\crypto\builtin\enc_provider\Makefile.in $(MKFDEP)
 ##DOS##        $(WCONFIG) config < $@.in > $@
 ##DOS##lib\crypto\krb\hash_provider\Makefile: lib\crypto\krb\hash_provider\Makefile.in $(MKFDEP)
 ##DOS##        $(WCONFIG) config < $@.in > $@
@@ -395,7 +395,7 @@ FILES= ./* \
        config/* include/* include/kerberosIV/* \
        include/krb5/* include/krb5/stock/* include/sys/* lib/* \
        lib/crypto/* lib/crypto/krb/crc32/* lib/crypto/builtin/des/* lib/crypto/krb/dk/* \
-       lib/crypto/krb/enc_provider/* lib/crypto/krb/hash_provider/* \
+       lib/crypto/builtin/enc_provider/* lib/crypto/krb/hash_provider/* \
        lib/crypto/krb/keyhash_provider/* lib/crypto/krb/old/* lib/crypto/krb/raw/* \
        lib/crypto/builtin/sha1/* lib/crypto/builtin/arcfour/* lib/crypto/builtin/md4/* \
        lib/crypto/builtin/md5/* lib/crypto/krb/yarrow/* \
index fb5a47a2511d02505c94cadbf53a5bd240d07251..5b85772ac26be43b3f8b3f0dd42b6d287c456b8e 100644 (file)
@@ -35,9 +35,11 @@ kinit \- obtain and cache Kerberos ticket-granting ticket
 [\fB\-f\fP | \fB\-F\fP]
 [\fB\-a\fP]
 [\fB\-A\fP]
+[\fB\-C\fP]
+[\fB\-E\fP]
 [\fB\-v\fP] [\fB\-R\fP]
 [\fB\-k\fP [\fB\-t\fP \fIkeytab_file\fP]] [\fB\-c\fP \fIcache_name\fP]
-[\fB\-S\fP \fIservice_name\fP][\fB\-T\fP \fIarmor_ccache\fP] 
+[\fB\-S\fP \fIservice_name\fP][\fB\-T\fP \fIarmor_ccache\fP]
 [\fB\-X\fP \fIattribute\fP[=\fIvalue\fP]]
 [\fIprincipal\fP]
 .ad b
@@ -109,6 +111,12 @@ request tickets with the local address[es].
 .B \-A
 request address-less tickets.
 .TP
+.B \-C
+requests canonicalization of the principal name.
+.TP
+.B \-E
+treats the principal name as an enterprise name.
+.TP
 .B \-v
 requests that the ticket granting ticket in the cache (with the 
 .I invalid
index 45f782f08f9e1c1ffb357ae5af8e43dc7962d630..a489f06e3d2e0b88b733655a3e880de4b018b64a 100644 (file)
@@ -282,8 +282,6 @@ int main( int argc, char ** argv )
 /*
 ** change the password -
 */
-       fprintf( stderr, "the password is %s\n", new_password );
-
        {
                int pw_result;
                krb5_ccache ccache;
index b7e4d46a0da91b52af7e61d8cc25676951e03723..37b0bcbd53bfa8a4c0f139eb6f12d8da45eee276 100644 (file)
@@ -51,6 +51,13 @@ suppress printing
 .B \-h
 prints a usage statement and exits
 .TP
+.B \-P
+specifies that the
+.B service1 service2 ...
+arguments are to be treated as services for which credentials should
+be acquired using constrained delegation. This option is only valid
+when used in conjunction with protocol transition.
+.TP
 .B \-S sname
 specifies that krb5_sname_to_principal() will be used to build
 principal names.  If this flag is specified, the
@@ -59,6 +66,13 @@ arguments are interpreted as hostnames (rather than principal names),
 and
 .B sname
 is interpreted as the service name.
+.TP
+.B \-U for_user
+specifies that protocol transition (S4U2Self) is to be used to acquire
+a ticket on behalf of
+.B for_user.
+If constrained delegation is not requested, the service name
+must match the credentials cache client principal.
 .SH ENVIRONMENT
 .B Kvno
 uses the following environment variable:
index b98b85d30420b50a817d276f17dab13501b9c6f1..58702525f6127b9abdb8e97f43edc3482fc6ef47 100644 (file)
@@ -39,8 +39,9 @@ static char *prog;
 
 static void xusage()
 {
-    fprintf(stderr, "usage: %s [-C] [-u] [-c ccache] [-e etype] [-k keytab] [-S sname] service1 service2 ...\n",
-            prog);
+    fprintf(stderr, "usage: %s [-C] [-u] [-c ccache] [-e etype]\n", prog);
+    fprintf(stderr, "\t[-k keytab] [-S sname] [-U for_user [-P]]\n");
+    fprintf(stderr, "\tservice1 service2 ...\n");
     exit(1);
 }
 
@@ -48,7 +49,8 @@ int quiet = 0;
 
 static void do_v5_kvno (int argc, char *argv[], 
                         char *ccachestr, char *etypestr, char *keytab_name,
-                       char *sname, int canon, int unknown);
+                       char *sname, int canon, int unknown,
+                       char *for_user, int proxy);
 
 #include <com_err.h>
 static void extended_com_err_fn (const char *, errcode_t, const char *,
@@ -58,8 +60,8 @@ int main(int argc, char *argv[])
 {
     int option;
     char *etypestr = NULL, *ccachestr = NULL, *keytab_name = NULL;
-    char *sname = NULL;
-    int canon = 0, unknown = 0;
+    char *sname = NULL, *for_user = NULL;
+    int canon = 0, unknown = 0, proxy = 0;
 
 
     set_com_err_hook (extended_com_err_fn);
@@ -67,7 +69,7 @@ int main(int argc, char *argv[])
     prog = strrchr(argv[0], '/');
     prog = prog ? (prog + 1) : argv[0];
 
-    while ((option = getopt(argc, argv, "uCc:e:hk:qS:")) != -1) {
+    while ((option = getopt(argc, argv, "uCc:e:hk:qPS:U:")) != -1) {
        switch (option) {
        case 'C':
            canon = 1;
@@ -87,6 +89,9 @@ int main(int argc, char *argv[])
        case 'q':
            quiet = 1;
            break;
+       case 'P':
+           proxy = 1; /* S4U2Proxy - constrained delegation */
+           break;
        case 'S':
            sname = optarg;
             if (unknown == 1){ 
@@ -101,21 +106,37 @@ int main(int argc, char *argv[])
                xusage();
             }
             break;
+       case 'U':
+           for_user = optarg; /* S4U2Self - protocol transition */
+           break;
        default:
            xusage();
            break;
        }
     }
 
+    if (proxy) {
+       if (keytab_name == NULL) {
+           fprintf(stderr, "Option -P (constrained delegation) "
+                           "requires keytab to be specified\n");
+           xusage();
+       } else if (for_user == NULL) {
+           fprintf(stderr, "Option -P (constrained delegation) requires "
+                           "option -U (protocol transition)\n");
+           xusage();
+       }
+    }
+
     if ((argc - optind) < 1)
        xusage();
 
        do_v5_kvno(argc - optind, argv + optind,
-                  ccachestr, etypestr, keytab_name, sname, canon, unknown);
+                  ccachestr, etypestr, keytab_name, sname,
+                  canon, unknown, for_user, proxy);
     return 0;
 }
 
-#include <krb5.h>
+#include <k5-int.h>
 static krb5_context context;
 static void extended_com_err_fn (const char *myprog, errcode_t code,
                                 const char *fmt, va_list args)
@@ -130,17 +151,18 @@ static void extended_com_err_fn (const char *myprog, errcode_t code,
 
 static void do_v5_kvno (int count, char *names[], 
                         char * ccachestr, char *etypestr, char *keytab_name,
-                       char *sname, int canon, int unknown)
+                       char *sname, int canon, int unknown, char *for_user,
+                       int proxy)
 {
     krb5_error_code ret;
     int i, errors;
     krb5_enctype etype;
     krb5_ccache ccache;
     krb5_principal me;
-    krb5_creds in_creds, *out_creds;
-    krb5_ticket *ticket;
-    char *princ;
+    krb5_creds in_creds;
     krb5_keytab keytab = NULL;
+    krb5_principal for_user_princ = NULL;
+    krb5_flags options;
 
     ret = krb5_init_context(&context);
     if (ret) {
@@ -175,6 +197,16 @@ static void do_v5_kvno (int count, char *names[],
        }
     }
 
+    if (for_user) {
+       ret = krb5_parse_name_flags(context, for_user,
+                                   KRB5_PRINCIPAL_PARSE_ENTERPRISE,
+                                   &for_user_princ);
+       if (ret) {
+           com_err(prog, ret, "while parsing principal name %s", for_user);
+           exit(1);
+       }
+    }
+
     ret = krb5_cc_get_principal(context, ccache, &me);
     if (ret) {
        com_err(prog, ret, "while getting client principal name");
@@ -183,91 +215,131 @@ static void do_v5_kvno (int count, char *names[],
 
     errors = 0;
 
+    options = 0;
+    if (canon)
+       options |= KRB5_GC_CANONICALIZE;
+
     for (i = 0; i < count; i++) {
-       memset(&in_creds, 0, sizeof(in_creds));
+       krb5_principal server = NULL;
+       krb5_ticket *ticket = NULL;
+       krb5_creds *out_creds = NULL;
+       char *princ = NULL;
 
-       in_creds.client = me;
+       memset(&in_creds, 0, sizeof(in_creds));
 
        if (sname != NULL) {
            ret = krb5_sname_to_principal(context, names[i],
                                          sname, KRB5_NT_SRV_HST,
-                                         &in_creds.server);
+                                         &server);
        } else {
-           ret = krb5_parse_name(context, names[i], &in_creds.server);
+           ret = krb5_parse_name(context, names[i], &server);
        }
        if (ret) {
            if (!quiet)
                com_err(prog, ret, "while parsing principal name %s", names[i]);
-           errors++;
-           continue;
+           goto error;
        }
         if (unknown == 1) {
-            krb5_princ_type(context, in_creds.server) = KRB5_NT_UNKNOWN;
+            krb5_princ_type(context, server) = KRB5_NT_UNKNOWN;
         }
 
-       ret = krb5_unparse_name(context, in_creds.server, &princ);
+       ret = krb5_unparse_name(context, server, &princ);
        if (ret) {
            com_err(prog, ret,
                    "while formatting parsed principal name for '%s'",
                    names[i]);
-           errors++;
-           continue;
+           goto error;
        }
 
        in_creds.keyblock.enctype = etype;
 
-       ret = krb5_get_credentials(context, canon ? KRB5_GC_CANONICALIZE : 0,
-                                  ccache, &in_creds, &out_creds);
+       if (for_user) {
+           if (!proxy &&
+               !krb5_principal_compare(context, me, server)) {
+               com_err(prog, EINVAL,
+                       "client and server principal names must match");
+               goto error;
+           }
 
-       krb5_free_principal(context, in_creds.server);
+           in_creds.client = for_user_princ;
+           in_creds.server = me;
+
+           ret = krb5_get_credentials_for_user(context, options, ccache,
+                                               &in_creds, NULL, &out_creds);
+       } else {
+           in_creds.client = me;
+           in_creds.server = server;
+           ret = krb5_get_credentials(context, options, ccache,
+                                      &in_creds, &out_creds);
+       }
 
        if (ret) {
            com_err(prog, ret, "while getting credentials for %s", princ);
-
-           krb5_free_unparsed_name(context, princ);
-
-           errors++;
-           continue;
+           goto error;
        }
 
        /* we need a native ticket */
        ret = krb5_decode_ticket(&out_creds->ticket, &ticket);
        if (ret) {
            com_err(prog, ret, "while decoding ticket for %s", princ);
-           krb5_free_creds(context, out_creds);
-           krb5_free_unparsed_name(context, princ);
-
-           errors++;
-           continue;
+           goto error;
        }
-           
+
        if (keytab) {
            ret = krb5_server_decrypt_ticket_keytab(context, keytab, ticket);
            if (ret) {
-               if (!quiet)
-                   printf("%s: kvno = %d, keytab entry invalid", princ, ticket->enc_part.kvno);
+               if (!quiet) {
+                   fprintf(stderr, "%s: kvno = %d, keytab entry invalid\n",
+                           princ, ticket->enc_part.kvno);
+               }
                com_err(prog, ret, "while decrypting ticket for %s", princ);
-               krb5_free_ticket(context, ticket);
-               krb5_free_creds(context, out_creds);
-               krb5_free_unparsed_name(context, princ);
-
-               errors++;
-               continue;
+               goto error;
            }
            if (!quiet)
-               printf("%s: kvno = %d, keytab entry valid\n", princ, ticket->enc_part.kvno);
+               printf("%s: kvno = %d, keytab entry valid\n",
+                      princ, ticket->enc_part.kvno);
+           if (proxy) {
+               krb5_free_creds(context, out_creds);
+               out_creds = NULL;
+
+               in_creds.client = ticket->enc_part2->client;
+               in_creds.server = server;
+
+               ret = krb5_get_credentials_for_proxy(context,
+                                                    KRB5_GC_CANONICALIZE,
+                                                    ccache,
+                                                    &in_creds,
+                                                    ticket,
+                                                    &out_creds);
+               if (ret) {
+                   com_err(prog, ret,
+                           "%s: constrained delegation failed", princ);
+                   goto error;
+               }
+           }
        } else {
            if (!quiet)
                printf("%s: kvno = %d\n", princ, ticket->enc_part.kvno);
        }
 
-       krb5_free_creds(context, out_creds);
-       krb5_free_unparsed_name(context, princ);
+       continue;
+
+error:
+       if (server != NULL)
+           krb5_free_principal(context, server);
+       if (ticket != NULL)
+           krb5_free_ticket(context, ticket);
+       if (out_creds != NULL)
+           krb5_free_creds(context, out_creds);
+       if (princ != NULL)
+           krb5_free_unparsed_name(context, princ);
+       errors++;
     }
 
     if (keytab)
        krb5_kt_close(context, keytab);
     krb5_free_principal(context, me);
+    krb5_free_principal(context, for_user_princ);
     krb5_cc_close(context, ccache);
     krb5_free_context(context);
 
index 122d06abe8ac9ab6540b42df03b926bafa1511d3..6462e5272fa95a54d4df79321c5dfde12a34907f 100644 (file)
@@ -1,19 +1,19 @@
 K5_AC_INIT([aclocal.m4])
-dnl
-dnl autoconf 2.49 defaults to a /dev/null cache file, which is what we
-dnl do not want for performance reasons. 
+#
+# autoconf 2.49 defaults to a /dev/null cache file, which is what we
+# do not want for performance reasons. 
 if test "x$cache_file" = "x/dev/null"; then
   cache_file=./config.cache
   AC_CACHE_LOAD
 fi
-dnl
+
 CONFIG_RULES
 KRB5_VERSION=K5_VERSION
 AC_SUBST(KRB5_VERSION)
-dnl
-dnl
+
+
 AC_REQUIRE_CPP
-dnl
+
 AC_CACHE_CHECK(if va_copy is available, krb5_cv_va_copy,
 [AC_LINK_IFELSE([
 #include <stdarg.h>
@@ -31,10 +31,10 @@ int main()
 if test "$krb5_cv_va_copy" = yes; then
   AC_DEFINE(HAS_VA_COPY,1,[Define if va_copy macro or function is available.])
 fi
-dnl
-dnl Note that this isn't checking if the copied value *works*, just
-dnl whether the C language constraints permit the copying.  If
-dnl va_list is defined as an array type, it can't be assigned.
+
+# Note that this isn't checking if the copied value *works*, just
+# whether the C language constraints permit the copying.  If
+# va_list is defined as an array type, it can't be assigned.
 AC_CACHE_CHECK(if va_list objects can be copied by assignment,
               krb5_cv_va_simple_copy,
 [AC_COMPILE_IFELSE([
@@ -46,23 +46,23 @@ void f(va_list va2) {
 if test "$krb5_cv_va_simple_copy" = yes; then
   AC_DEFINE(CAN_COPY_VA_LIST,1,[Define if va_list objects can be simply copied by assignment.])
 fi
-dnl
-dnl The following lines are so that configure --help gives some global 
-dnl configuration options.
-dnl
+
+# The following lines are so that configure --help gives some global 
+# configuration options.
+
 KRB5_LIB_AUX
 AC_KRB5_TCL
 AC_ARG_ENABLE([athena],
 [  --enable-athena         build with MIT Project Athena configuration],,)
-dnl
-dnl Begin autoconf tests for the Makefiles generated out of the top-level
-dnl configure.in...
-dnl
+
+# Begin autoconf tests for the Makefiles generated out of the top-level
+# configure.in...
+
 AC_CHECK_FUNCS(memmove)
 KRB5_BUILD_LIBOBJS
 KRB5_BUILD_LIBRARY
 KRB5_BUILD_PROGRAM
-dnl for slave
+# for slave
 AC_TYPE_MODE_T
 AC_PROG_INSTALL
 KRB5_AC_NEED_DAEMON
@@ -73,7 +73,7 @@ AC_CHECK_LIB(util,main,[AC_DEFINE(HAVE_LIBUTIL,1,[Define if the util library is
 LIBUTIL=-lutil
 ])
 AC_SUBST(LIBUTIL)
-dnl for kdc
+# for kdc
 AC_CHECK_HEADERS(syslog.h stdarg.h sys/select.h sys/sockio.h ifaddrs.h unistd.h)
 AC_CHECK_FUNCS(openlog syslog closelog strftime vsprintf vasprintf vsnprintf)
 AC_CHECK_FUNCS(strlcpy)
@@ -100,68 +100,68 @@ KRB5_NEED_PROTO([#include <string.h>
 #include <stdlib.h>
 ],swab,1)
 KRB5_NEED_PROTO([#include <ctype.h>],isblank,1)
-dnl
+
 AC_PROG_AWK
 KRB5_AC_INET6
 KRB5_SOCKADDR_SA_LEN
 CHECK_SIGNALS
-dnl
-dnl --with-vague-errors disables useful error messages.
-dnl
+
+# --with-vague-errors disables useful error messages.
+
 AC_ARG_WITH([vague-errors],
-AC_HELP_STRING([--with-vague-errors],[Do not @<:@do@:>@ send helpful errors to client]), , withval=no)dnl
+AC_HELP_STRING([--with-vague-errors],[Do not @<:@do@:>@ send helpful errors to client]), , withval=no)
 if test "$withval" = yes; then
        AC_MSG_RESULT(Supplying vague error messages to KDC clients)
        AC_DEFINE(KRBCONF_VAGUE_ERRORS,1,[Define if the KDC should return only vague error codes to clients])
 fi
-dnl
-dnl WITH_CRYPTO_IMPL
-dnl
+
+# WITH_CRYPTO_IMPL
+
 CRYPTO_IMPL="builtin"
 AC_ARG_WITH([crypto-impl],
 AC_HELP_STRING([--with-crypto-impl=IMPL], [use specified crypto implementation @<:@builtin@:>@]),
 [CRYPTO_IMPL=$withval
 AC_MSG_RESULT("k5crypto will use \'$withval\'")
-], withval=builtin)dnl
+], withval=builtin)
 AC_SUBST(CRYPTO_IMPL)
-dnl
-dnl --with-kdc-kdb-update makes the KDC update the database with last request
-dnl information and failure information.
-dnl
+
+# --with-kdc-kdb-update makes the KDC update the database with last request
+# information and failure information.
+
 AC_ARG_WITH([kdc-kdb-update],
-AC_HELP_STRING([--with-kdc-kdb-update],[Update the database @<:@don't update@:>@]), , withval=no)dnl
+AC_HELP_STRING([--with-kdc-kdb-update],[Update the database @<:@don't update@:>@]), , withval=no)
 if test "$withval" = yes; then
        AC_MSG_RESULT(Updating KDC database with each request)
        AC_DEFINE(KRBCONF_KDC_MODIFIES_KDB,1,[Define if KDC should update database with each request])
 fi
-dnl
-dnl Needed for hw-preauth replay detection on KDC.
-dnl
-dnl USE_RCACHE enables the replay cache
-dnl NOCACHE disables the lookaside cache
-dnl
-dnl The lookaside cache is checked first; if *exactly* the same message
-dnl comes in twice, e.g., because the (legitimate) client resent it,
-dnl the previous response will be resent.  Otherwise, the replay cache
-dnl is used to check for attempts to fake out the KDC.  Some hardware
-dnl preauth methods are weak enough that we *really* want to have this
-dnl checking turned on.
-dnl
+
+# Needed for hw-preauth replay detection on KDC.
+
+# USE_RCACHE enables the replay cache
+# NOCACHE disables the lookaside cache
+
+# The lookaside cache is checked first; if *exactly* the same message
+# comes in twice, e.g., because the (legitimate) client resent it,
+# the previous response will be resent.  Otherwise, the replay cache
+# is used to check for attempts to fake out the KDC.  Some hardware
+# preauth methods are weak enough that we *really* want to have this
+# checking turned on.
+
 AC_ARG_ENABLE([kdc-replay-cache],
-AC_HELP_STRING([--enable-kdc-replay-cache],[check for replayed/retransmitted KDC requests (recommended when hardware preauthentication is in use) @<:@disabled@:>@]), , enableval=yes)dnl
+AC_HELP_STRING([--enable-kdc-replay-cache],[check for replayed/retransmitted KDC requests (recommended when hardware preauthentication is in use) @<:@disabled@:>@]), , enableval=yes)
 if test "$enableval" = yes ; then
        AC_DEFINE(USE_RCACHE,1,[Define if the KDC should use a replay cache])
 else
        AC_DEFINE(NOCACHE,1,[Define if the KDC should use no replay cache])
 fi
 KRB5_RUN_FLAGS
-dnl
+
 AC_TYPE_SIGNAL
-dnl
-dnl from old include/configure.in
+
+# from old include/configure.in
 AH_TEMPLATE([HAVE_STRUCT_SOCKADDR_STORAGE], 
 [Define if "struct sockaddr_storage" is available.])
-dnl
+
 AC_CONFIG_HEADERS(include/autoconf.h, [echo timestamp > include/autoconf.stamp])
 AC_PROG_INSTALL
 AC_PROG_AWK
@@ -169,7 +169,7 @@ AC_PROG_LEX
 AC_C_CONST
 AC_HEADER_DIRENT
 AC_CHECK_FUNCS(strdup setvbuf inet_ntoa inet_aton seteuid setresuid setreuid setegid setresgid setregid setsid flock fchmod chmod strftime strptime geteuid setenv unsetenv getenv gethostbyname2 getifaddrs gmtime_r localtime_r pthread_mutex_lock sched_yield bswap16 bswap64 mkstemp getusershell lstat access ftime getcwd srand48 srand srandom stat strchr strerror strerror_r strstr timezone umask waitpid sem_init sem_trywait daemon)
-dnl
+
 AC_CHECK_FUNC(mkstemp,
 [MKSTEMP_ST_OBJ=
 MKSTEMP_OBJ=],
@@ -179,7 +179,7 @@ EXTRA_SUPPORT_SYMS="$EXTRA_SUPPORT_SYMS krb5int_mkstemp"])
 AC_SUBST(MKSTEMP_OBJ)
 AC_SUBST(MKSTEMP_ST_OBJ)
 AC_SUBST(EXTRA_SUPPORT_SYMS)
-dnl
+
 AC_HEADER_STDARG
 DECLARE_SYS_ERRLIST
 AC_CHECK_HEADERS(unistd.h paths.h regex.h regexpr.h fcntl.h memory.h ifaddrs.h sys/filio.h sched.h byteswap.h machine/endian.h machine/byte_order.h sys/bswap.h endian.h pwd.h arpa/inet.h alloca.h dlfcn.h limits.h pthread.h semaphore.h krb_db.h kdc.h)
@@ -198,25 +198,25 @@ AC_CHECK_MEMBERS([struct stat.st_mtimensec,struct stat.st_mtimespec.tv_nsec,stru
 #include <sys/stat.h>])
 KRB5_AC_REGEX_FUNCS
 AC_TYPE_OFF_T
-dnl
-dnl Fancy caching of perror result...
+
+# Fancy caching of perror result...
 AC_MSG_CHECKING(for perror declaration)
 AC_CACHE_VAL(krb5_cv_decl_perror,
 [AC_EGREP_HEADER(perror, errno.h, 
-  krb5_cv_decl_perror=yes, krb5_cv_decl_perror=no)])dnl
+  krb5_cv_decl_perror=yes, krb5_cv_decl_perror=no)])
 AC_MSG_RESULT($krb5_cv_decl_perror)
 if test $krb5_cv_decl_perror = yes; then
        AC_DEFINE(HDR_HAS_PERROR,1,[Define if errno.h declares perror])
 fi
-dnl
+
 KRB5_NEED_PROTO([#include <time.h>],strptime)
 CHECK_WAIT_TYPE
 CHECK_SIGPROCMASK
 AC_TYPE_GETGROUPS
 CHECK_SETJMP
-dnl
-dnl *rpcent return types needed for lib/rpc
-dnl
+
+# *rpcent return types needed for lib/rpc
+
 AC_MSG_CHECKING([return type of setrpcent])
 AC_CACHE_VAL(k5_cv_type_setrpcent,
 [AC_TRY_COMPILE([#include <netdb.h>
@@ -224,10 +224,10 @@ AC_CACHE_VAL(k5_cv_type_setrpcent,
 extern "C"
 #endif
 extern void setrpcent();],
-[int i;], k5_cv_type_setrpcent=void, k5_cv_type_setrpcent=int)])dnl
+[int i;], k5_cv_type_setrpcent=void, k5_cv_type_setrpcent=int)])
 AC_MSG_RESULT($k5_cv_type_setrpcent)
 AC_DEFINE_UNQUOTED(SETRPCENT_TYPE, $k5_cv_type_setrpcent, [Define as return type of setrpcent])
-dnl
+
 AC_MSG_CHECKING([return type of endrpcent])
 AC_CACHE_VAL(k5_cv_type_endrpcent,
 [AC_TRY_COMPILE([#include <netdb.h>
@@ -235,12 +235,12 @@ AC_CACHE_VAL(k5_cv_type_endrpcent,
 extern "C"
 #endif
 extern void endrpcent();],
-[int i;], k5_cv_type_endrpcent=void, k5_cv_type_endrpcent=int)])dnl
+[int i;], k5_cv_type_endrpcent=void, k5_cv_type_endrpcent=int)])
 AC_MSG_RESULT($k5_cv_type_endrpcent)
 AC_DEFINE_UNQUOTED(ENDRPCENT_TYPE, $k5_cv_type_endrpcent, [Define as return type of endrpcent])
-dnl
-dnl
-dnl bswap_16 is a macro in byteswap.h under GNU libc
+
+
+# bswap_16 is a macro in byteswap.h under GNU libc
 AC_MSG_CHECKING(for bswap_16)
 AC_CACHE_VAL(krb5_cv_bswap_16,[
 AC_TRY_LINK([#if HAVE_BYTESWAP_H
@@ -259,9 +259,9 @@ AC_MSG_RESULT($krb5_cv_bswap_64)
 if test "$krb5_cv_bswap_64" = yes; then
   AC_DEFINE(HAVE_BSWAP_64,1,[Define to 1 if bswap_64 is available via byteswap.h])
 fi
-dnl
-dnl Needed for ksu and some appl stuff.
-dnl
+
+# Needed for ksu and some appl stuff.
+
 case $krb5_cv_host in
 alpha*-dec-osf*)
        AC_CHECK_LIB(security,setluid,
@@ -271,7 +271,7 @@ alpha*-dec-osf*)
        ;;
 esac
 AC_SUBST(KSU_LIBS)
-dnl
+
 if test $ac_cv_func_setenv = no || test $ac_cv_func_unsetenv = no \
   || test $ac_cv_func_getenv = no; then
   SETENVOBJ=setenv.o
@@ -279,9 +279,9 @@ else
   SETENVOBJ=
 fi
 AC_SUBST(SETENVOBJ)
-dnl
-dnl Check what the return types for gethostbyname_r and getservbyname_r are.
-dnl
+
+# Check what the return types for gethostbyname_r and getservbyname_r are.
+
 AC_CHECK_FUNC(gethostbyname_r,[
 ac_cv_func_gethostbyname_r=yes
 if test "$ac_cv_func_gethostbyname_r" = yes; then
@@ -314,7 +314,7 @@ if test "$ac_cv_func_gethostbyname_r" = yes; then
   AC_CHECK_FUNC(gethostbyaddr_r)
 fi
 ])
-dnl
+
 
 AC_CHECK_FUNC(getpwnam_r,ac_cv_func_getpwnam_r=yes,ac_cv_func_getpwnam_r=no)
 AC_CHECK_FUNC(getpwuid_r,ac_cv_func_getpwuid_r=yes,ac_cv_func_getpwuid_r=no)
@@ -436,23 +436,23 @@ if test "$ac_cv_func_getservbyname_r" = yes; then
   AC_CHECK_FUNC(getservbyport_r)
 fi
 ])
-dnl
+
 HAVE_YYLINENO
 CHECK_DIRENT
 AC_TYPE_UID_T
 AC_TYPE_MODE_T
-dnl
-AC_CHECK_HEADER(termios.h,dnl
-[AC_CHECK_FUNC([tcsetattr],dnl
+
+AC_CHECK_HEADER(termios.h,
+[AC_CHECK_FUNC([tcsetattr],
   AC_DEFINE(POSIX_TERMIOS,1,[Define if termios.h exists and tcsetattr exists]))])
-dnl
+
 KRB5_SIGTYPE
 AC_CHECK_HEADERS(stdlib.h string.h stddef.h sys/types.h sys/file.h sys/param.h sys/stat.h sys/time.h netinet/in.h sys/uio.h sys/filio.h sys/select.h time.h paths.h errno.h)
 AC_HEADER_STDARG
 KRB5_AC_INET6
-dnl
-dnl If compiling with IPv6 support, test if in6addr_any functions.
-dnl Irix 6.5.16 defines it, but lacks support in the C library.
+
+# If compiling with IPv6 support, test if in6addr_any functions.
+# Irix 6.5.16 defines it, but lacks support in the C library.
 if test $krb5_cv_inet6 = yes || test "$krb5_cv_inet6_with_dinet6" = yes ; then
 AC_CACHE_CHECK([for in6addr_any definition in library], 
   krb5_cv_var_in6addr_any,
@@ -473,11 +473,11 @@ AC_CACHE_CHECK([for in6addr_any definition in library],
   fi
 fi
 
-dnl
-dnl
-dnl check for ANSI stdio, esp "b" option to fopen().  This (unfortunately)
-dnl requires a run check...
-dnl
+
+
+# check for ANSI stdio, esp "b" option to fopen().  This (unfortunately)
+# requires a run check...
+
 AC_MSG_CHECKING([for ANSI stdio])
 AC_CACHE_VAL(krb5_cv_has_ansi_stdio,
 [AC_TRY_RUN(
@@ -492,19 +492,19 @@ int main()
   exit(0);
 }],
 krb5_cv_has_ansi_stdio=yes, krb5_cv_has_ansi_stdio=no,
-krb5_cv_has_ansi_stdio=yes)])dnl assume ANSI in cross environment
+krb5_cv_has_ansi_stdio=yes)])# assume ANSI in cross environment
 AC_MSG_RESULT($krb5_cv_has_ansi_stdio)
 if test $krb5_cv_has_ansi_stdio = yes; then
 AC_DEFINE(ANSI_STDIO,1,[Define if ANSI stdio is present (in particular "b" option to fopen)])
 fi
-dnl
-dnl then from osconf.h, we have
-dnl
+
+# then from osconf.h, we have
+
 AC_HEADER_TIME
 AC_CHECK_TYPE(time_t, long)
-dnl
-dnl Determine where to put the replay cache.
-dnl
+
+# Determine where to put the replay cache.
+
 AC_MSG_CHECKING([for replay cache directory])
 AC_CACHE_VAL(krb5_cv_sys_rcdir,
 [
@@ -512,12 +512,12 @@ for t_dir in /var/tmp /usr/tmp /var/usr/tmp /tmp ; do
        test -d $t_dir || continue
        krb5_cv_sys_rcdir=$t_dir
        break
-done])dnl
+done])
 AC_MSG_RESULT($krb5_cv_sys_rcdir)
 KRB5_RCTMPDIR=$krb5_cv_sys_rcdir
 AC_SUBST(KRB5_RCTMPDIR)
-dnl
-dnl
+
+
 AC_MSG_CHECKING(for socklen_t)
 AC_CACHE_VAL(krb5_cv_has_type_socklen_t,
 [AC_TRY_COMPILE(
@@ -529,7 +529,7 @@ AC_MSG_RESULT($krb5_cv_has_type_socklen_t)
 if test $krb5_cv_has_type_socklen_t = yes; then
     AC_DEFINE(HAVE_SOCKLEN_T,1,[Define if there is a socklen_t type. If not, probably use size_t])
 fi
-dnl
+
 AC_MSG_CHECKING(for struct lifconf)
 AC_CACHE_VAL(krb5_cv_has_struct_lifconf,
 [AC_TRY_COMPILE(
@@ -541,7 +541,7 @@ AC_MSG_RESULT($krb5_cv_has_struct_lifconf)
 if test $krb5_cv_has_struct_lifconf = yes; then
     AC_DEFINE(HAVE_STRUCT_LIFCONF,1,[Define if there is a struct lifconf.])
 fi
-dnl HP-UX 11 uses stuct if_laddrconf
+# HP-UX 11 uses stuct if_laddrconf
 AC_MSG_CHECKING(for struct if_laddrconf)
 AC_CACHE_VAL(krb5_cv_has_struct_if_laddrconf,
 [AC_TRY_COMPILE(
@@ -554,8 +554,8 @@ AC_MSG_RESULT($krb5_cv_has_struct_if_laddrconf)
 if test $krb5_cv_has_struct_if_laddrconf = yes; then
     AC_DEFINE(HAVE_STRUCT_IF_LADDRCONF,1,[Define if there is a struct if_laddrconf.])
 fi
-dnl
-dnl
+
+
 AC_MSG_CHECKING([for h_errno in netdb.h])
 AC_CACHE_VAL(krb5_cv_header_netdb_h_h_errno,
 [AC_TRY_COMPILE(
@@ -567,13 +567,13 @@ if test $krb5_cv_header_netdb_h_h_errno = yes; then
     AC_DEFINE([HAVE_NETDB_H_H_ERRNO], 1,
        [Define if netdb.h declares h_errno])
 fi
-dnl
-dnl
+
+
 AC_ARG_ENABLE([athena],
 [  --enable-athena         build with MIT Project Athena configuration],
 AC_DEFINE(KRB5_ATHENA_COMPAT,1,[Define if MIT Project Athena default configuration should be used]),)
 
-dnl
+
 AC_C_INLINE
 AH_TOP([
 #ifndef KRB5_AUTOCONF_H
@@ -586,9 +586,9 @@ AH_BOTTOM([
 #endif
 #endif /* KRB5_AUTOCONF_H */
 ])
-dnl
-dnl Not used yet, but let's find out what we've got on the platforms
-dnl we're working with....
+
+# Not used yet, but let's find out what we've got on the platforms
+# we're working with....
 AC_CHECK_HEADERS(inttypes.h stdint.h)
 AC_CHECK_TYPES([uint32_t, int32_t, uint64_t, int64_t, uint_least32_t, uintptr_t, uintmax_t, long long], , , [
 #ifdef HAVE_STDINT_H
@@ -607,19 +607,19 @@ AC_CHECK_TYPES([struct rt_msghdr], , , [
 #include <net/if.h>
 #include <net/route.h>
 ])
-dnl
-dnl stuff for util/profile
-dnl
-dnl AC_KRB5_TCL already done
+
+# stuff for util/profile
+
+# AC_KRB5_TCL already done
 DO_TCL=
 test "$TCL_LIBS" != "" && DO_TCL=ok
 AC_SUBST(DO_TCL)
-dnl
-dnl types libdb2 wants
-dnl
+
+# types libdb2 wants
+
 AC_CHECK_TYPES([ssize_t, u_char, u_int, u_long, u_int8_t, u_int16_t, u_int32_t, int8_t, int16_t, int32_t])
-dnl
-dnl Some libdb2 test programs want a shell that supports functions.
+
+# Some libdb2 test programs want a shell that supports functions.
 FCTSH=false
 AC_PATH_PROG(SH,sh,false)
 AC_PATH_PROG(SH5,sh5,false)
@@ -635,10 +635,10 @@ for prog in $SH $SH5 $BASH; do
   fi
 done
 AC_SUBST(FCTSH)
-dnl
-dnl Test for POSIX 2001 *printf support (X/Open System Interfaces extension
-dnl to ANSI/ISO C 1999 specification).  Specifically, positional
-dnl specifications; not checking for other features like %zx at present.
+
+# Test for POSIX 2001 *printf support (X/Open System Interfaces extension
+# to ANSI/ISO C 1999 specification).  Specifically, positional
+# specifications; not checking for other features like %zx at present.
 AC_MSG_CHECKING(for POSIX printf positional specification support)
 AC_CACHE_VAL(ac_cv_printf_positional,[
 AC_TRY_RUN([
@@ -657,19 +657,19 @@ int main () {
   ac_cv_printf_positional=yes,
   ac_cv_printf_positional=no,
   AC_MSG_ERROR([Cannot test for printf positional argument support when cross compiling]))])
-dnl Nothing for autoconf.h for now.
+# Nothing for autoconf.h for now.
 AC_MSG_RESULT($ac_cv_printf_positional)
-dnl
-dnl
-dnl for kadmin
-dnl
+
+
+# for kadmin
+
 AC_PROG_YACC
 ath_compat=
 AC_ARG_ENABLE([athena],
 [  --enable-athena         build with MIT Project Athena configuration],
 ath_compat=compat,)
-dnl The following are tests for the presence of programs required for
-dnl kadmin testing.
+# The following are tests for the presence of programs required for
+# kadmin testing.
 AC_CHECK_PROG(have_RUNTEST,runtest,runtest)
 AC_CHECK_PROG(have_PERL,perl,perl)
 AC_KRB5_TCL    
@@ -677,8 +677,8 @@ if test "$have_PERL" = perl -a "$have_RUNTEST" = runtest -a "$TCL_LIBS" != ""; t
        DO_TEST=ok
 fi
 AC_SUBST(DO_TEST) 
-dnl
-dnl The following are substituted into kadmin/testing/scripts/env-setup.sh
+
+# The following are substituted into kadmin/testing/scripts/env-setup.sh
 RBUILD=`pwd`
 AC_SUBST(RBUILD)
 case "$srcdir" in
@@ -688,18 +688,18 @@ esac
 AC_SUBST(S_TOP)
 AC_PATH_PROG(PERL_PATH,perl)
 AC_PATH_PROG(EXPECT,expect)
-dnl For kadmin/testing/util/Makefile.in
+# For kadmin/testing/util/Makefile.in
 if test "$TCL_LIBS" != "" ;  then
        DO_ALL=tcl
 fi
 AC_SUBST(DO_ALL)
 KRB5_AC_PRIOCNTL_HACK
 K5_GEN_FILE(kadmin/testing/scripts/env-setup.sh:kadmin/testing/scripts/env-setup.shin)
-dnl for lib/kadm5
+# for lib/kadm5
 AC_CHECK_PROG(RUNTEST,runtest,runtest)
 AC_CHECK_PROG(PERL,perl,perl)
-dnl
-dnl lib/gssapi
+
+# lib/gssapi
 AC_CHECK_HEADER(stdint.h,[
        include_stdint='awk '\''END{printf("%cinclude <stdint.h>\n", 35);}'\'' < /dev/null'],
        include_stdint='echo "/* no stdint.h */"')
@@ -712,24 +712,24 @@ AC_CHECK_HEADER(xom.h,[
        include_xom='awk '\''END{printf("%cinclude <xom.h>\n", 35);}'\'' < /dev/null'], [
        include_xom='echo "/* no xom.h */"'])
 AC_SUBST(include_xom)
-dnl
-dnl
-dnl lib/rpc
+
+
+# lib/rpc
 ### Check where struct rpcent is declared.
-#
+
 # This is necessary to determine:
 # 1. If /usr/include/netdb.h declares struct rpcent
 # 2. If /usr/include/rpc/netdb.h declares struct rpcent
-#
+
 # We have our own rpc/netdb.h, and if /usr/include/netdb.h includes
 # rpc/netdb.h, then nastiness could happen.
-#
+
 # Logic: If /usr/include/netdb.h declares struct rpcent, then check
 # rpc/netdb.h.  If /usr/include/rpc/netdb.h declares struct rpcent,
 # then define STRUCT_RPCENT_IN_RPC_NETDB_H, otherwise do not.  If
 # neither netdb.h nor rpc/netdb.h declares struct rpcent, then define
 # STRUCT_RPCENT_IN_RPC_NETDB_H anyway.
-#
+
 AC_MSG_CHECKING([where struct rpcent is declared])
 AC_TRY_COMPILE([#include <netdb.h>],
 [struct rpcent e;
@@ -847,9 +847,9 @@ else
   GSSRPC__BSD_TYPEALIASES='#define GSSRPC__BSD_TYPEALIASES 1'
 fi
 AC_SUBST(GSSRPC__BSD_TYPEALIASES)
-#
+
 # sockaddr length field checks
-#
+
 AC_CHECK_MEMBERS([struct sockaddr_in.sin_len], , ,
   [#include <sys/types.h>
 @%:@include <netinet/in.h>])
@@ -864,10 +864,10 @@ AC_CACHE_VAL(k5_cv_type_setrpcent,
 extern "C"
 #endif
 extern void setrpcent();],
-[int i;], k5_cv_type_setrpcent=void, k5_cv_type_setrpcent=int)])dnl
+[int i;], k5_cv_type_setrpcent=void, k5_cv_type_setrpcent=int)])
 AC_MSG_RESULT($k5_cv_type_setrpcent)
 AC_DEFINE_UNQUOTED(SETRPCENT_TYPE, $k5_cv_type_setrpcent, [Define as return type of setrpcent])
-dnl
+
 AC_MSG_CHECKING([return type of endrpcent])
 AC_CACHE_VAL(k5_cv_type_endrpcent,
 [AC_TRY_COMPILE([#include <netdb.h>
@@ -875,7 +875,7 @@ AC_CACHE_VAL(k5_cv_type_endrpcent,
 extern "C"
 #endif
 extern void endrpcent();],
-[int i;], k5_cv_type_endrpcent=void, k5_cv_type_endrpcent=int)])dnl
+[int i;], k5_cv_type_endrpcent=void, k5_cv_type_endrpcent=int)])
 AC_MSG_RESULT($k5_cv_type_endrpcent)
 AC_DEFINE_UNQUOTED(ENDRPCENT_TYPE, $k5_cv_type_endrpcent, [Define as return type of endrpcent])
 K5_GEN_FILE(include/gssrpc/types.h:include/gssrpc/types.hin)
@@ -891,7 +891,7 @@ esac
 changequote([, ])
 AC_SUBST(PASS)
 
-dnl for pkinit
+# for pkinit
 AC_ARG_ENABLE([pkinit],
 [  --disable-pkinit        disable PKINIT plugin support],,
 enable_pkinit=try)
@@ -916,10 +916,10 @@ else
   AC_MSG_NOTICE([Disabling PKINIT support.])
 fi
 
-dnl for lib/apputils
+# for lib/apputils
 AC_REPLACE_FUNCS(daemon)
 
-dnl for tests/
+# for tests/
 if test x"$RUNTEST" != x; then
        HAVE_RUNTEST=yes
 else
@@ -927,11 +927,11 @@ else
 fi
 AC_SUBST(HAVE_RUNTEST)
 
-dnl for plugins/kdb/db2
-dnl
-dnl AIX is unusual in that it wants all symbols resolved at link time
-dnl  Fortunately, it will allow us to link the kdb library now, even if
-dnl it is linked again later.
+# for plugins/kdb/db2
+
+# AIX is unusual in that it wants all symbols resolved at link time
+#  Fortunately, it will allow us to link the kdb library now, even if
+# it is linked again later.
 case $krb5_cv_host in
 *-*-aix*)
        DB_EXTRA_LIBS=-ldb
@@ -942,14 +942,14 @@ case $krb5_cv_host in
 esac
 AC_SUBST(DB_EXTRA_LIBS)
 
-dnl
-dnl
-dnl Check for thread safety issues.
-dnl (Is there a better place for this?)
-dnl tsfuncs="getpwnam_r getpwuid_r gethostbyname_r getservbyname_r gmtime_r localtime_r"
-dnl Removed getpwnam_r and getpwuid_r because include/configure.in has some
-dnl more careful checks, and may decide to pretend that they're not found if
-dnl the function signatures can't be figured out.
+
+
+# Check for thread safety issues.
+# (Is there a better place for this?)
+# tsfuncs="getpwnam_r getpwuid_r gethostbyname_r getservbyname_r gmtime_r localtime_r"
+# Removed getpwnam_r and getpwuid_r because include/configure.in has some
+# more careful checks, and may decide to pretend that they're not found if
+# the function signatures can't be figured out.
 tsfuncs="gethostbyname_r getservbyname_r gmtime_r localtime_r"
 AC_CHECK_FUNCS($tsfuncs)
 if test "$enable_thread_support" = yes; then
@@ -972,34 +972,34 @@ if test "$enable_thread_support" = yes; then
     AC_MSG_WARN([may not be thread-safe.])
   fi # tsmissing not empty
 fi # enable_thread_support
-dnl
-dnl Sadly, we seem to have accidentally committed ourselves in 1.4 to
-dnl an ABI that includes the existence of libkrb5support.0 even
-dnl though random apps should never use anything from it.  And on
-dnl the Mac, to which that didn't apply, we can't use major version 0.
-dnl
+
+# Sadly, we seem to have accidentally committed ourselves in 1.4 to
+# an ABI that includes the existence of libkrb5support.0 even
+# though random apps should never use anything from it.  And on
+# the Mac, to which that didn't apply, we can't use major version 0.
+
 case $krb5_cv_host in
 *-*-darwin* | *-*-rhapsody*) SUPPORTLIB_MAJOR=1 ;;
 *)                          SUPPORTLIB_MAJOR=0 ;;
 esac
 AC_SUBST(SUPPORTLIB_MAJOR)
-dnl
-dnl On the Mac we need CoreFoundation for UCS-2 conversion for RC4.
+
+# On the Mac we need CoreFoundation for UCS-2 conversion for RC4.
 case $krb5_cv_host in
 *-*-darwin* | *-*-rhapsody*) CRYPTO_LIBS="-framework CoreFoundation" ;;
 *)                          CRYPTO_LIBS="" ;;
 esac
 AC_SUBST(CRYPTO_LIBS)
-dnl
-dnl
+
+
 if test "$COM_ERR_VERSION" = k5 ; then
   K5_GEN_MAKEFILE(util/et)
 fi
 if test "$SS_VERSION" = k5 ; then
   K5_GEN_MAKEFILE(util/ss)
 fi
-dnl
-dnl
+
+
 ldap_plugin_dir=""
 ldap_lib=""
 if test -n "$OPENLDAP_PLUGIN"; then
@@ -1036,20 +1036,20 @@ fi
 AC_SUBST(ldap_plugin_dir)
 AC_SUBST(LDAP)
 
-dnl We really should look for and use python-config.
+# We really should look for and use python-config.
 PYTHON_LIB=
 AC_CHECK_HEADERS(Python.h python2.3/Python.h python2.5/Python.h)
 AC_CHECK_LIB(python2.3,main,[PYTHON_LIB=-lpython2.3],
   AC_CHECK_LIB(python2.5,main,[PYTHON_LIB=-lpython2.5]))
 AC_SUBST(PYTHON_LIB)
 
-dnl
-dnl Kludge for simple server --- FIXME is this the best way to do this?
-dnl
+
+# Kludge for simple server --- FIXME is this the best way to do this?
+
 if test "$ac_cv_lib_socket" = "yes" -a "$ac_cv_lib_nsl" = "yes"; then
        AC_DEFINE(BROKEN_STREAMS_SOCKETS,1,[Define if socket can't be bound to 0.0.0.0])
 fi
-dnl
+
 AC_CONFIG_SUBDIRS(appl/libpty appl/bsd appl/gssftp appl/telnet)
 
 AC_CONFIG_FILES(krb5-config, [chmod +x krb5-config])
@@ -1060,7 +1060,7 @@ V5_AC_OUTPUT_MAKEFILE(.
        lib lib/kdb
 
        lib/crypto lib/crypto/krb lib/crypto/krb/crc32 lib/crypto/builtin/des
-       lib/crypto/krb/dk lib/crypto/krb/enc_provider
+       lib/crypto/krb/dk lib/crypto/builtin/enc_provider
        lib/crypto/krb/hash_provider lib/crypto/krb/keyhash_provider
        lib/crypto/builtin lib/crypto/builtin/md4 lib/crypto/builtin/md5
        lib/crypto/krb/old lib/crypto/krb/raw lib/crypto/builtin/sha1
index 0578e6b63e866373c705156f9c9c3173f601c72f..bac2b0cfe9b130d9ff95522a043817246c492e8a 100644 (file)
@@ -675,6 +675,7 @@ struct krb5_enc_provider {
 };
 
 struct krb5_hash_provider {
+    char hash_name[8];
     size_t hashsize, blocksize;
 
     /* this takes multiple inputs to avoid lots of copying. */
@@ -965,6 +966,21 @@ typedef struct _krb5_pa_for_user {
     krb5_data          auth_package;
 } krb5_pa_for_user;
 
+typedef struct _krb5_s4u_userid {
+    krb5_int32         nonce;
+    krb5_principal     user;
+    krb5_data          subject_cert;
+    krb5_flags         options;
+} krb5_s4u_userid;
+
+#define KRB5_S4U_OPTS_CHECK_LOGON_HOURS                0x40000000 /* check logon hour restrictions */
+#define KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE      0x20000000 /* sign with usage 27 instead of 26 */
+
+typedef struct _krb5_pa_s4u_x509_user {
+    krb5_s4u_userid    user_id;
+    krb5_checksum      cksum;
+} krb5_pa_s4u_x509_user;
+
 enum {
   KRB5_FAST_ARMOR_AP_REQUEST = 0x1
 };
@@ -1299,6 +1315,10 @@ void KRB5_CALLCONV krb5_free_pa_enc_ts
        (krb5_context, krb5_pa_enc_ts *);
 void KRB5_CALLCONV krb5_free_pa_for_user
        (krb5_context, krb5_pa_for_user * );
+void KRB5_CALLCONV krb5_free_s4u_userid_contents
+       (krb5_context, krb5_s4u_userid * );
+void KRB5_CALLCONV krb5_free_pa_s4u_x509_user
+       (krb5_context, krb5_pa_s4u_x509_user * );
 void KRB5_CALLCONV krb5_free_pa_svr_referral_data
        (krb5_context, krb5_pa_svr_referral_data * );
 void KRB5_CALLCONV krb5_free_pa_server_referral_data
@@ -1708,6 +1728,12 @@ krb5_error_code encode_krb5_setpw_req
 krb5_error_code encode_krb5_pa_for_user
        (const krb5_pa_for_user * , krb5_data **);
 
+krb5_error_code encode_krb5_s4u_userid
+       (const krb5_s4u_userid * , krb5_data **);
+
+krb5_error_code encode_krb5_pa_s4u_x509_user
+       (const krb5_pa_s4u_x509_user * , krb5_data **);
+
 krb5_error_code encode_krb5_pa_svr_referral_data
        (const krb5_pa_svr_referral_data * , krb5_data **);
 
@@ -1880,6 +1906,9 @@ krb5_error_code decode_krb5_setpw_req
 krb5_error_code decode_krb5_pa_for_user
        (const krb5_data *, krb5_pa_for_user **);
 
+krb5_error_code decode_krb5_pa_s4u_x509_user
+       (const krb5_data *, krb5_pa_s4u_x509_user **);
+
 krb5_error_code decode_krb5_pa_svr_referral_data
        (const krb5_data *, krb5_pa_svr_referral_data **);
 
@@ -2711,6 +2740,11 @@ krb5_error_code krb5int_send_tgs
                krb5_pa_data * const *,
                const krb5_data *,
                krb5_creds *,
+               krb5_error_code (*gcvt_fct)(krb5_context,
+                                           krb5_keyblock *,
+                                           krb5_kdc_req *,
+                                           void *),
+               void *gcvt_data,
                krb5_response * , krb5_keyblock **subkey);
                 /* The subkey field is an output parameter; if a
                 * tgs-rep is received then the subkey will be filled
@@ -2914,6 +2948,21 @@ krb5int_pac_sign(krb5_context context,
                 const krb5_keyblock *privsvr_key,
                 krb5_data *data);
 
+krb5_error_code KRB5_CALLCONV
+krb5_get_credentials_for_user(krb5_context context, krb5_flags options,
+                             krb5_ccache ccache,
+                             krb5_creds *in_creds,
+                             krb5_data *cert,
+                             krb5_creds **out_creds);
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_credentials_for_proxy(krb5_context context,
+                              krb5_flags options,
+                              krb5_ccache ccache,
+                              krb5_creds *in_creds,
+                              krb5_ticket *evidence_tkt,
+                              krb5_creds **out_creds);
+
 krb5_error_code krb5int_parse_enctype_list(krb5_context context, char *profstr,
                                           krb5_enctype *default_list,
                                           krb5_enctype **result);
index ea81cfeef156cefe934b814445b0e38e0983d117..8c0cd247a2991f73fc84ff850830d98e65889550 100644 (file)
@@ -96,6 +96,8 @@
 #define KRB5_KDB_SUPPORT_DESMD5         0x00004000
 #define        KRB5_KDB_NEW_PRINC              0x00008000
 #define KRB5_KDB_OK_AS_DELEGATE                0x00100000
+#define KRB5_KDB_OK_TO_AUTH_AS_DELEGATE        0x00200000 /* S4U2Self OK */
+#define KRB5_KDB_NO_AUTH_DATA_REQUIRED 0x00400000
 
 /* Creation flags */
 #define KRB5_KDB_CREATE_BTREE          0x00000001
index 56959716974742e5f5847d676068c640e9651d55..384192005850affaa976658f9d62fbc1beee416b 100644 (file)
 #ifndef KRB5_KDB5_EXT__
 #define KRB5_KDB5_EXT__
 
-/* Allowed to use protocol transition */
-#define KRB5_KDB_OK_TO_AUTH_AS_DELEGATE        0x00200000
-/* Service does not require authorization data */
-#define KRB5_KDB_NO_AUTH_DATA_REQUIRED 0x00400000
 /* Private flag used to indicate principal is local TGS */
 #define KRB5_KDB_TICKET_GRANTING_SERVICE       0x01000000
 /* Private flag used to indicate xrealm relationship  is non-transitive */
index ea7475261ee850c32bd8fb5bf0161ea220bbd793..81bc1cf6e5dfa6b53f8e1502723a6fc3185ea597 100644 (file)
@@ -631,6 +631,11 @@ krb5_error_code KRB5_CALLCONV
 
 /* Defined in KDC referrals draft */
 #define KRB5_KEYUSAGE_PA_REFERRAL              26 /* XXX note conflict with above */
+
+/* Defined in [MS-SFU] */
+#define KRB5_KEYUSAGE_PA_S4U_X509_USER_REQUEST 26 /* XXX note conflict with above */
+#define KRB5_KEYUSAGE_PA_S4U_X509_USER_REPLY   27 /* XXX note conflict with above */
+
 /* define in draft-ietf-krb-wg-preauth-framework*/
 #define KRB5_KEYUSAGE_FAST_REQ_CHKSUM 50
 #define KRB5_KEYUSAGE_FAST_ENC 51
@@ -1566,6 +1571,10 @@ void KRB5_CALLCONV krb5_free_tgt_creds
 #define        KRB5_GC_USER_USER       1       /* want user-user ticket */
 #define        KRB5_GC_CACHED          2       /* want cached ticket only */
 #define        KRB5_GC_CANONICALIZE    4       /* set canonicalize KDC option */
+#define        KRB5_GC_NO_STORE        8       /* do not store in credentials cache */
+#define        KRB5_GC_FORWARDABLE             16  /* acquire forwardable tickets */
+#define        KRB5_GC_NO_TRANSIT_CHECK        32  /* disable transited check */
+#define        KRB5_GC_CONSTRAINED_DELEGATION  64  /* constrained delegation */
 
 krb5_error_code KRB5_CALLCONV krb5_get_credentials
        (krb5_context,
index 814ace35cc34d120ff1427d09eedc2828ca95686..513e716bbea6e6d9072b416b9f4ce9fbf7fc4981 100644 (file)
@@ -72,7 +72,9 @@ static struct pflag flags[] = {
 {"allow_svr", 9,       KRB5_KDB_DISALLOW_SVR, 1},
 {"password_changing_service",  25,     KRB5_KDB_PWCHANGE_SERVICE,      0 },
 {"support_desmd5",     14,     KRB5_KDB_SUPPORT_DESMD5,        0 },
-{"ok_as_delegate",     14,     KRB5_KDB_OK_AS_DELEGATE,        0 }
+{"ok_as_delegate",     14,     KRB5_KDB_OK_AS_DELEGATE,        0 },
+{"ok_to_auth_as_delegate", 22, KRB5_KDB_OK_TO_AUTH_AS_DELEGATE, 0 },
+{"no_auth_data_required", 21,  KRB5_KDB_NO_AUTH_DATA_REQUIRED, 0},
 };
 
 static char *prflags[] = {
@@ -97,6 +99,8 @@ static char *prflags[] = {
     "UNKNOWN_0x00040000",      /* 0x00040000 */
     "UNKNOWN_0x00080000",      /* 0x00080000 */
     "OK_AS_DELEGATE",          /* 0x00100000 */
+    "OK_TO_AUTH_AS_DELEGATE",  /* 0x00200000 */
+    "NO_AUTH_DATA_REQUIRED",   /* 0x00400000 */
 };
 
 char *getenv();
@@ -1123,7 +1127,7 @@ kadmin_addprinc_usage(func)
            "\t\tallow_postdated allow_forwardable allow_tgs_req allow_renewable\n",
            "\t\tallow_proxiable allow_dup_skey allow_tix requires_preauth\n",
            "\t\trequires_hwauth needchange allow_svr password_changing_service\n"
-           "\t\tok_as_delegate\n"
+           "\t\tok_as_delegate ok_to_auth_as_delegate no_auth_data_required\n"
            "\nwhere,\n\t[-x db_princ_args]* - any number of database specific arguments.\n"
            "\t\t\tLook at each database documentation for supported arguments\n");
 }
@@ -1140,7 +1144,7 @@ kadmin_modprinc_usage(func)
            "\t\tallow_postdated allow_forwardable allow_tgs_req allow_renewable\n",
            "\t\tallow_proxiable allow_dup_skey allow_tix requires_preauth\n",
            "\t\trequires_hwauth needchange allow_svr password_changing_service\n"
-           "\t\tok_as_delegate\n"
+           "\t\tok_as_delegate ok_to_auth_as_delegate no_auth_data_required\n"
            "\nwhere,\n\t[-x db_princ_args]* - any number of database specific arguments.\n"
            "\t\t\tLook at each database documentation for supported arguments\n"
        );
index 519b9864e188e4a00c7a69f14dc717e89ee6d102..be0715110400948a45d255fbf5b9de4b0fa0da5d 100755 (executable)
@@ -90,21 +90,15 @@ if [ "$TEST_PATH" != "" ]; then
 fi
 
 if [ "x$PS_ALL" = "x" ]; then
-       ps -axwwu >/dev/null 2>&1
-       ps_bsd=$?
-
-       ps -ef >/dev/null 2>&1
-       ps_sysv=$?
-
-       if [ $ps_bsd = 0 -a $ps_sysv = 1 ]; then
-               PS_ALL="ps -auxww"
-               PS_PID="ps -auxww"
-       elif [ $ps_bsd = 1 -a $ps_sysv = 0 ]; then
+       if ps auxww >/dev/null 2>&1; then
+               PS_ALL="ps auxww"
+               PS_PID="ps auxww"
+       elif ps -ef >/dev/null 2>&1; then
                PS_ALL="ps -ef"
                PS_PID="ps -fp"
        else
-               PS_ALL="ps -auxww"
-               PS_PID="ps -auxww"
+               PS_ALL="ps auxww"
+               PS_PID="ps auxww"
                echo "WARNING!  Cannot auto-detect ps type, assuming BSD."
        fi
 
index 15ae99fdde23add5a3de717ecbbce019c696c1d6..6679ce0a7c5e8b46e9e010e71831c23657d20b55 100644 (file)
@@ -2033,7 +2033,7 @@ static int tcl_kadm5_randkey_principal(ClientData clientData,
 
      ret = kadm5_randkey_principal(server_handle,
                                   princ, keyblock_var ? &keyblocks : 0,
-                                  num_var ? &num_keys : 0);
+                                  &num_keys);
 
      if (ret == KADM5_OK) {
          if (keyblock_var) {
index 8b1c47387b2ea4f7d9d45fa51ac55f265f3fdedf..48d8f3886e01cbb8826c87be5ddec96d6ed21ba0 100644 (file)
@@ -117,7 +117,7 @@ process_tgs_req(krb5_data *pkt, const krb5_fulladdr *from,
     krb5_enc_tkt_part *header_enc_tkt = NULL; /* ticket granting or evidence ticket */
     krb5_db_entry client, krbtgt;
     int c_nprincs = 0, k_nprincs = 0;
-    krb5_pa_for_user *for_user = NULL;           /* protocol transition request */
+    krb5_pa_s4u_x509_user *s4u_x509_user = NULL; /* protocol transition request */
     krb5_authdata **kdc_issued_auth_data = NULL; /* auth data issued by KDC */
     unsigned int c_flags = 0, s_flags = 0;       /* client/server KDB flags */
     char *s4u_name = NULL;
@@ -131,7 +131,7 @@ process_tgs_req(krb5_data *pkt, const krb5_fulladdr *from,
     krb5_data scratch;
 
     session_key.contents = NULL;
-    
+
     retval = decode_krb5_tgs_req(pkt, &request);
     if (retval)
         return retval;
@@ -292,12 +292,20 @@ tgt_again:
         !krb5_principal_compare(kdc_context, tgs_server, server.princ);
 
     /* Check for protocol transition */
-    errcode = kdc_process_s4u2self_req(kdc_context, request, header_enc_tkt->client,
-                                       &server, header_enc_tkt->session, kdc_time,
-                                       &for_user, &client, &c_nprincs, &status);
+    errcode = kdc_process_s4u2self_req(kdc_context,
+                                      request,
+                                      header_enc_tkt->client,
+                                       &server,
+                                      subkey,
+                                      header_enc_tkt->session,
+                                      kdc_time,
+                                       &s4u_x509_user,
+                                      &client,
+                                      &c_nprincs,
+                                      &status);
     if (errcode)
         goto cleanup;
-    if (for_user != NULL)
+    if (s4u_x509_user != NULL)
         setflag(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION);
 
     /*
@@ -438,19 +446,32 @@ tgt_again:
     /* processing of any of these flags.  For example, some */
     /* realms may refuse to issue renewable tickets         */
 
-    if (isflagset(request->kdc_options, KDC_OPT_FORWARDABLE))
+    if (isflagset(request->kdc_options, KDC_OPT_FORWARDABLE)) {
         setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
-    if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION)) {
-        if (!krb5_is_tgs_principal(server.princ) &&
-            is_local_principal(server.princ)) {
-            if (isflagset(server.attributes, KRB5_KDB_OK_TO_AUTH_AS_DELEGATE))
-                setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
-            else
+
+        if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION)) {
+            /*
+             * If S4U2Self principal is not forwardable, then mark ticket as
+             * unforwardable. This behaviour matches Windows, but it is
+             * different to the MIT AS-REQ path, which returns an error
+             * (KDC_ERR_POLICY) if forwardable tickets cannot be issued.
+             *
+             * Consider this block the S4U2Self equivalent to
+             * validate_forwardable().
+             */
+            if (c_nprincs &&
+                isflagset(client.attributes, KRB5_KDB_DISALLOW_FORWARDABLE))
+                clear(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
+            /*
+             * OK_TO_AUTH_AS_DELEGATE must be set on the service requesting
+             * S4U2Self in order for forwardable tickets to be returned.
+             */
+            else if (!is_referral &&
+                !isflagset(server.attributes, KRB5_KDB_OK_TO_AUTH_AS_DELEGATE))
                 clear(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
         }
-        if (isflagset(client.attributes, KRB5_KDB_DISALLOW_FORWARDABLE))
-            clear(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
     }
+
     if (isflagset(request->kdc_options, KDC_OPT_FORWARDED)) {
         setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDED);
 
@@ -560,7 +581,7 @@ tgt_again:
         enc_tkt_reply.times.starttime = 0;
 
     if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION)) {
-        errcode = krb5_unparse_name(kdc_context, for_user->user, &s4u_name);
+        errcode = krb5_unparse_name(kdc_context, s4u_x509_user->user_id.user, &s4u_name);
     } else if (isflagset(c_flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION)) {
         errcode = krb5_unparse_name(kdc_context, header_enc_tkt->client, &s4u_name);
     } else {
@@ -670,8 +691,8 @@ tgt_again:
     enc_tkt_reply.authorization_data = NULL;
 
     if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION) &&
-        is_local_principal(header_enc_tkt->client))
-        enc_tkt_reply.client = for_user->user;
+        !isflagset(c_flags, KRB5_KDB_FLAG_CROSS_REALM))
+        enc_tkt_reply.client = s4u_x509_user->user_id.user;
     else
         enc_tkt_reply.client = header_enc_tkt->client;
 
@@ -689,7 +710,8 @@ tgt_again:
                               &encrypting_key, /* U2U or server key */
                               pkt,
                               request,
-                              for_user ? for_user->user : NULL,
+                              s4u_x509_user ?
+                               s4u_x509_user->user_id.user : NULL,
                               header_enc_tkt,
                               &enc_tkt_reply);
     if (errcode) {
@@ -845,6 +867,20 @@ tgt_again:
     /* Start assembling the response */
     reply.msg_type = KRB5_TGS_REP;
     reply.padata = 0;/* always */
+    if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION) &&
+        find_pa_data(request->padata, KRB5_PADATA_S4U_X509_USER) != NULL) {
+        errcode = kdc_make_s4u2self_rep(kdc_context,
+                                        subkey,
+                                        header_ticket->enc_part2->session,
+                                        s4u_x509_user,
+                                        &reply,
+                                        &reply_encpart);
+        if (errcode) {
+            status = "KDC_RETURN_S4U2SELF_PADATA";
+            goto cleanup;
+        }
+    }
+
     reply.client = enc_tkt_reply.client;
     reply.enc_part.kvno = 0;/* We are using the session key */
     reply.ticket = &ticket_reply;
@@ -958,14 +994,18 @@ cleanup:
         krb5_db_free_principal(kdc_context, &krbtgt, k_nprincs);
     if (c_nprincs)
         krb5_db_free_principal(kdc_context, &client, c_nprincs);
-    if (for_user != NULL)
-        krb5_free_pa_for_user(kdc_context, for_user);
+    if (s4u_x509_user != NULL)
+        krb5_free_pa_s4u_x509_user(kdc_context, s4u_x509_user);
     if (kdc_issued_auth_data != NULL)
         krb5_free_authdata(kdc_context, kdc_issued_auth_data);
     if (s4u_name != NULL)
         free(s4u_name);
     if (subkey != NULL)
         krb5_free_keyblock(kdc_context, subkey);
+    if (reply.padata)
+        krb5_free_pa_data(kdc_context, reply.padata);
+    if (reply_encpart.enc_padata)
+        krb5_free_pa_data(kdc_context, reply_encpart.enc_padata);
 
     return retval;
 }
index 493e2397e7593a009f30840ff5d8f5fcd3ad291c..82f934f57f11e9ef65193e05e944b72a94ee88be 100644 (file)
@@ -549,9 +549,18 @@ handle_tgt_authdata (krb5_context context,
     }
 
     if (ad_nprincs != 0) {
+       /*
+        * This code was submitted by Novell; however there is no
+        * mention in [MS-SFU] of needing to examine the authorization
+        * data to clear the forwardable flag. My understanding is that
+        * the state of the forwardable flag is propagated through the
+        * cross-realm TGTs.
+        */
+#if 0
        if (isflagset(flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION) &&
            isflagset(ad_entry.attributes, KRB5_KDB_DISALLOW_FORWARDABLE))
            clear(enc_tkt_reply->flags, TKT_FLG_FORWARDABLE);
+#endif
 
        krb5_db_free_principal(context, &ad_entry, ad_nprincs);
 
index cc7ae34ed4ce2530dee9f25f4d6ae065985940c9..2149fd1ac2061b50ae998b489130e56322b7260c 100644 (file)
@@ -1348,25 +1348,6 @@ cleanup:
     return (retval);
 }
 
-static krb5_boolean
-enctype_requires_etype_info_2(krb5_enctype enctype)
-{
-    switch(enctype) {
-    case ENCTYPE_DES_CBC_CRC:
-    case ENCTYPE_DES_CBC_MD4:
-    case ENCTYPE_DES_CBC_MD5:
-    case ENCTYPE_DES3_CBC_SHA1:
-    case ENCTYPE_DES3_CBC_RAW:
-    case ENCTYPE_ARCFOUR_HMAC:
-    case ENCTYPE_ARCFOUR_HMAC_EXP :
-       return 0;
-    default:
-       if (krb5_c_valid_enctype(enctype))
-           return 1;
-       else return 0;
-    }
-}
-
 static krb5_boolean
 request_contains_enctype (krb5_context context,  const krb5_kdc_req *request,
                          krb5_enctype enctype)
index 8dd4f91dec549c4c989dfbbeebf878c89122dce0..9aada81329c23356b28f7cd5f3cef215b1548b08 100644 (file)
@@ -223,7 +223,7 @@ comp_cksum(krb5_context kcontext, krb5_data *source, krb5_ticket *ticket,
 krb5_pa_data *
 find_pa_data(krb5_pa_data **padata, krb5_preauthtype pa_type)
 {
-return krb5int_find_pa_data(kdc_context, padata, pa_type);
+    return krb5int_find_pa_data(kdc_context, padata, pa_type);
 }
 
 krb5_error_code 
@@ -371,7 +371,8 @@ kdc_process_tgs_req(krb5_kdc_req *request, const krb5_fulladdr *from,
     }
 
     /* make sure the client is of proper lineage (see above) */
-    if (foreign_server && !find_pa_data(request->padata, KRB5_PADATA_FOR_USER)) {
+    if (foreign_server &&
+       !find_pa_data(request->padata, KRB5_PADATA_FOR_USER)) {
        if (is_local_principal((*ticket)->enc_part2->client)) {
            /* someone in a foreign realm claiming to be local */
            krb5_klog_syslog(LOG_INFO, "PROCESS_TGS: failed lineage check");
@@ -926,7 +927,8 @@ fail:
  * as a com_err error number!
  */
 #define AS_INVALID_OPTIONS (KDC_OPT_FORWARDED | KDC_OPT_PROXY |\
-KDC_OPT_VALIDATE | KDC_OPT_RENEW | KDC_OPT_ENC_TKT_IN_SKEY)
+                           KDC_OPT_VALIDATE | KDC_OPT_RENEW | \
+                           KDC_OPT_ENC_TKT_IN_SKEY | KDC_OPT_CNAME_IN_ADDL_TKT)
 int
 validate_as_request(register krb5_kdc_req *request, krb5_db_entry client,
                    krb5_db_entry server, krb5_timestamp kdc_time,
@@ -998,17 +1000,9 @@ validate_as_request(register krb5_kdc_req *request, krb5_db_entry client,
      *    preauthentication data is absent in the request.
      *
      * Hence, this check most be done after the check for preauth
-     * data, and is now performed by validate_forwardable().
+     * data, and is now performed by validate_forwardable() (the
+     * contents of which were previously below).
      */
-#if 0
-    /* Client and server must allow forwardable tickets */
-    if (isflagset(request->kdc_options, KDC_OPT_FORWARDABLE) &&
-       (isflagset(client.attributes, KRB5_KDB_DISALLOW_FORWARDABLE) ||
-        isflagset(server.attributes, KRB5_KDB_DISALLOW_FORWARDABLE))) {
-       *status = "FORWARDABLE NOT ALLOWED";
-       return(KDC_ERR_POLICY);
-    }
-#endif
     
     /* Client and server must allow renewable tickets */
     if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE) &&
@@ -1795,7 +1789,7 @@ sign_db_authdata (krb5_context context,
 }
 
 static krb5_error_code
-verify_s4u2self_checksum(krb5_context context,
+verify_for_user_checksum(krb5_context context,
                         krb5_keyblock *key,
                         krb5_pa_for_user *req)
 {
@@ -1854,7 +1848,7 @@ verify_s4u2self_checksum(krb5_context context,
                                  &valid);
 
     if (code == 0 && valid == FALSE)
-       code = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+       code = KRB5KRB_AP_ERR_MODIFIED;
 
     free(data.data);
 
@@ -1862,55 +1856,246 @@ verify_s4u2self_checksum(krb5_context context,
 }
 
 /*
- * Protocol transition validation code based on AS-REQ
- * validation code
+ * Legacy protocol transition (Windows 2003 and above)
  */
-static int
-validate_s4u2self_request(krb5_kdc_req *request,
-                         const krb5_db_entry *client,
-                         krb5_timestamp kdc_time,
-                         const char **status)
+static krb5_error_code
+kdc_process_for_user(krb5_context context,
+                    krb5_pa_data *pa_data,
+                    krb5_keyblock *tgs_session,
+                    krb5_pa_s4u_x509_user **s4u_x509_user,
+                    const char **status)
 {
-    int                                errcode;
-    krb5_db_entry              server = { 0 };
-    /* The client must not be expired */
-    if (client->expiration && client->expiration < kdc_time) {
-       *status = "CLIENT EXPIRED";
-       return KDC_ERR_NAME_EXP;
+    krb5_error_code            code;
+    krb5_pa_for_user           *for_user;
+    krb5_data                  req_data;
+
+    req_data.length = pa_data->length;
+    req_data.data = (char *)pa_data->contents;
+
+    code = decode_krb5_pa_for_user(&req_data, &for_user);
+    if (code)
+       return code;
+
+    code = verify_for_user_checksum(context, tgs_session, for_user);
+    if (code) {
+       *status = "INVALID_S4U2SELF_CHECKSUM";
+       krb5_free_pa_for_user(kdc_context, for_user);
+       return code;
     }
 
-    /* The client's password must not be expired, unless the server is
-      a KRB5_KDC_PWCHANGE_SERVICE. */
-    if (client->pw_expiration && client->pw_expiration < kdc_time) {
-       *status = "CLIENT KEY EXPIRED";
-       return KDC_ERR_KEY_EXP;
+    *s4u_x509_user = calloc(1, sizeof(krb5_pa_s4u_x509_user));
+    if (*s4u_x509_user == NULL) {
+       krb5_free_pa_for_user(kdc_context, for_user);
+       return ENOMEM;
     }
 
+    (*s4u_x509_user)->user_id.user = for_user->user;
+    for_user->user = NULL;
+    krb5_free_pa_for_user(context, for_user);
+
+    return 0;
+}
+
+static krb5_error_code
+verify_s4u_x509_user_checksum(krb5_context context,
+                             krb5_keyblock *key,
+                             krb5_data *req_data,
+                             krb5_int32 kdc_req_nonce,
+                             krb5_pa_s4u_x509_user *req)
+{
+    krb5_error_code            code;
+    krb5_data                  scratch;
+    krb5_boolean               valid = FALSE;
+
+    if (enctype_requires_etype_info_2(key->enctype) &&
+       !krb5_c_is_keyed_cksum(req->cksum.checksum_type))
+       return KRB5KRB_AP_ERR_INAPP_CKSUM;
+
+    if (req->user_id.nonce != kdc_req_nonce)
+       return KRB5KRB_AP_ERR_MODIFIED;
+
     /*
-     * If the client requires password changing, then return an
-     * error; S4U2Self cannot be used to change a password.
+     * Verify checksum over the encoded userid. If that fails,
+     * re-encode, and verify that. This is similar to the
+     * behaviour in kdc_process_tgs_req().
      */
-    if (isflagset(client->attributes, KRB5_KDB_REQUIRES_PWCHANGE)) {
-       *status = "REQUIRED PWCHANGE";
-       return KDC_ERR_KEY_EXP;
+    if (fetch_asn1_field((unsigned char *)req_data->data, 1, 0, &scratch) < 0)
+       return ASN1_PARSE_ERROR;
+
+    code = krb5_c_verify_checksum(context,
+                                 key,
+                                 KRB5_KEYUSAGE_PA_S4U_X509_USER_REQUEST,
+                                 &scratch,
+                                 &req->cksum,
+                                 &valid);
+    if (code != 0)
+       return code;
+
+    if (valid == FALSE) {
+       krb5_data *data;
+
+       code = encode_krb5_s4u_userid(&req->user_id, &data);
+       if (code != 0)
+           return code;
+
+       code = krb5_c_verify_checksum(context,
+                                     key,
+                                     KRB5_KEYUSAGE_PA_S4U_X509_USER_REQUEST,
+                                     data,
+                                     &req->cksum,
+                                     &valid);
+
+       krb5_free_data(context, data);
+
+       if (code != 0)
+           return code;
     }
 
-    /* Check to see if client is locked out */
-    if (isflagset(client->attributes, KRB5_KDB_DISALLOW_ALL_TIX)) {
-       *status = "CLIENT LOCKED OUT";
-       return KDC_ERR_C_PRINCIPAL_UNKNOWN;
+    return valid ? 0 : KRB5KRB_AP_ERR_MODIFIED;
+}
+
+/*
+ * New protocol transition request (Windows 2008 and above)
+ */
+static krb5_error_code
+kdc_process_s4u_x509_user(krb5_context context,
+                         krb5_kdc_req *request,
+                         krb5_pa_data *pa_data,
+                         krb5_keyblock *tgs_subkey,
+                         krb5_keyblock *tgs_session,
+                         krb5_pa_s4u_x509_user **s4u_x509_user,
+                         const char **status)
+{
+    krb5_error_code            code;
+    krb5_data                  req_data;
+
+    req_data.length = pa_data->length;
+    req_data.data = (char *)pa_data->contents;
+
+    code = decode_krb5_pa_s4u_x509_user(&req_data, s4u_x509_user);
+    if (code)
+       return code;
+
+    code = verify_s4u_x509_user_checksum(context,
+                                        tgs_subkey ? tgs_subkey :
+                                           tgs_session,
+                                        &req_data,
+                                        request->nonce, *s4u_x509_user);
+
+    if (code) {
+       *status = "INVALID_S4U2SELF_CHECKSUM";
+       krb5_free_pa_s4u_x509_user(context, *s4u_x509_user);
+       *s4u_x509_user = NULL;
+       return code;
     }
 
+    if (krb5_princ_size(context, (*s4u_x509_user)->user_id.user) == 0 ||
+       (*s4u_x509_user)->user_id.subject_cert.length != 0) {
+       *status = "INVALID_S4U2SELF_REQUEST";
+       krb5_free_pa_s4u_x509_user(context, *s4u_x509_user);
+       *s4u_x509_user = NULL;
+       return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+    }
+
+    return 0;
+}
+
+krb5_error_code
+kdc_make_s4u2self_rep(krb5_context context,
+                     krb5_keyblock *tgs_subkey,
+                     krb5_keyblock *tgs_session,
+                     krb5_pa_s4u_x509_user *req_s4u_user,
+                     krb5_kdc_rep *reply,
+                     krb5_enc_kdc_rep_part *reply_encpart)
+{
+    krb5_error_code            code;
+    krb5_data                  *data = NULL;
+    krb5_pa_s4u_x509_user      rep_s4u_user;
+    krb5_pa_data               padata;
+    krb5_enctype               enctype;
+    krb5_keyusage              usage;
+
+    memset(&rep_s4u_user, 0, sizeof(rep_s4u_user));
+
+    rep_s4u_user.user_id.nonce   = req_s4u_user->user_id.nonce;
+    rep_s4u_user.user_id.user    = req_s4u_user->user_id.user;
+    rep_s4u_user.user_id.options =
+       req_s4u_user->user_id.options & KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE;
+
+    code = encode_krb5_s4u_userid(&rep_s4u_user.user_id, &data);
+    if (code != 0)
+        goto cleanup;
+
+    if (req_s4u_user->user_id.options & KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE)
+        usage = KRB5_KEYUSAGE_PA_S4U_X509_USER_REPLY;
+    else
+        usage = KRB5_KEYUSAGE_PA_S4U_X509_USER_REQUEST;
+
+    code = krb5_c_make_checksum(context, req_s4u_user->cksum.checksum_type,
+                               tgs_subkey != NULL ? tgs_subkey : tgs_session,
+                                usage, data,
+                                &rep_s4u_user.cksum);
+    if (code != 0)
+        goto cleanup;
+
+    krb5_free_data(context, data);
+    data = NULL;
+
+    code = encode_krb5_pa_s4u_x509_user(&rep_s4u_user, &data);
+    if (code != 0)
+        goto cleanup;
+
+    padata.magic = KV5M_PA_DATA;
+    padata.pa_type = KRB5_PADATA_S4U_X509_USER;
+    padata.length = data->length;
+    padata.contents = (krb5_octet *)data->data;
+
+    code = add_pa_data_element(context, &padata, &reply->padata, FALSE);
+    if (code != 0)
+       goto cleanup;
+
+    free(data);
+    data = NULL;
+
+    if (tgs_subkey != NULL)
+       enctype = tgs_subkey->enctype;
+    else
+       enctype = tgs_session->enctype;
+
     /*
-     * Check against local policy
+     * Owing to a bug in Windows, unkeyed checksums were used for older
+     * enctypes, including rc4-hmac. A forthcoming workaround for this
+     * includes the checksum bytes in the encrypted padata.
      */
-    errcode = against_local_policy_as(request, *client, server,
-                                     kdc_time, status); 
-    if (errcode)
-       return errcode;
+    if ((req_s4u_user->user_id.options & KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE) &&
+       enctype_requires_etype_info_2(enctype) == FALSE) {
+       padata.length = req_s4u_user->cksum.length +
+                       rep_s4u_user.cksum.length;
+       padata.contents = malloc(padata.length);
+       if (padata.contents == NULL) {
+           code = ENOMEM;
+           goto cleanup;
+       }
 
-    return 0;
+       memcpy(padata.contents,
+              req_s4u_user->cksum.contents,
+              req_s4u_user->cksum.length);
+       memcpy(&padata.contents[req_s4u_user->cksum.length],
+              rep_s4u_user.cksum.contents,
+              rep_s4u_user.cksum.length);
+
+       code = add_pa_data_element(context,&padata,
+                                  &reply_encpart->enc_padata, FALSE);
+       if (code != 0)
+           goto cleanup;
+    }
+
+cleanup:
+    if (rep_s4u_user.cksum.contents != NULL)
+        krb5_free_checksum_contents(context, &rep_s4u_user.cksum);
+    krb5_free_data(context, data);
+
+    return code;
 }
 
 /*
@@ -1921,92 +2106,116 @@ kdc_process_s4u2self_req(krb5_context context,
                         krb5_kdc_req *request,
                         krb5_const_principal client_princ,
                         const krb5_db_entry *server,
-                        krb5_keyblock *subkey,
+                        krb5_keyblock *tgs_subkey,
+                        krb5_keyblock *tgs_session,
                         krb5_timestamp kdc_time,
-                        krb5_pa_for_user **for_user,
+                        krb5_pa_s4u_x509_user **s4u_x509_user,
                         krb5_db_entry *princ,
                         int *nprincs,
                         const char **status)
 {
     krb5_error_code            code;
-    krb5_pa_data               **pa_data;
-    krb5_data                  req_data;
+    krb5_pa_data               *pa_data;
     krb5_boolean               more;
+    int                                flags;
 
     *nprincs = 0;
     memset(princ, 0, sizeof(*princ));
 
-    if (request->padata == NULL) {
-       return 0;
-    }
-
-    for (pa_data = request->padata; *pa_data != NULL; pa_data++) {
-       if ((*pa_data)->pa_type == KRB5_PADATA_FOR_USER)
-           break;
-    }
-    if (*pa_data == NULL) {
-       return 0;
+    pa_data = find_pa_data(request->padata, KRB5_PADATA_S4U_X509_USER);
+    if (pa_data != NULL) {
+       code = kdc_process_s4u_x509_user(context,
+                                        request,
+                                        pa_data,
+                                        tgs_subkey,
+                                        tgs_session,
+                                        s4u_x509_user,
+                                        status);
+       if (code != 0)
+           return code;
+    } else {
+       pa_data = find_pa_data(request->padata, KRB5_PADATA_FOR_USER);
+       if (pa_data != NULL) {
+           code = kdc_process_for_user(context,
+                                       pa_data,
+                                       tgs_session,
+                                       s4u_x509_user,
+                                       status);
+           if (code != 0)
+               return code;
+       } else
+           return 0;
     }
 
-#if 0
     /*
-     * Ignore request if the server principal is a TGS, not so much
-     * to avoid unconstrained tickets being issued (as that would
-     * require knowing the TGS key anyway) but so that we do not
-     * block the server referral path.
+     * We need to compare the client name in the TGT with the requested
+     * server name. Supporting server name aliases without assuming a
+     * global name service makes this difficult to do.
+     *
+     * The comparison below handles the following cases (note that the
+     * term "principal name" below excludes the realm).
+     *
+     * (1) The requested service is a host-based service with two name
+     *     components, in which case we assume the principal name to
+     *     contain sufficient qualifying information. The realm is
+     *     ignored for the purpose of comparison.
+     *
+     * (2) The requested service name is an enterprise principal name:
+     *     the service principal name is compared with the unparsed
+     *     form of the client name (including its realm).
+     *
+     * (3) The requested service is some other name type: an exact
+     *     match is required.
+     *
+     * An alternative would be to look up the server once again with
+     * FLAG_CANONICALIZE | FLAG_CLIENT_REFERRALS_ONLY set, do an exact
+     * match between the returned name and client_princ. However, this
+     * assumes that the client set FLAG_CANONICALIZE when requesting
+     * the TGT and that we have a global name service.
      */
-    if (krb5_is_tgs_principal(server->princ)) {
-       return 0;
-    }
-#endif
-
-    *status = "PROCESS_S4U2SELF_REQUEST";
-
-    req_data.length = (*pa_data)->length;
-    req_data.data = (char *)(*pa_data)->contents;
-
-    code = decode_krb5_pa_for_user(&req_data, for_user);
-    if (code) {
-       return code;
-    }
-
-    if (krb5_princ_type(context, (*for_user)->user) !=
-       KRB5_NT_ENTERPRISE_PRINCIPAL) {
-       *status = "INVALID_S4U2SELF_REQUEST";
-       return KRB5KDC_ERR_POLICY;
+    flags = 0;
+    switch (krb5_princ_type(kdc_context, request->server)) {
+    case KRB5_NT_SRV_HST:                  /* (1) */
+       if (krb5_princ_size(kdc_context, request->server) == 2)
+           flags |= KRB5_PRINCIPAL_COMPARE_IGNORE_REALM;
+       break;
+    case KRB5_NT_ENTERPRISE_PRINCIPAL:     /* (2) */
+       flags |= KRB5_PRINCIPAL_COMPARE_ENTERPRISE;
+       break;
+    default:                               /* (3) */
+       break;
     }
 
-    code = verify_s4u2self_checksum(context, subkey, *for_user);
-    if (code) {
-       *status = "INVALID_S4U2SELF_CHECKSUM";
-       krb5_free_pa_for_user(kdc_context, *for_user);
-       *for_user = NULL;
-       return code;
-    }
-    if (!krb5_principal_compare_flags(context, request->server, client_princ,
-                                     KRB5_PRINCIPAL_COMPARE_ENTERPRISE)) {
+    if (!krb5_principal_compare_flags(context,
+                                     request->server,
+                                     client_princ,
+                                     flags)) {
        *status = "INVALID_S4U2SELF_REQUEST";
-       return KRB5KDC_ERR_POLICY;
+       return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; /* match Windows error code */
     }
 
     /*
      * Protocol transition is mutually exclusive with renew/forward/etc
-     * as well as user-to-user and constrained delegation.
+     * as well as user-to-user and constrained delegation. This check
+     * is also made in validate_as_request().
      *
      * We can assert from this check that the header ticket was a TGT, as
      * that is validated previously in validate_tgs_request().
      */
-    if (request->kdc_options & (NO_TGT_OPTION | KDC_OPT_ENC_TKT_IN_SKEY | KDC_OPT_CNAME_IN_ADDL_TKT)) {
+    if (request->kdc_options & AS_INVALID_OPTIONS) {
+       *status = "INVALID AS OPTIONS";
        return KRB5KDC_ERR_BADOPTION;
     }
 
     /*
      * Do not attempt to lookup principals in foreign realms.
      */
-    if (is_local_principal((*for_user)->user)) {
+    if (is_local_principal((*s4u_x509_user)->user_id.user)) {
+       krb5_db_entry no_server;
+
        *nprincs = 1;
        code = krb5_db_get_principal_ext(kdc_context,
-                                        (*for_user)->user,
+                                        (*s4u_x509_user)->user_id.user,
                                         KRB5_KDB_FLAG_INCLUDE_PAC,
                                         princ, nprincs, &more);
        if (code) {
@@ -2023,14 +2232,15 @@ kdc_process_s4u2self_req(krb5_context context,
            return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
        }
 
-       code = validate_s4u2self_request(request, princ, kdc_time, status);
+       memset(&no_server, 0, sizeof(no_server));
+
+       code = validate_as_request(request, *princ,
+                                  no_server, kdc_time, status);
        if (code) {
            return code;
        }
     }
 
-    *status = NULL;
-
     return 0;
 }
 
@@ -2051,7 +2261,7 @@ check_allowed_to_delegate_to(krb5_context context,
 
     /* Must be in same realm */
     if (!krb5_realm_compare(context, server->princ, proxy)) {
-       return KRB5KDC_ERR_BADOPTION;
+       return KRB5KDC_ERR_POLICY;
     }
 
     req.server = server;
@@ -2347,3 +2557,63 @@ log_tgs_alt_tgt(krb5_principal p)
     /* OpenSolaris: audit_krb5kdc_tgs_req_alt_tgt(...) */
 }
 
+krb5_boolean
+enctype_requires_etype_info_2(krb5_enctype enctype)
+{
+    switch(enctype) {
+    case ENCTYPE_DES_CBC_CRC:
+    case ENCTYPE_DES_CBC_MD4:
+    case ENCTYPE_DES_CBC_MD5:
+    case ENCTYPE_DES3_CBC_SHA1:
+    case ENCTYPE_DES3_CBC_RAW:
+    case ENCTYPE_ARCFOUR_HMAC:
+    case ENCTYPE_ARCFOUR_HMAC_EXP :
+       return 0;
+    default:
+       return krb5_c_valid_enctype(enctype);
+    }
+}
+
+/* XXX where are the generic helper routines for this? */
+krb5_error_code
+add_pa_data_element(krb5_context context,
+                   krb5_pa_data *padata,
+                   krb5_pa_data ***inout_padata,
+                   krb5_boolean copy)
+{
+    int                                i;
+    krb5_pa_data               **p;
+
+    if (*inout_padata != NULL) {
+       for (i = 0; (*inout_padata)[i] != NULL; i++)
+           ;
+    } else
+       i = 0;
+
+    p = realloc(*inout_padata, (i + 2) * sizeof(krb5_pa_data *));
+    if (p == NULL)
+       return ENOMEM;
+
+    *inout_padata = p;
+
+    p[i] = (krb5_pa_data *)malloc(sizeof(krb5_pa_data));
+    if (p[i] == NULL)
+       return ENOMEM;
+    *(p[i]) = *padata;
+
+    p[i + 1] = NULL;
+
+    if (copy) {
+       p[i]->contents = (krb5_octet *)malloc(padata->length);
+       if (p[i]->contents == NULL) {
+           free(p[i]);
+           p[i] = NULL;
+           return ENOMEM;
+       }
+
+       memcpy(p[i]->contents, padata->contents, padata->length);
+    }
+
+    return 0;
+}
+
index e34ca876b44d4eac447afc0f8898dc4134590a46..26650510d8983a99d2b083620623fb7a6f4c6d36 100644 (file)
@@ -150,6 +150,8 @@ int against_local_policy_tgs (krb5_kdc_req *, krb5_db_entry,
                                        krb5_ticket *, const char **);
 
 /* kdc_preauth.c */
+krb5_boolean enctype_requires_etype_info_2(krb5_enctype enctype);
+
 const char * missing_required_preauth
     (krb5_db_entry *client, krb5_db_entry *server,
               krb5_enc_tkt_part *enc_tkt_reply);
@@ -177,6 +179,12 @@ krb5_error_code free_padata_context
 krb5_pa_data *find_pa_data
     (krb5_pa_data **padata, krb5_preauthtype pa_type);
 
+krb5_error_code add_pa_data_element
+    (krb5_context context,
+                   krb5_pa_data *padata,
+                   krb5_pa_data ***out_padata,
+                   krb5_boolean copy);
+
 /* kdc_authdata.c */
 krb5_error_code load_authdata_plugins(krb5_context context);
 krb5_error_code unload_authdata_plugins(krb5_context context);
@@ -240,13 +248,22 @@ krb5_error_code kdc_process_s4u2self_req
                krb5_kdc_req *request,
                krb5_const_principal client_princ,
                const krb5_db_entry *server,
-               krb5_keyblock *subkey,
+               krb5_keyblock *tgs_subkey,
+               krb5_keyblock *tgs_session,
                krb5_timestamp kdc_time,
-               krb5_pa_for_user **s4u2_req,
+               krb5_pa_s4u_x509_user **s4u2self_req,
                krb5_db_entry *princ,
                int *nprincs,
                const char **status);
 
+krb5_error_code kdc_make_s4u2self_rep
+       (krb5_context context,
+               krb5_keyblock *tgs_subkey,
+               krb5_keyblock *tgs_session,
+               krb5_pa_s4u_x509_user *req_s4u_user,
+               krb5_kdc_rep *reply,
+               krb5_enc_kdc_rep_part *reply_encpart);
+
 krb5_error_code kdc_process_s4u2proxy_req
        (krb5_context context,
                krb5_kdc_req *request,
index b68ef554fd98a6db9892cc6462b9ac5d89b246c3..a6203b2fb17ff4bbe90a0234379943dd8284b7ab 100644 (file)
@@ -2,7 +2,7 @@ thisconfigdir=../..
 myfulldir=lib/crypto
 mydir=lib/crypto
 BUILDTOP=$(REL)..$(S)..
-SUBDIRS=krb builtin crypto_tests
+SUBDIRS= builtin krb crypto_tests
 
 RUN_SETUP = @KRB5_RUN_ENV@
 PROG_LIBPATH=-L$(TOPLIBD)
@@ -20,19 +20,19 @@ LIBINITFUNC=cryptoint_initialize_library
 LIBFINIFUNC=cryptoint_cleanup_library
 RELDIR=crypto
 
-STOBJLISTS=krb/crc32/OBJS.ST krb/dk/OBJS.ST krb/enc_provider/OBJS.ST           \
-        krb/hash_provider/OBJS.ST krb/keyhash_provider/OBJS.ST                 \
-        krb/old/OBJS.ST krb/raw/OBJS.ST krb/yarrow/OBJS.ST                     \
-        @CRYPTO_IMPL@/md4/OBJS.ST @CRYPTO_IMPL@/md5/OBJS.ST @CRYPTO_IMPL@/sha1/OBJS.ST                 \
-       @CRYPTO_IMPL@/arcfour/OBJS.ST  @CRYPTO_IMPL@/aes/OBJS.ST @CRYPTO_IMPL@/des/OBJS.ST      \
-        krb/OBJS.ST  @CRYPTO_IMPL@/OBJS.ST
+STOBJLISTS=krb/crc32/OBJS.ST krb/dk/OBJS.ST builtin/enc_provider/OBJS.ST       \
+       krb/hash_provider/OBJS.ST krb/keyhash_provider/OBJS.ST                  \
+       krb/old/OBJS.ST krb/raw/OBJS.ST krb/yarrow/OBJS.ST                      \
+       builtin/md4/OBJS.ST builtin/md5/OBJS.ST builtin/sha1/OBJS.ST            \
+       builtin/arcfour/OBJS.ST  builtin/aes/OBJS.ST builtin/des/OBJS.ST        \
+       krb/OBJS.ST  builtin/OBJS.ST
 
-SUBDIROBJLISTS=krb/crc32/OBJS.ST krb/dk/OBJS.ST krb/enc_provider/OBJS.ST       \
-        krb/hash_provider/OBJS.ST krb/keyhash_provider/OBJS.ST                         \
+SUBDIROBJLISTS=krb/crc32/OBJS.ST krb/dk/OBJS.ST builtin/enc_provider/OBJS.ST   \
+       krb/hash_provider/OBJS.ST krb/keyhash_provider/OBJS.ST                  \
        krb/old/OBJS.ST krb/raw/OBJS.ST  krb/yarrow/OBJS.ST                     \
-       @CRYPTO_IMPL@/md4/OBJS.ST @CRYPTO_IMPL@/md5/OBJS.ST     @CRYPTO_IMPL@/sha1/OBJS.ST              \
-       @CRYPTO_IMPL@/arcfour/OBJS.ST @CRYPTO_IMPL@/aes/OBJS.ST @CRYPTO_IMPL@/des/OBJS.ST               \
-        krb/OBJS.ST  @CRYPTO_IMPL@/OBJS.ST
+       builtin/md4/OBJS.ST builtin/md5/OBJS.ST builtin/sha1/OBJS.ST            \
+       builtin/arcfour/OBJS.ST builtin/aes/OBJS.ST builtin/des/OBJS.ST         \
+       krb/OBJS.ST builtin/OBJS.ST
 
 # No dependencies.  Record places to find this shared object if the target
 # link editor and loader support it.
index 03ca5e966501ce0715f8f87a62c761be369ba5ce..c1d8a554be51404ffde84ad5b40117d209a00060 100644 (file)
@@ -2,15 +2,16 @@ thisconfigdir=../../..
 myfulldir=lib/crypto/builtin
 mydir=lib/crypto/builtin
 BUILDTOP=$(REL)..$(S)..$(S)..
-SUBDIRS=../@CRYPTO_IMPL@/des ../@CRYPTO_IMPL@/arcfour ../@CRYPTO_IMPL@/aes     \
-       ../@CRYPTO_IMPL@/md4 ../@CRYPTO_IMPL@/md5  ../@CRYPTO_IMPL@/sha1 
-LOCALINCLUDES = -I$(srcdir)/../krb -I$(srcdir)/../krb/hash_provider    \
+SUBDIRS=des arcfour aes         md4 md5  sha1 enc_provider
+LOCALINCLUDES = -I$(srcdir)/../krb                     \
+               -I$(srcdir)/../krb/hash_provider        \
                -I$(srcdir)/../@CRYPTO_IMPL@/des        \
                -I$(srcdir)/../@CRYPTO_IMPL@/aes        \
                -I$(srcdir)/../@CRYPTO_IMPL@/arcfour    \
                -I$(srcdir)/../@CRYPTO_IMPL@/sha1       \
                -I$(srcdir)/../@CRYPTO_IMPL@/md4        \
-               -I$(srcdir)/../@CRYPTO_IMPL@/md5
+               -I$(srcdir)/../@CRYPTO_IMPL@/md5        \
+               -I$(srcdir)/../@CRYPTO_IMPL@/enc_provider       
 PROG_LIBPATH=-L$(TOPLIBD)
 PROG_RPATH=$(KRB5_LIBDIR)
 DEFS=
@@ -23,8 +24,8 @@ DEFS=
 ##DOSOBJFILEDEP =$(OUTPRE)crypto.lst $(OUTPRE)des.lst $(OUTPRE)md4.lst $(OUTPRE)md5.lst $(OUTPRE)sha1.lst $(OUTPRE)arcfour.lst $(OUTPRE)crc32.lst $(OUTPRE)dk.lst $(OUTPRE)old.lst $(OUTPRE)raw.lst $(OUTPRE)enc_prov.lst $(OUTPRE)hash_pro.lst $(OUTPRE)kh_pro.lst $(OUTPRE)aes.lst
 
 STLIBOBJS=\
-       hmac.o  \
-       pbkdf2.o                
+       ../@CRYPTO_IMPL@/hmac.o \
+       ../@CRYPTO_IMPL@/pbkdf2.o               
 
 OBJS=\
        $(OUTPRE)../@CRYPTO_IMPL@/hmac.$(OBJEXT)        \
@@ -34,16 +35,18 @@ SRCS=\
        $(srcdir)/../@CRYPTO_IMPL@/hmac.c       \
        $(srcdir)/../@CRYPTO_IMPL@/pbkdf2.c     
 
-STOBJLISTS= ../@CRYPTO_IMPL@/des/OBJS.ST ../@CRYPTO_IMPL@/md4/OBJS.ST  \
-       ../@CRYPTO_IMPL@/md5/OBJS.ST ../@CRYPTO_IMPL@/sha1/OBJS.ST      \
-       ../@CRYPTO_IMPL@/arcfour/OBJS.ST        \
-       ../@CRYPTO_IMPL@/aes/OBJS.ST            \
-       ../@CRYPTO_IMPL@/OBJS.ST
+STOBJLISTS= des/OBJS.ST md4/OBJS.ST    \
+       md5/OBJS.ST sha1/OBJS.ST        \
+       enc_provider/OBJS.ST            \
+       arcfour/OBJS.ST                 \
+       aes/OBJS.ST                     \
+       OBJS.ST
 
-SUBDIROBJLISTS= ../@CRYPTO_IMPL@/des/OBJS.ST ../@CRYPTO_IMPL@/md4/OBJS.ST      \
-               ../@CRYPTO_IMPL@/md5/OBJS.ST ../@CRYPTO_IMPL@/sha1/OBJS.ST      \
-               ../@CRYPTO_IMPL@/arcfour/OBJS.ST                                \
-               ../@CRYPTO_IMPL@/aes/OBJS.ST ../@CRYPTO_IMPL@/OBJS.ST
+SUBDIROBJLISTS= des/OBJS.ST md4/OBJS.ST        \
+               md5/OBJS.ST sha1/OBJS.ST        \
+               enc_provider/OBJS.ST            \
+               arcfour/OBJS.ST                 \
+               aes/OBJS.ST OBJS.ST
 
 ##DOS##LIBOBJS = $(OBJS)
 
@@ -67,6 +70,9 @@ all-windows::
        cd ..\sha1
        @echo Making in crypto\sha1
        $(MAKE) -$(MFLAGS)
+       cd ..\enc_provider
+       @echo Making in crypto\enc_provider
+       $(MAKE) -$(MFLAGS)
        cd ..\arcfour
        @echo Making in crypto\arcfour
        $(MAKE) -$(MFLAGS)
@@ -88,6 +94,9 @@ clean-windows::
        cd ..\sha1
        @echo Making clean in crypto\sha1
        $(MAKE) -$(MFLAGS) clean
+       cd ..\enc_provider
+       @echo Making clean in crypto\enc_provider
+       $(MAKE) -$(MFLAGS) clean
        cd ..\arcfour
        @echo Making clean in crypto\arcfour
        $(MAKE) -$(MFLAGS) clean
@@ -109,6 +118,9 @@ check-windows::
        cd ..\sha1
        @echo Making check in crypto\sha1
        $(MAKE) -$(MFLAGS) check
+       cd ..\enc_provider
+       @echo Making check in crypto\enc_provider
+       $(MAKE) -$(MFLAGS) check
        cd ..\arcfour
        @echo Making check in crypto\arcfour
        $(MAKE) -$(MFLAGS) check
index ed36f7e6131e3c6404fbc5d28a3c26dcd57d57b8..49bc6a9c23b065448237734cbd22e0d09746f068 100644 (file)
@@ -12,28 +12,30 @@ DEFS=
 PROG_LIBPATH=-L$(TOPLIBD)
 PROG_RPATH=$(KRB5_LIBDIR)
 
+CIMPL = @CRYPTO_IMPL@/aes
+
 STLIBOBJS=\
-       aescrypt.o      \
-       aestab.o        \
-       aeskey.o        \
-       aes_s2k.o
+       ../../$(CIMPL)/aescrypt.o       \
+       ../../$(CIMPL)/aestab.o \
+       ../../$(CIMPL)/aeskey.o \
+       ../../$(CIMPL)/aes_s2k.o
 
 OBJS=\
-       $(OUTPRE)aescrypt.$(OBJEXT)     \
-       $(OUTPRE)aestab.$(OBJEXT)       \
-       $(OUTPRE)aeskey.$(OBJEXT)       \
-       $(OUTPRE)aes_s2k.$(OBJEXT)
+       $(OUTPRE)../../$(CIMPL)/aescrypt.$(OBJEXT)      \
+       $(OUTPRE)../../$(CIMPL)/aestab.$(OBJEXT)        \
+       $(OUTPRE)../../$(CIMPL)/aeskey.$(OBJEXT)        \
+       $(OUTPRE)../../$(CIMPL)/aes_s2k.$(OBJEXT)
 
 SRCS=\
-       $(srcdir)/aescrypt.c    \
-       $(srcdir)/aestab.c      \
-       $(srcdir)/aeskey.c      \
-       $(srcdir)/aes_s2k.c
+       $(srcdir)..//../$(CIMPL)/aescrypt.c     \
+       $(srcdir)..//../$(CIMPL)/aestab.c       \
+       $(srcdir)/../../$(CIMPL)/aeskey.c       \
+       $(srcdir)/../../$(CIMPL)/aes_s2k.c
 
 GEN_OBJS=\
-       $(OUTPRE)aescrypt.$(OBJEXT)     \
-       $(OUTPRE)aestab.$(OBJEXT)       \
-       $(OUTPRE)aeskey.$(OBJEXT)
+       $(OUTPRE)../../$(CIMPL)/aescrypt.$(OBJEXT)      \
+       $(OUTPRE)../../$(CIMPL)/aestab.$(OBJEXT)        \
+       $(OUTPRE)../../$(CIMPL)/aeskey.$(OBJEXT)
 
 ##DOS##LIBOBJS = $(OBJS)
 
index cf6c5115389aca3b62f2fc7e91f0d7d2a10c618a..499c0a0765d68d250d756715c7bdea35d8c828b4 100644 (file)
@@ -12,20 +12,22 @@ DEFS=
 PROG_LIBPATH=-L$(TOPLIBD)
 PROG_RPATH=$(KRB5_LIBDIR)
 
+CIMPL = @CRYPTO_IMPL@/arcfour
+
 STLIBOBJS=\
-       arcfour.o       \
-       arcfour_aead.o  \
-       arcfour_s2k.o
+       ../../$(CIMPL)/arcfour.o        \
+       ../../$(CIMPL)/arcfour_aead.o   \
+       ../../$(CIMPL)/arcfour_s2k.o
 
 OBJS=\
-       $(OUTPRE)arcfour.$(OBJEXT)      \
-       $(OUTPRE)arcfour_aead.$(OBJEXT) \
-       $(OUTPRE)arcfour_s2k.$(OBJEXT)
+       $(OUTPRE)../../$(CIMPL)/arcfour.$(OBJEXT)       \
+       $(OUTPRE)../../$(CIMPL)/arcfour_aead.$(OBJEXT)  \
+       $(OUTPRE)../../$(CIMPL)/arcfour_s2k.$(OBJEXT)
 
 SRCS=\
-       $(srcdir)/arcfour.c     \
-       $(srcdir)/arcfour_aead.c\
-       $(srcdir)/arcfour_s2k.c
+       $(srcdir)/../../$(CIMPL)/arcfour.c      \
+       $(srcdir)/../../$(CIMPL)/arcfour_aead.c\
+       $(srcdir)/../../$(CIMPL)/arcfour_s2k.c
 
 ##DOS##LIBOBJS = $(OBJS)
 
index a609c42991687bdd599b4f188b0699f252a79d11..47e9b1a6149f178f51f556dd445f840fa77546a8 100644 (file)
@@ -12,51 +12,53 @@ DEFS=
 PROG_LIBPATH=-L$(TOPLIBD)
 PROG_RPATH=$(KRB5_LIBDIR)
 
+CIMPL = @CRYPTO_IMPL@/des
+
 STLIBOBJS=\
-       afsstring2key.o \
-       d3_cbc.o        \
-       d3_aead.o       \
-       d3_kysched.o    \
-       des_prf.o       \
-       f_aead.o        \
-       f_cbc.o         \
-       f_cksum.o       \
-       f_parity.o      \
-       f_sched.o       \
-       f_tables.o      \
-       key_sched.o     \
-       string2key.o    \
-       weak_key.o
+       ../../$(CIMPL)/afsstring2key.o  \
+       ../../$(CIMPL)/d3_cbc.o \
+       ../../$(CIMPL)/d3_aead.o        \
+       ../../$(CIMPL)/d3_kysched.o     \
+       ../../$(CIMPL)/des_prf.o        \
+       ../../$(CIMPL)/f_aead.o         \
+       ../../$(CIMPL)/f_cbc.o  \
+       ../../$(CIMPL)/f_cksum.o        \
+       ../../$(CIMPL)/f_parity.o       \
+       ../../$(CIMPL)/f_sched.o        \
+       ../../$(CIMPL)/f_tables.o       \
+       ../../$(CIMPL)/key_sched.o      \
+       ../../$(CIMPL)/string2key.o     \
+       ../../$(CIMPL)/weak_key.o
 
-OBJS=  $(OUTPRE)afsstring2key.$(OBJEXT)        \
-       $(OUTPRE)d3_cbc.$(OBJEXT)       \
-       $(OUTPRE)d3_aead.$(OBJEXT)      \
-       $(OUTPRE)d3_kysched.$(OBJEXT)   \
-       $(OUTPRE)des_prf.$(OBJEXT)      \
-       $(OUTPRE)f_aead.$(OBJEXT)       \
-       $(OUTPRE)f_cbc.$(OBJEXT)        \
-       $(OUTPRE)f_cksum.$(OBJEXT)      \
-       $(OUTPRE)f_parity.$(OBJEXT)     \
-       $(OUTPRE)f_sched.$(OBJEXT)      \
-       $(OUTPRE)f_tables.$(OBJEXT)     \
-       $(OUTPRE)key_sched.$(OBJEXT)    \
-       $(OUTPRE)string2key.$(OBJEXT)   \
-       $(OUTPRE)weak_key.$(OBJEXT)
+OBJS=  $(OUTPRE)../../$(CIMPL)/afsstring2key.$(OBJEXT) \
+       $(OUTPRE)../../$(CIMPL)/d3_cbc.$(OBJEXT)        \
+       $(OUTPRE)../../$(CIMPL)/d3_aead.$(OBJEXT)       \
+       $(OUTPRE)../../$(CIMPL)/d3_kysched.$(OBJEXT)    \
+       $(OUTPRE)../../$(CIMPL)/des_prf.$(OBJEXT)       \
+       $(OUTPRE)../../$(CIMPL)/f_aead.$(OBJEXT)        \
+       $(OUTPRE)../../$(CIMPL)/f_cbc.$(OBJEXT)         \
+       $(OUTPRE)../../$(CIMPL)/f_cksum.$(OBJEXT)       \
+       $(OUTPRE)../../$(CIMPL)/f_parity.$(OBJEXT)      \
+       $(OUTPRE)../../$(CIMPL)/f_sched.$(OBJEXT)       \
+       $(OUTPRE)../../$(CIMPL)/f_tables.$(OBJEXT)      \
+       $(OUTPRE)../../$(CIMPL)/key_sched.$(OBJEXT)     \
+       $(OUTPRE)../../$(CIMPL)/string2key.$(OBJEXT)    \
+       $(OUTPRE)../../$(CIMPL)/weak_key.$(OBJEXT)
 
-SRCS=  $(srcdir)/afsstring2key.c       \
-       $(srcdir)/d3_cbc.c      \
-       $(srcdir)/d3_aead.c     \
-       $(srcdir)/d3_kysched.c  \
-       $(srcdir)/des_prf.c     \
-       $(srcdir)/f_aead.c      \
-       $(srcdir)/f_cbc.c       \
-       $(srcdir)/f_cksum.c     \
-       $(srcdir)/f_parity.c    \
-       $(srcdir)/f_sched.c     \
-       $(srcdir)/f_tables.c    \
-       $(srcdir)/key_sched.c   \
-       $(srcdir)/weak_key.c    \
-       $(srcdir)/string2key.c
+SRCS=  $(srcdir)/../../$(CIMPL)/afsstring2key.c        \
+       $(srcdir)/../../$(CIMPL)/d3_cbc.c       \
+       $(srcdir)/../../$(CIMPL)/d3_aead.c      \
+       $(srcdir)/../../$(CIMPL)/d3_kysched.c   \
+       $(srcdir)/../../$(CIMPL)/des_prf.c      \
+       $(srcdir)/../../$(CIMPL)/f_aead.c       \
+       $(srcdir)/../../$(CIMPL)/f_cbc.c        \
+       $(srcdir)/../../$(CIMPL)/f_cksum.c      \
+       $(srcdir)/../../$(CIMPL)/f_parity.c     \
+       $(srcdir)/../../$(CIMPL)/f_sched.c      \
+       $(srcdir)/../../$(CIMPL)/f_tables.c     \
+       $(srcdir)/../../$(CIMPL)/key_sched.c    \
+       $(srcdir)/../../$(CIMPL)/weak_key.c     \
+       $(srcdir)/../../$(CIMPL)/string2key.c
 
 ##DOS##LIBOBJS = $(OBJS)
 
diff --git a/src/lib/crypto/builtin/enc_provider/Makefile.in b/src/lib/crypto/builtin/enc_provider/Makefile.in
new file mode 100644 (file)
index 0000000..1895b51
--- /dev/null
@@ -0,0 +1,48 @@
+thisconfigdir=../../../..
+myfulldir=lib/crypto/builtin/enc_provider
+mydir=lib/crypto/builtin/enc_provider
+BUILDTOP=$(REL)..$(S)..$(S)..$(S)..
+LOCALINCLUDES = -I$(srcdir)/../../@CRYPTO_IMPL@/des    \
+               -I$(srcdir)/../../@CRYPTO_IMPL@/arcfour \
+               -I$(srcdir)/../../@CRYPTO_IMPL@/aes     \
+               -I$(srcdir)/../../krb   \
+               -I$(srcdir)/.. -I$(srcdir)/../../@CRYPTO_IMPL@ 
+DEFS=
+
+##DOS##BUILDTOP = ..\..\..\..
+##DOS##PREFIXDIR=enc_provider
+##DOS##OBJFILE=..\$(OUTPRE)enc_prov.lst
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+STLIBOBJS= \
+       ../../@CRYPTO_IMPL@/enc_provider/des.o  \
+       ../../@CRYPTO_IMPL@/enc_provider/des3.o         \
+       ../../@CRYPTO_IMPL@/enc_provider/rc4.o  \
+       ../../@CRYPTO_IMPL@/enc_provider/aes.o 
+
+OBJS= \
+       $(OUTPRE)../../@CRYPTO_IMPL@/enc_provider/des.$(OBJEXT)         \
+       $(OUTPRE)../../@CRYPTO_IMPL@/enc_provider/des3.$(OBJEXT)        \
+       $(OUTPRE)../../@CRYPTO_IMPL@/enc_provider/aes.$(OBJEXT)         \
+       $(OUTPRE)../../@CRYPTO_IMPL@/enc_provider/rc4.$(OBJEXT)
+
+SRCS= \
+       $(srcdir)/../../@CRYPTO_IMPL@/enc_provider/des.c        \
+       $(srcdir)/../../@CRYPTO_IMPL@/enc_provider/des3.c       \
+       $(srcdir)/../../@CRYPTO_IMPL@/enc_provider/aes.c        \
+       $(srcdir)/../../@CRYPTO_IMPL@/enc_provider/rc4.c
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix:: all-libobjs
+
+includes:: depend
+
+depend:: $(SRCS)
+
+clean-unix:: clean-libobjs
+
+@libobj_frag@
+
diff --git a/src/lib/crypto/builtin/enc_provider/aes.c b/src/lib/crypto/builtin/enc_provider/aes.c
new file mode 100644 (file)
index 0000000..88f2d9e
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * lib/crypto/enc_provider/aes.c
+ *
+ * Copyright (C) 2003, 2007, 2008 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"
+#include "enc_provider.h"
+#include "aes.h"
+#include <aead.h>
+
+#if 0
+aes_rval aes_blk_len(unsigned int blen, aes_ctx cx[1]);
+aes_rval aes_enc_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]);
+aes_rval aes_enc_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]);
+aes_rval aes_dec_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]);
+aes_rval aes_dec_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]);
+#endif
+
+#define CHECK_SIZES 0
+
+#if 0
+static void printd (const char *descr, krb5_data *d) {
+    int i, j;
+    const int r = 16;
+
+    printf("%s:", descr);
+
+    for (i = 0; i < d->length; i += r) {
+       printf("\n  %04x: ", i);
+       for (j = i; j < i + r && j < d->length; j++)
+           printf(" %02x", 0xff & d->data[j]);
+#ifdef SHOW_TEXT
+       for (; j < i + r; j++)
+           printf("   ");
+       printf("   ");
+       for (j = i; j < i + r && j < d->length; j++) {
+           int c = 0xff & d->data[j];
+           printf("%c", isprint(c) ? c : '.');
+       }
+#endif
+    }
+    printf("\n");
+}
+#endif
+
+static inline void enc(char *out, const char *in, aes_ctx *ctx)
+{
+    if (aes_enc_blk((const unsigned char *)in, (unsigned char *)out, ctx)
+       != aes_good)
+       abort();
+}
+static inline void dec(char *out, const char *in, aes_ctx *ctx)
+{
+    if (aes_dec_blk((const unsigned char *)in, (unsigned char *)out, ctx)
+       != aes_good)
+       abort();
+}
+
+static void xorblock(char *out, const char *in)
+{
+    int z;
+    for (z = 0; z < BLOCK_SIZE; z++)
+       out[z] ^= in[z];
+}
+
+krb5_error_code
+krb5int_aes_encrypt(const krb5_keyblock *key, const krb5_data *ivec,
+                   const krb5_data *input, krb5_data *output)
+{
+    aes_ctx ctx;
+    char tmp[BLOCK_SIZE], tmp2[BLOCK_SIZE], tmp3[BLOCK_SIZE];
+    int nblocks = 0, blockno;
+
+/*    CHECK_SIZES; */
+
+    if (aes_enc_key(key->contents, key->length, &ctx) != aes_good)
+       abort();
+
+    if (ivec)
+       memcpy(tmp, ivec->data, BLOCK_SIZE);
+    else
+       memset(tmp, 0, BLOCK_SIZE);
+
+    nblocks = (input->length + BLOCK_SIZE - 1) / BLOCK_SIZE;
+
+    if (nblocks == 1) {
+       /* XXX Used for DK function.  */
+       enc(output->data, input->data, &ctx);
+    } else {
+       unsigned int nleft;
+
+       for (blockno = 0; blockno < nblocks - 2; blockno++) {
+           xorblock(tmp, input->data + blockno * BLOCK_SIZE);
+           enc(tmp2, tmp, &ctx);
+           memcpy(output->data + blockno * BLOCK_SIZE, tmp2, BLOCK_SIZE);
+
+           /* Set up for next block.  */
+           memcpy(tmp, tmp2, BLOCK_SIZE);
+       }
+       /* Do final CTS step for last two blocks (the second of which
+          may or may not be incomplete).  */
+       xorblock(tmp, input->data + (nblocks - 2) * BLOCK_SIZE);
+       enc(tmp2, tmp, &ctx);
+       nleft = input->length - (nblocks - 1) * BLOCK_SIZE;
+       memcpy(output->data + (nblocks - 1) * BLOCK_SIZE, tmp2, nleft);
+       memcpy(tmp, tmp2, BLOCK_SIZE);
+
+       memset(tmp3, 0, sizeof(tmp3));
+       memcpy(tmp3, input->data + (nblocks - 1) * BLOCK_SIZE, nleft);
+       xorblock(tmp, tmp3);
+       enc(tmp2, tmp, &ctx);
+       memcpy(output->data + (nblocks - 2) * BLOCK_SIZE, tmp2, BLOCK_SIZE);
+       if (ivec)
+           memcpy(ivec->data, tmp2, BLOCK_SIZE);
+    }
+
+    return 0;
+}
+
+krb5_error_code
+krb5int_aes_decrypt(const krb5_keyblock *key, const krb5_data *ivec,
+                   const krb5_data *input, krb5_data *output)
+{
+    aes_ctx ctx;
+    char tmp[BLOCK_SIZE], tmp2[BLOCK_SIZE], tmp3[BLOCK_SIZE];
+    int nblocks = 0, blockno;
+
+    CHECK_SIZES;
+
+    if (aes_dec_key(key->contents, key->length, &ctx) != aes_good)
+       abort();
+
+    if (ivec)
+       memcpy(tmp, ivec->data, BLOCK_SIZE);
+    else
+       memset(tmp, 0, BLOCK_SIZE);
+
+    nblocks = (input->length + BLOCK_SIZE - 1) / BLOCK_SIZE;
+
+    if (nblocks == 1) {
+       if (input->length < BLOCK_SIZE)
+           abort();
+       dec(output->data, input->data, &ctx);
+    } else {
+
+       for (blockno = 0; blockno < nblocks - 2; blockno++) {
+           dec(tmp2, input->data + blockno * BLOCK_SIZE, &ctx);
+           xorblock(tmp2, tmp);
+           memcpy(output->data + blockno * BLOCK_SIZE, tmp2, BLOCK_SIZE);
+           memcpy(tmp, input->data + blockno * BLOCK_SIZE, BLOCK_SIZE);
+       }
+       /* Do last two blocks, the second of which (next-to-last block
+          of plaintext) may be incomplete.  */
+       dec(tmp2, input->data + (nblocks - 2) * BLOCK_SIZE, &ctx);
+       /* Set tmp3 to last ciphertext block, padded.  */
+       memset(tmp3, 0, sizeof(tmp3));
+       memcpy(tmp3, input->data + (nblocks - 1) * BLOCK_SIZE,
+              input->length - (nblocks - 1) * BLOCK_SIZE);
+       /* Set tmp2 to last (possibly partial) plaintext block, and
+          save it.  */
+       xorblock(tmp2, tmp3);
+       memcpy(output->data + (nblocks - 1) * BLOCK_SIZE, tmp2,
+              input->length - (nblocks - 1) * BLOCK_SIZE);
+       /* Maybe keep the trailing part, and copy in the last
+          ciphertext block.  */
+       memcpy(tmp2, tmp3, input->length - (nblocks - 1) * BLOCK_SIZE);
+       /* Decrypt, to get next to last plaintext block xor previous
+          ciphertext.  */
+       dec(tmp3, tmp2, &ctx);
+       xorblock(tmp3, tmp);
+       memcpy(output->data + (nblocks - 2) * BLOCK_SIZE, tmp3, BLOCK_SIZE);
+       if (ivec)
+           memcpy(ivec->data, input->data + (nblocks - 2) * BLOCK_SIZE,
+                  BLOCK_SIZE);
+    }
+
+    return 0;
+}
+
+static krb5_error_code
+krb5int_aes_encrypt_iov(const krb5_keyblock *key,
+                       const krb5_data *ivec,
+                       krb5_crypto_iov *data,
+                       size_t num_data)
+{
+    aes_ctx ctx;
+    char tmp[BLOCK_SIZE], tmp2[BLOCK_SIZE];
+    int nblocks = 0, blockno;
+    size_t input_length, i;
+
+    if (aes_enc_key(key->contents, key->length, &ctx) != aes_good)
+       abort();
+
+    if (ivec != NULL)
+       memcpy(tmp, ivec->data, BLOCK_SIZE);
+    else
+       memset(tmp, 0, BLOCK_SIZE);
+
+    for (i = 0, input_length = 0; i < num_data; i++) {
+       krb5_crypto_iov *iov = &data[i];
+
+       if (ENCRYPT_IOV(iov))
+           input_length += iov->data.length;
+    }
+
+    nblocks = (input_length + BLOCK_SIZE - 1) / BLOCK_SIZE;
+
+    assert(nblocks > 1);
+
+    {
+       char blockN2[BLOCK_SIZE];   /* second last */
+       char blockN1[BLOCK_SIZE];   /* last block */
+       struct iov_block_state input_pos, output_pos;
+
+       IOV_BLOCK_STATE_INIT(&input_pos);
+       IOV_BLOCK_STATE_INIT(&output_pos);
+
+       for (blockno = 0; blockno < nblocks - 2; blockno++) {
+           char blockN[BLOCK_SIZE];
+
+           krb5int_c_iov_get_block((unsigned char *)blockN, BLOCK_SIZE, data, num_data, &input_pos);
+           xorblock(tmp, blockN);
+           enc(tmp2, tmp, &ctx);
+           krb5int_c_iov_put_block(data, num_data, (unsigned char *)tmp2, BLOCK_SIZE, &output_pos);
+
+           /* Set up for next block.  */
+           memcpy(tmp, tmp2, BLOCK_SIZE);
+       }
+
+       /* Do final CTS step for last two blocks (the second of which
+          may or may not be incomplete).  */
+
+       /* First, get the last two blocks */
+       memset(blockN1, 0, sizeof(blockN1)); /* pad last block with zeros */
+       krb5int_c_iov_get_block((unsigned char *)blockN2, BLOCK_SIZE, data, num_data, &input_pos);
+       krb5int_c_iov_get_block((unsigned char *)blockN1, BLOCK_SIZE, data, num_data, &input_pos);
+
+       /* Encrypt second last block */
+       xorblock(tmp, blockN2);
+       enc(tmp2, tmp, &ctx);
+       memcpy(blockN2, tmp2, BLOCK_SIZE); /* blockN2 now contains first block */
+       memcpy(tmp, tmp2, BLOCK_SIZE);
+
+       /* Encrypt last block */
+       xorblock(tmp, blockN1);
+       enc(tmp2, tmp, &ctx);
+       memcpy(blockN1, tmp2, BLOCK_SIZE);
+
+       /* Put the last two blocks back into the iovec (reverse order) */
+       krb5int_c_iov_put_block(data, num_data, (unsigned char *)blockN1, BLOCK_SIZE, &output_pos);
+       krb5int_c_iov_put_block(data, num_data, (unsigned char *)blockN2, BLOCK_SIZE, &output_pos);
+
+       if (ivec != NULL)
+           memcpy(ivec->data, blockN1, BLOCK_SIZE);
+    }
+
+    return 0;
+}
+
+static krb5_error_code
+krb5int_aes_decrypt_iov(const krb5_keyblock *key,
+                       const krb5_data *ivec,
+                       krb5_crypto_iov *data,
+                       size_t num_data)
+{
+    aes_ctx ctx;
+    char tmp[BLOCK_SIZE], tmp2[BLOCK_SIZE], tmp3[BLOCK_SIZE];
+    int nblocks = 0, blockno;
+    unsigned int i;
+    size_t input_length;
+
+    CHECK_SIZES;
+
+    if (aes_dec_key(key->contents, key->length, &ctx) != aes_good)
+       abort();
+
+    if (ivec != NULL)
+       memcpy(tmp, ivec->data, BLOCK_SIZE);
+    else
+       memset(tmp, 0, BLOCK_SIZE);
+
+    for (i = 0, input_length = 0; i < num_data; i++) {
+       krb5_crypto_iov *iov = &data[i];
+
+       if (ENCRYPT_IOV(iov))
+           input_length += iov->data.length;
+    }
+
+    nblocks = (input_length + BLOCK_SIZE - 1) / BLOCK_SIZE;
+
+    assert(nblocks > 1);
+
+    {
+       char blockN2[BLOCK_SIZE];   /* second last */
+       char blockN1[BLOCK_SIZE];   /* last block */
+       struct iov_block_state input_pos, output_pos;
+
+       IOV_BLOCK_STATE_INIT(&input_pos);
+       IOV_BLOCK_STATE_INIT(&output_pos);
+
+       for (blockno = 0; blockno < nblocks - 2; blockno++) {
+           char blockN[BLOCK_SIZE];
+
+           krb5int_c_iov_get_block((unsigned char *)blockN, BLOCK_SIZE, data, num_data, &input_pos);
+           dec(tmp2, blockN, &ctx);
+           xorblock(tmp2, tmp);
+           krb5int_c_iov_put_block(data, num_data, (unsigned char *)tmp2, BLOCK_SIZE, &output_pos);
+           memcpy(tmp, blockN, BLOCK_SIZE);
+       }
+
+       /* Do last two blocks, the second of which (next-to-last block
+          of plaintext) may be incomplete.  */
+
+       /* First, get the last two encrypted blocks */
+       memset(blockN1, 0, sizeof(blockN1)); /* pad last block with zeros */
+       krb5int_c_iov_get_block((unsigned char *)blockN2, BLOCK_SIZE, data, num_data, &input_pos);
+       krb5int_c_iov_get_block((unsigned char *)blockN1, BLOCK_SIZE, data, num_data, &input_pos);
+
+       /* Decrypt second last block */
+       dec(tmp2, blockN2, &ctx);
+       /* Set tmp2 to last (possibly partial) plaintext block, and
+          save it.  */
+       xorblock(tmp2, blockN1);
+       memcpy(blockN2, tmp2, BLOCK_SIZE);
+
+       /* Maybe keep the trailing part, and copy in the last
+          ciphertext block.  */
+       input_length %= BLOCK_SIZE;
+       memcpy(tmp2, blockN1, input_length ? input_length : BLOCK_SIZE);
+       dec(tmp3, tmp2, &ctx);
+       xorblock(tmp3, tmp);
+       /* Copy out ivec first before we clobber blockN1 with plaintext */
+       if (ivec != NULL)
+           memcpy(ivec->data, blockN1, BLOCK_SIZE);
+       memcpy(blockN1, tmp3, BLOCK_SIZE);
+
+       /* Put the last two blocks back into the iovec */
+       krb5int_c_iov_put_block(data, num_data, (unsigned char *)blockN1, BLOCK_SIZE, &output_pos);
+       krb5int_c_iov_put_block(data, num_data, (unsigned char *)blockN2, BLOCK_SIZE, &output_pos);
+    }
+
+    return 0;
+}
+
+static krb5_error_code
+k5_aes_make_key(const krb5_data *randombits, krb5_keyblock *key)
+{
+    if (key->length != 16 && key->length != 32)
+       return(KRB5_BAD_KEYSIZE);
+    if (randombits->length != key->length)
+       return(KRB5_CRYPTO_INTERNAL);
+
+    key->magic = KV5M_KEYBLOCK;
+
+    memcpy(key->contents, randombits->data, randombits->length);
+    return(0);
+}
+
+static krb5_error_code
+krb5int_aes_init_state (const krb5_keyblock *key, krb5_keyusage usage,
+                       krb5_data *state)
+{
+    state->length = 16;
+    state->data = (void *) malloc(16);
+    if (state->data == NULL)
+       return ENOMEM;
+    memset(state->data, 0, state->length);
+    return 0;
+}
+
+const struct krb5_enc_provider krb5int_enc_aes128 = {
+    16,
+    16, 16,
+    krb5int_aes_encrypt,
+    krb5int_aes_decrypt,
+    k5_aes_make_key,
+    krb5int_aes_init_state,
+    krb5int_default_free_state,
+    krb5int_aes_encrypt_iov,
+    krb5int_aes_decrypt_iov
+};
+
+const struct krb5_enc_provider krb5int_enc_aes256 = {
+    16,
+    32, 32,
+    krb5int_aes_encrypt,
+    krb5int_aes_decrypt,
+    k5_aes_make_key,
+    krb5int_aes_init_state,
+    krb5int_default_free_state,
+    krb5int_aes_encrypt_iov,
+    krb5int_aes_decrypt_iov
+};
+
diff --git a/src/lib/crypto/builtin/enc_provider/deps b/src/lib/crypto/builtin/enc_provider/deps
new file mode 100644 (file)
index 0000000..ed1b61c
--- /dev/null
@@ -0,0 +1,49 @@
+# 
+# Generated makefile dependencies follow.
+#
+des.so des.po $(OUTPRE)des.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+  $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/k5-buf.h \
+  $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-gmt_mktime.h \
+  $(SRCTOP)/include/k5-int-pkinit.h $(SRCTOP)/include/k5-int.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \
+  $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/krb5.h \
+  $(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(srcdir)/../des/des_int.h $(srcdir)/../../krb/aead.h \
+  $(srcdir)/../../krb/cksumtypes.h des.c enc_provider.h
+des3.so des3.po $(OUTPRE)des3.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+  $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/k5-buf.h \
+  $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-gmt_mktime.h \
+  $(SRCTOP)/include/k5-int-pkinit.h $(SRCTOP)/include/k5-int.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \
+  $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/krb5.h \
+  $(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(srcdir)/../des/des_int.h $(srcdir)/../../krb/aead.h \
+  $(srcdir)/../../krb/cksumtypes.h des3.c
+aes.so aes.po $(OUTPRE)aes.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+  $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/k5-buf.h \
+  $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-gmt_mktime.h \
+  $(SRCTOP)/include/k5-int-pkinit.h $(SRCTOP)/include/k5-int.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \
+  $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/krb5.h \
+  $(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(srcdir)/../aes/aes.h $(srcdir)/../aes/uitypes.h \
+  $(srcdir)/../../krb/aead.h $(srcdir)/../../krb/cksumtypes.h aes.c \
+  enc_provider.h
+rc4.so rc4.po $(OUTPRE)rc4.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+  $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/k5-buf.h \
+  $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-gmt_mktime.h \
+  $(SRCTOP)/include/k5-int-pkinit.h $(SRCTOP)/include/k5-int.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \
+  $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/krb5.h \
+  $(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(srcdir)/../arcfour/arcfour-int.h $(srcdir)/../arcfour/arcfour.h \
+  $(srcdir)/../../krb/aead.h $(srcdir)/../../krb/cksumtypes.h enc_provider.h \
+  rc4.c
diff --git a/src/lib/crypto/builtin/enc_provider/des.c b/src/lib/crypto/builtin/enc_provider/des.c
new file mode 100644 (file)
index 0000000..547f6b9
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * 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 FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "des_int.h"
+#include "enc_provider.h"
+#include "aead.h"
+
+static krb5_error_code
+k5_des_docrypt(const krb5_keyblock *key, const krb5_data *ivec,
+              const krb5_data *input, krb5_data *output, int enc)
+{
+    mit_des_key_schedule schedule;
+
+    /* key->enctype was checked by the caller */
+
+    if (key->length != 8)
+       return(KRB5_BAD_KEYSIZE);
+    if ((input->length%8) != 0)
+       return(KRB5_BAD_MSIZE);
+    if (ivec && (ivec->length != 8))
+       return(KRB5_BAD_MSIZE);
+    if (input->length != output->length)
+       return(KRB5_BAD_MSIZE);
+
+    switch (mit_des_key_sched(key->contents, schedule)) {
+    case -1:
+       return(KRB5DES_BAD_KEYPAR);
+    case -2:
+       return(KRB5DES_WEAK_KEY);
+    }
+
+    /* this has a return value, but the code always returns zero */
+
+    mit_des_cbc_encrypt((krb5_pointer) input->data,
+                       (krb5_pointer) output->data, input->length,
+                       schedule,
+                       (ivec
+                        ? (const unsigned char *) ivec->data
+                        : (const unsigned char *) mit_des_zeroblock),
+                       enc);
+
+    memset(schedule, 0, sizeof(schedule));
+
+    return(0);
+}
+
+static krb5_error_code
+k5_des_encrypt(const krb5_keyblock *key, const krb5_data *ivec,
+              const krb5_data *input, krb5_data *output)
+{
+    return(k5_des_docrypt(key, ivec, input, output, 1));
+}
+
+static krb5_error_code
+k5_des_decrypt(const krb5_keyblock *key, const krb5_data *ivec,
+              const krb5_data *input, krb5_data *output)
+{
+    return(k5_des_docrypt(key, ivec, input, output, 0));
+}
+
+static krb5_error_code
+k5_des_make_key(const krb5_data *randombits, krb5_keyblock *key)
+{
+    if (key->length != 8)
+       return(KRB5_BAD_KEYSIZE);
+    if (randombits->length != 7)
+       return(KRB5_CRYPTO_INTERNAL);
+
+    key->magic = KV5M_KEYBLOCK;
+    key->length = 8;
+
+    /* take the seven bytes, move them around into the top 7 bits of the
+       8 key bytes, then compute the parity bits */
+
+    memcpy(key->contents, randombits->data, randombits->length);
+    key->contents[7] = (((key->contents[0]&1)<<1) | ((key->contents[1]&1)<<2) |
+                       ((key->contents[2]&1)<<3) | ((key->contents[3]&1)<<4) |
+                       ((key->contents[4]&1)<<5) | ((key->contents[5]&1)<<6) |
+                       ((key->contents[6]&1)<<7));
+
+    mit_des_fixup_key_parity(key->contents);
+
+    return(0);
+}
+
+static krb5_error_code
+k5_des_docrypt_iov(const krb5_keyblock *key, const krb5_data *ivec,
+                  krb5_crypto_iov *data, size_t num_data, int enc)
+{
+    mit_des_key_schedule schedule;
+    size_t input_length = 0;
+    unsigned int i;
+
+    /* key->enctype was checked by the caller */
+
+    if (key->length != 8)
+       return(KRB5_BAD_KEYSIZE);
+
+    for (i = 0; i < num_data; i++) {
+       const krb5_crypto_iov *iov = &data[i];
+
+       if (ENCRYPT_DATA_IOV(iov))
+           input_length += iov->data.length;
+    }
+
+    if ((input_length % 8) != 0)
+       return(KRB5_BAD_MSIZE);
+    if (ivec && (ivec->length != 8))
+       return(KRB5_BAD_MSIZE);
+
+    switch (mit_des_key_sched(key->contents, schedule)) {
+    case -1:
+       return(KRB5DES_BAD_KEYPAR);
+    case -2:
+       return(KRB5DES_WEAK_KEY);
+    }
+
+    /* this has a return value, but the code always returns zero */
+    if (enc)
+       krb5int_des_cbc_encrypt_iov(data, num_data, schedule, ivec ? ivec->data : NULL);
+    else
+       krb5int_des_cbc_decrypt_iov(data, num_data, schedule, ivec ? ivec->data : NULL);
+
+    memset(schedule, 0, sizeof(schedule));
+
+    return(0);
+}
+
+static krb5_error_code
+k5_des_encrypt_iov(const krb5_keyblock *key,
+                   const krb5_data *ivec,
+                   krb5_crypto_iov *data,
+                   size_t num_data)
+{
+    return k5_des_docrypt_iov(key, ivec, data, num_data, 1);
+}
+
+static krb5_error_code
+k5_des_decrypt_iov(const krb5_keyblock *key,
+                  const krb5_data *ivec,
+                  krb5_crypto_iov *data,
+                  size_t num_data)
+{
+    return k5_des_docrypt_iov(key, ivec, data, num_data, 0);
+}
+
+const struct krb5_enc_provider krb5int_enc_des = {
+    8,
+    7, 8,
+    k5_des_encrypt,
+    k5_des_decrypt,
+    k5_des_make_key,
+    krb5int_des_init_state,
+    krb5int_default_free_state,
+    k5_des_encrypt_iov,
+    k5_des_decrypt_iov
+};
diff --git a/src/lib/crypto/builtin/enc_provider/des3.c b/src/lib/crypto/builtin/enc_provider/des3.c
new file mode 100644 (file)
index 0000000..dc7c633
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * 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 FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "des_int.h"
+#include <aead.h>
+
+static krb5_error_code
+validate_and_schedule(const krb5_keyblock *key, const krb5_data *ivec,
+                     const krb5_data *input, const krb5_data *output,
+                     mit_des3_key_schedule *schedule)
+{
+    /* key->enctype was checked by the caller */
+
+    if (key->length != 24)
+       return(KRB5_BAD_KEYSIZE);
+    if ((input->length%8) != 0)
+       return(KRB5_BAD_MSIZE);
+    if (ivec && (ivec->length != 8))
+       return(KRB5_BAD_MSIZE);
+    if (input->length != output->length)
+       return(KRB5_BAD_MSIZE);
+
+    switch (mit_des3_key_sched(*(mit_des3_cblock *)key->contents,
+                              *schedule)) {
+    case -1:
+       return(KRB5DES_BAD_KEYPAR);
+    case -2:
+       return(KRB5DES_WEAK_KEY);
+    }
+    return 0;
+}
+
+static krb5_error_code
+validate_and_schedule_iov(const krb5_keyblock *key, const krb5_data *ivec,
+                         const krb5_crypto_iov *data, size_t num_data,
+                         mit_des3_key_schedule *schedule)
+{
+    size_t i, input_length;
+
+    for (i = 0, input_length = 0; i < num_data; i++) {
+       const krb5_crypto_iov *iov = &data[i];
+
+       if (ENCRYPT_IOV(iov))
+           input_length += iov->data.length;
+    }
+
+    if (key->length != 24)
+       return(KRB5_BAD_KEYSIZE);
+    if ((input_length%8) != 0)
+       return(KRB5_BAD_MSIZE);
+    if (ivec && (ivec->length != 8))
+       return(KRB5_BAD_MSIZE);
+
+    switch (mit_des3_key_sched(*(mit_des3_cblock *)key->contents,
+                              *schedule)) {
+    case -1:
+       return(KRB5DES_BAD_KEYPAR);
+    case -2:
+       return(KRB5DES_WEAK_KEY);
+    }
+    return 0;
+}
+
+static krb5_error_code
+k5_des3_encrypt(const krb5_keyblock *key, const krb5_data *ivec,
+               const krb5_data *input, krb5_data *output)
+{
+    mit_des3_key_schedule schedule;
+    krb5_error_code err;
+
+    err = validate_and_schedule(key, ivec, input, output, &schedule);
+    if (err)
+       return err;
+
+    /* this has a return value, but the code always returns zero */
+    krb5int_des3_cbc_encrypt((krb5_pointer) input->data,
+                            (krb5_pointer) output->data, input->length,
+                            schedule[0], schedule[1], schedule[2],
+                            ivec?(const unsigned char *) ivec->data:(const unsigned char *)mit_des_zeroblock);
+
+    zap(schedule, sizeof(schedule));
+
+    return(0);
+}
+
+static krb5_error_code
+k5_des3_decrypt(const krb5_keyblock *key, const krb5_data *ivec,
+               const krb5_data *input, krb5_data *output)
+{
+    mit_des3_key_schedule schedule;
+    krb5_error_code err;
+
+    err = validate_and_schedule(key, ivec, input, output, &schedule);
+    if (err)
+       return err;
+
+    /* this has a return value, but the code always returns zero */
+    krb5int_des3_cbc_decrypt((krb5_pointer) input->data,
+                            (krb5_pointer) output->data, input->length,
+                            schedule[0], schedule[1], schedule[2],
+                            ivec?(const unsigned char *) ivec->data:(const unsigned char *)mit_des_zeroblock);
+
+    zap(schedule, sizeof(schedule));
+
+    return(0);
+}
+
+static krb5_error_code
+k5_des3_make_key(const krb5_data *randombits, krb5_keyblock *key)
+{
+    int i;
+
+    if (key->length != 24)
+       return(KRB5_BAD_KEYSIZE);
+    if (randombits->length != 21)
+       return(KRB5_CRYPTO_INTERNAL);
+
+    key->magic = KV5M_KEYBLOCK;
+    key->length = 24;
+
+    /* take the seven bytes, move them around into the top 7 bits of the
+       8 key bytes, then compute the parity bits.  Do this three times. */
+
+    for (i=0; i<3; i++) {
+       memcpy(key->contents+i*8, randombits->data+i*7, 7);
+       key->contents[i*8+7] = (((key->contents[i*8]&1)<<1) |
+                               ((key->contents[i*8+1]&1)<<2) |
+                               ((key->contents[i*8+2]&1)<<3) |
+                               ((key->contents[i*8+3]&1)<<4) |
+                               ((key->contents[i*8+4]&1)<<5) |
+                               ((key->contents[i*8+5]&1)<<6) |
+                               ((key->contents[i*8+6]&1)<<7));
+
+       mit_des_fixup_key_parity(key->contents+i*8);
+    }
+
+    return(0);
+}
+
+static krb5_error_code
+k5_des3_encrypt_iov(const krb5_keyblock *key,
+                   const krb5_data *ivec,
+                   krb5_crypto_iov *data,
+                   size_t num_data)
+{
+    mit_des3_key_schedule schedule;
+    krb5_error_code err;
+
+    err = validate_and_schedule_iov(key, ivec, data, num_data, &schedule);
+    if (err)
+       return err;
+
+    /* this has a return value, but the code always returns zero */
+    krb5int_des3_cbc_encrypt_iov(data, num_data,
+                            schedule[0], schedule[1], schedule[2],
+                            ivec != NULL ? (unsigned char *) ivec->data : NULL);
+
+    zap(schedule, sizeof(schedule));
+
+    return(0);
+}
+
+static krb5_error_code
+k5_des3_decrypt_iov(const krb5_keyblock *key,
+                   const krb5_data *ivec,
+                   krb5_crypto_iov *data,
+                   size_t num_data)
+{
+    mit_des3_key_schedule schedule;
+    krb5_error_code err;
+
+    err = validate_and_schedule_iov(key, ivec, data, num_data, &schedule);
+    if (err)
+       return err;
+
+    /* this has a return value, but the code always returns zero */
+    krb5int_des3_cbc_decrypt_iov(data, num_data,
+                                schedule[0], schedule[1], schedule[2],
+                                ivec != NULL ? (unsigned char *) ivec->data : NULL);
+
+    zap(schedule, sizeof(schedule));
+
+    return(0);
+}
+
+const struct krb5_enc_provider krb5int_enc_des3 = {
+    8,
+    21, 24,
+    k5_des3_encrypt,
+    k5_des3_decrypt,
+    k5_des3_make_key,
+    krb5int_des_init_state,
+    krb5int_default_free_state,
+    k5_des3_encrypt_iov,
+    k5_des3_decrypt_iov
+};
+
diff --git a/src/lib/crypto/builtin/enc_provider/enc_provider.h b/src/lib/crypto/builtin/enc_provider/enc_provider.h
new file mode 100644 (file)
index 0000000..92022b3
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * 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 FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+
+extern const struct krb5_enc_provider krb5int_enc_des;
+extern const struct krb5_enc_provider krb5int_enc_des3;
+extern const struct krb5_enc_provider krb5int_enc_arcfour;
+extern const struct krb5_enc_provider krb5int_enc_aes128;
+extern const struct krb5_enc_provider krb5int_enc_aes256;
+extern const struct krb5_enc_provider krb5int_enc_aes128_ctr;
+extern const struct krb5_enc_provider krb5int_enc_aes256_ctr;
+
diff --git a/src/lib/crypto/builtin/enc_provider/rc4.c b/src/lib/crypto/builtin/enc_provider/rc4.c
new file mode 100644 (file)
index 0000000..d1dbb6c
--- /dev/null
@@ -0,0 +1,271 @@
+/* arcfour.c 
+ *
+ * Copyright (c) 2000 by Computer Science Laboratory,
+ *                       Rensselaer Polytechnic Institute
+ *
+ * #include STD_DISCLAIMER
+ */
+
+#include "k5-int.h"
+#include "arcfour-int.h"
+#include "enc_provider.h"
+#include <aead.h>
+/* gets the next byte from the PRNG */
+#if ((__GNUC__ >= 2) )
+static __inline__ unsigned int k5_arcfour_byte(ArcfourContext *);
+#else
+static unsigned int k5_arcfour_byte(ArcfourContext *);
+#endif /* gcc inlines*/
+
+/* Initializes the context and sets the key. */
+static krb5_error_code k5_arcfour_init(ArcfourContext *ctx, const unsigned char *key, 
+                 unsigned int keylen);
+
+/* Encrypts/decrypts data. */
+static void k5_arcfour_crypt(ArcfourContext *ctx, unsigned char *dest, 
+                    const unsigned char *src, unsigned int len);
+
+/* Interface layer to kerb5 crypto layer */
+static krb5_error_code
+k5_arcfour_docrypt(const krb5_keyblock *, const krb5_data *,
+                  const krb5_data *, krb5_data *);
+
+/* from a random bitstrem, construct a key */
+static krb5_error_code
+k5_arcfour_make_key(const krb5_data *, krb5_keyblock *);
+
+static const unsigned char arcfour_weakkey1[] = {0x00, 0x00, 0xfd};
+static const unsigned char arcfour_weakkey2[] = {0x03, 0xfd, 0xfc};
+static const struct {
+    size_t length;
+    const unsigned char *data;
+} arcfour_weakkeys[] = {
+    { sizeof (arcfour_weakkey1), arcfour_weakkey1},
+    { sizeof (arcfour_weakkey2), arcfour_weakkey2},
+};
+
+static inline unsigned int k5_arcfour_byte(ArcfourContext * ctx)
+{
+  unsigned int x;
+  unsigned int y;
+  unsigned int sx, sy;
+  unsigned char *state;
+
+  state = ctx->state;
+  x = (ctx->x + 1) & 0xff;
+  sx = state[x];
+  y = (sx + ctx->y) & 0xff;
+  sy = state[y];
+  ctx->x = x;
+  ctx->y = y;
+  state[y] = sx;
+  state[x] = sy;
+  return state[(sx + sy) & 0xff];
+}
+
+static void k5_arcfour_crypt(ArcfourContext *ctx, unsigned char *dest, 
+                    const unsigned char *src, unsigned int len)
+{
+  unsigned int i;
+  for (i = 0; i < len; i++)
+    dest[i] = src[i] ^ k5_arcfour_byte(ctx);
+}
+
+
+static krb5_error_code
+k5_arcfour_init(ArcfourContext *ctx, const unsigned char *key, 
+                 unsigned int key_len)
+{
+  unsigned int t, u;
+  unsigned int keyindex;
+  unsigned int stateindex;
+  unsigned char* state;
+  unsigned int counter;
+
+  if (key_len != 16)
+    return KRB5_BAD_MSIZE;     /*this is probably not the correct error code
+                                to return */
+  for (counter=0;
+       counter < sizeof(arcfour_weakkeys)/sizeof(arcfour_weakkeys[0]);
+       counter++)
+      if (!memcmp(key, arcfour_weakkeys[counter].data,
+                 arcfour_weakkeys[counter].length))
+         return KRB5DES_WEAK_KEY; /* most certainly not the correct error */
+
+  state = &ctx->state[0];
+  ctx->x = 0;
+  ctx->y = 0;
+  for (counter = 0; counter < 256; counter++)
+    state[counter] = counter;
+  keyindex = 0;
+  stateindex = 0;
+  for (counter = 0; counter < 256; counter++)
+    {
+      t = state[counter];
+      stateindex = (stateindex + key[keyindex] + t) & 0xff;
+      u = state[stateindex];
+      state[stateindex] = t;
+      state[counter] = u;
+      if (++keyindex >= key_len)
+       keyindex = 0;
+    }
+  return 0;
+}
+
+
+/* The workhorse of the arcfour system, this impliments the cipher */
+static krb5_error_code
+k5_arcfour_docrypt(const krb5_keyblock *key, const krb5_data *state,
+              const krb5_data *input, krb5_data *output)
+{
+  ArcfourContext *arcfour_ctx;
+  ArcFourCipherState *cipher_state;
+  int ret;
+
+  if (key->length != 16)
+    return(KRB5_BAD_KEYSIZE);
+  if (state && (state->length != sizeof (ArcFourCipherState)))
+    return(KRB5_BAD_MSIZE);
+  if (input->length != output->length)
+    return(KRB5_BAD_MSIZE);
+
+  if (state) {
+    cipher_state = (ArcFourCipherState *) state->data;
+    arcfour_ctx=&cipher_state->ctx;
+    if (cipher_state->initialized == 0) {
+      if ((ret=k5_arcfour_init(arcfour_ctx, key->contents, key->length))) {
+       return ret;
+      }
+      cipher_state->initialized = 1;
+    }
+    k5_arcfour_crypt(arcfour_ctx, (unsigned char *) output->data, (const unsigned char *) input->data, input->length);
+  }
+  else {
+    arcfour_ctx=malloc(sizeof (ArcfourContext));
+    if (arcfour_ctx == NULL)
+      return ENOMEM;
+    if ((ret=k5_arcfour_init(arcfour_ctx, key->contents, key->length))) {
+      free(arcfour_ctx);
+      return (ret);
+    }
+    k5_arcfour_crypt(arcfour_ctx, (unsigned char * ) output->data,
+                    (const unsigned char * ) input->data, input->length);
+    memset(arcfour_ctx, 0, sizeof (ArcfourContext));
+    free(arcfour_ctx);
+  }
+  
+  return 0;
+}
+
+/* In-place encryption */
+static krb5_error_code
+k5_arcfour_docrypt_iov(const krb5_keyblock *key,
+                      const krb5_data *state,
+                      krb5_crypto_iov *data,
+                      size_t num_data)
+{
+    ArcfourContext *arcfour_ctx = NULL;
+    ArcFourCipherState *cipher_state = NULL;
+    krb5_error_code ret;
+    size_t i;
+
+    if (key->length != 16)
+       return KRB5_BAD_KEYSIZE;
+    if (state != NULL && (state->length != sizeof(ArcFourCipherState)))
+       return KRB5_BAD_MSIZE;
+
+    if (state != NULL) {
+       cipher_state = (ArcFourCipherState *)state->data;
+       arcfour_ctx = &cipher_state->ctx;
+       if (cipher_state->initialized == 0) {
+           ret = k5_arcfour_init(arcfour_ctx, key->contents, key->length);
+           if (ret != 0)
+               return ret;
+
+           cipher_state->initialized = 1;
+       }
+    } else {
+       arcfour_ctx = (ArcfourContext *)malloc(sizeof(ArcfourContext));
+       if (arcfour_ctx == NULL)
+           return ENOMEM;
+
+       ret = k5_arcfour_init(arcfour_ctx, key->contents, key->length);
+       if (ret != 0) {
+           free(arcfour_ctx);
+           return ret;
+       }
+    }
+
+    for (i = 0; i < num_data; i++) {
+       krb5_crypto_iov *iov = &data[i];
+
+       if (ENCRYPT_IOV(iov))
+           k5_arcfour_crypt(arcfour_ctx, (unsigned char *)iov->data.data,
+                            (const unsigned char *)iov->data.data, iov->data.length);
+    }
+
+    if (state == NULL) {
+       memset(arcfour_ctx, 0, sizeof(ArcfourContext));
+       free(arcfour_ctx);
+    }
+
+    return 0;
+}
+
+static krb5_error_code
+k5_arcfour_make_key(const krb5_data *randombits, krb5_keyblock *key)
+{
+    if (key->length != 16)
+       return(KRB5_BAD_KEYSIZE);
+    if (randombits->length != 16)
+       return(KRB5_CRYPTO_INTERNAL);
+
+    key->magic = KV5M_KEYBLOCK;
+    key->length = 16;
+
+    memcpy(key->contents, randombits->data, randombits->length);
+
+    return(0);
+}
+
+static krb5_error_code
+k5_arcfour_init_state (const krb5_keyblock *key,
+                      krb5_keyusage keyusage, krb5_data *new_state)
+{
+  /* Note that we can't actually set up the state here  because the key
+   * will change  between now and when encrypt is called
+   * because  it is data dependent.  Yeah, this has strange
+   * properties. --SDH
+   */
+  new_state->length = sizeof (ArcFourCipherState);
+  new_state->data = malloc (new_state->length);
+  if (new_state->data) {
+    memset (new_state->data, 0 , new_state->length);
+    /* That will set initialized to zero*/
+  }else {
+    return (ENOMEM);
+  }
+  return 0;
+}
+
+/* Since the arcfour cipher is identical going forwards and backwards, 
+   we just call "docrypt" directly
+*/
+const struct krb5_enc_provider krb5int_enc_arcfour = {
+    /* This seems to work... although I am not sure what the
+       implications are in other places in the kerberos library */
+    1,
+    /* Keysize is arbitrary in arcfour, but the constraints of the
+       system, and to attempt to work with the MSFT system forces us
+       to 16byte/128bit.  Since there is no parity in the key, the
+       byte and length are the same.  */
+    16, 16,
+    k5_arcfour_docrypt,
+    k5_arcfour_docrypt,
+    k5_arcfour_make_key,
+    k5_arcfour_init_state, /*xxx not implemented yet*/
+    krb5int_default_free_state,
+    k5_arcfour_docrypt_iov,
+    k5_arcfour_docrypt_iov
+};
+
index 78dd0534b50f468c0906b561ad9708757020913c..480906bc6bb10d6f31c020041f17b031c475cbdd 100644 (file)
@@ -12,11 +12,11 @@ DEFS=
 PROG_LIBPATH=-L$(TOPLIBD)
 PROG_RPATH=$(KRB5_LIBDIR)
 
-STLIBOBJS= md4.o
+STLIBOBJS= ../../@CRYPTO_IMPL@/md4/md4.o
 
-OBJS= $(OUTPRE)md4.$(OBJEXT) 
+OBJS= $(OUTPRE)../../@CRYPTO_IMPL@/md4/md4.$(OBJEXT) 
 
-SRCS= $(srcdir)/md4.c
+SRCS= $(srcdir)/../../@CRYPTO_IMPL@/md4/md4.c
 
 ##DOS##LIBOBJS = $(OBJS)
 
index 6da43749d472bf13c907c87aaa1316530b8a633f..929291906587b537355f7e381ef7c6accb412e58 100644 (file)
@@ -11,11 +11,11 @@ DEFS=
 PROG_LIBPATH=-L$(TOPLIBD)
 PROG_RPATH=$(KRB5_LIBDIR)
 
-STLIBOBJS= md5.o
+STLIBOBJS= ../../@CRYPTO_IMPL@/md5/md5.o
 
-OBJS= $(OUTPRE)md5.$(OBJEXT) 
+OBJS= $(OUTPRE)../../@CRYPTO_IMPL@/md5/md5.$(OBJEXT) 
 
-SRCS= $(srcdir)/md5.c
+SRCS= $(srcdir)/../../@CRYPTO_IMPL@/md5/md5.c
 
 ##DOS##LIBOBJS = $(OBJS)
 
index 81776f57bc399524b99dde4ca919a84bbffc6740..7610881881f40acfa05d2ccac335f425191d6163 100644 (file)
@@ -11,11 +11,11 @@ DEFS=
 PROG_LIBPATH=-L$(TOPLIBD)
 PROG_RPATH=$(KRB5_LIBDIR)
 
-STLIBOBJS= shs.o
+STLIBOBJS= ../../@CRYPTO_IMPL@/sha1/shs.o
 
-OBJS= $(OUTPRE)shs.$(OBJEXT) 
+OBJS= $(OUTPRE)../../@CRYPTO_IMPL@/sha1/shs.$(OBJEXT) 
 
-SRCS= $(srcdir)/shs.c
+SRCS= $(srcdir)/../../@CRYPTO_IMPL@/sha1/shs.c
 
 ##DOS##LIBOBJS = $(OBJS)
 
index 4e33e83b8de92cc70d0e2a26fd53b8e2214461d7..41704c85c28451ce68125e00bb3e573d05289bf4 100644 (file)
@@ -2,7 +2,7 @@ thisconfigdir=../../..
 myfulldir=lib/crypto/crypto_tests
 mydir=lib/crypto/crypto_tests
 BUILDTOP=$(REL)..$(S)..$(S)..
-LOCALINCLUDES = -I$(srcdir)/../krb -I$(srcdir)/../krb/enc_provider             \
+LOCALINCLUDES = -I$(srcdir)/../krb -I$(srcdir)/../@CRYPTO_IMPL@/enc_provider           \
        -I$(srcdir)/../krb/hash_provider -I$(srcdir)/../krb/keyhash_provider    \
        -I$(srcdir)/../krb/dk -I$(srcdir)/../@CRYPTO_IMPL@/                     \
        -I$(srcdir)/../krb/yarrow       \
index 887fa160f0add6370a6db813fb9225a8374fc613..636d2c6cddd73aaa1da3400ffc12cf220455a21e 100644 (file)
@@ -2,11 +2,11 @@ thisconfigdir=../../..
 myfulldir=lib/crypto/krb
 mydir=lib/crypto/krb
 BUILDTOP=$(REL)..$(S)..$(S)..
-SUBDIRS= crc32 dk enc_provider hash_provider keyhash_provider \
+SUBDIRS= crc32 dk hash_provider keyhash_provider \
         old raw yarrow 
-LOCALINCLUDES = -I$(srcdir) -I$(srcdir)/enc_provider -I$(srcdir)/dk    \
-               -I$(srcdir)/hash_provider -I$(srcdir)/keyhash_provider  \
-               -I$(srcdir)/old -I$(srcdir)/raw -I$(srcdir)/yarrow      \
+LOCALINCLUDES = -I$(srcdir) -I$(srcdir)/../@CRYPTO_IMPL@/enc_provider -I$(srcdir)/dk   \
+               -I$(srcdir)/hash_provider -I$(srcdir)/keyhash_provider                  \
+               -I$(srcdir)/old -I$(srcdir)/raw -I$(srcdir)/yarrow                      \
                -I$(srcdir)/../@CRYPTO_IMPL@/ -I$(srcdir)/../@CRYPTO_IMPL@/des          \
                -I$(srcdir)/../@CRYPTO_IMPL@/aes -I$(srcdir)/../@CRYPTO_IMPL@/arcfour   \
                -I$(srcdir)/../@CRYPTO_IMPL@/sha1
@@ -149,11 +149,11 @@ SRCS=\
        $(srcdir)/verify_checksum.c     \
        $(srcdir)/verify_checksum_iov.c
 
-STOBJLISTS=crc32/OBJS.ST  dk/OBJS.ST enc_provider/OBJS.ST      \
+STOBJLISTS=crc32/OBJS.ST  dk/OBJS.ST                           \
        hash_provider/OBJS.ST keyhash_provider/OBJS.ST          \
        old/OBJS.ST raw/OBJS.ST  yarrow/OBJS.ST  OBJS.ST
 
-SUBDIROBJLISTS=crc32/OBJS.ST  dk/OBJS.ST enc_provider/OBJS.ST  \
+SUBDIROBJLISTS=crc32/OBJS.ST  dk/OBJS.ST                       \
        hash_provider/OBJS.ST keyhash_provider/OBJS.ST          \
        old/OBJS.ST raw/OBJS.ST  yarrow/OBJS.ST OBJS.ST 
 
@@ -173,9 +173,6 @@ all-windows::
        cd ..\dk
        @echo Making in crypto\dk
        $(MAKE) -$(MFLAGS)
-       cd ..\enc_provider
-       @echo Making in crypto\enc_provider
-       $(MAKE) -$(MFLAGS)
        cd ..\hash_provider
        @echo Making in crypto\hash_provider
        $(MAKE) -$(MFLAGS)
@@ -200,9 +197,6 @@ clean-windows::
        cd ..\dk
        @echo Making clean in crypto\dk
        $(MAKE) -$(MFLAGS) clean
-       cd ..\enc_provider
-       @echo Making clean in crypto\enc_provider
-       $(MAKE) -$(MFLAGS) clean
        cd ..\hash_provider
        @echo Making clean in crypto\hash_provider
        $(MAKE) -$(MFLAGS) clean
@@ -227,9 +221,6 @@ check-windows::
        cd ..\dk
        @echo Making check in crypto\dk
        $(MAKE) -$(MFLAGS) check
-       cd ..\enc_provider
-       @echo Making check in crypto\enc_provider
-       $(MAKE) -$(MFLAGS) check
        cd ..\hash_provider
        @echo Making check in crypto\hash_provider
        $(MAKE) -$(MFLAGS) check
index fa65836789cab2f898da8e67e52fe78c93afca4e..58a614bdf4d0c76259758e0d195a22375c9cdc09 100644 (file)
@@ -192,7 +192,7 @@ etypes.so etypes.po $(OUTPRE)etypes.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
   $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
   $(srcdir)/../builtin/aes/aes_s2k.h $(srcdir)/../builtin/arcfour/arcfour.h \
   $(srcdir)/../builtin/des/des_int.h $(srcdir)/dk/dk.h \
-  $(srcdir)/enc_provider/enc_provider.h $(srcdir)/hash_provider/hash_provider.h \
+  $(srcdir)/../builtin/enc_provider/enc_provider.h $(srcdir)/hash_provider/hash_provider.h \
   $(srcdir)/old/old.h $(srcdir)/raw/raw.h etypes.c etypes.h
 keyblocks.so keyblocks.po $(OUTPRE)keyblocks.$(OBJEXT): \
   $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
@@ -326,7 +326,7 @@ prng.so prng.po $(OUTPRE)prng.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
   $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/krb5.h \
   $(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \
   $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
-  $(srcdir)/../builtin/sha1/shs.h $(srcdir)/enc_provider/enc_provider.h \
+  $(srcdir)/../builtin/sha1/shs.h $(srcdir)/../builtin/enc_provider/enc_provider.h \
   $(srcdir)/yarrow/yarrow.h $(srcdir)/yarrow/ycipher.h \
   $(srcdir)/yarrow/yhash.h $(srcdir)/yarrow/ytypes.h \
   prng.c
index ca268106765f78d9e2ab4a7dff13570896e86911..780e1589ddecac4e229cc6e63de4369d1b9d372d 100644 (file)
@@ -49,6 +49,7 @@ k5_crc32_hash(unsigned int icount, const krb5_data *input,
 }
 
 const struct krb5_hash_provider krb5int_hash_crc32 = {
+    "CRC32",
     CRC32_CKSUM_LENGTH,
     1,
     k5_crc32_hash
index 1fa23c214e56c2528a71b649bad5dfe6eee9bf1f..f507aaaf7dfafe5b2a80a8396f82a6419b9e9388 100644 (file)
@@ -49,6 +49,7 @@ k5_md4_hash(unsigned int icount, const krb5_data *input,
 }
 
 const struct krb5_hash_provider krb5int_hash_md4 = {
+    "MD4",
     RSA_MD4_CKSUM_LENGTH,
     64,
     k5_md4_hash
index 174c432a40df25c913958ade69354931b83f8a2a..a6e380ae2dc2062f6516dbef9487a6161ae88ce2 100644 (file)
@@ -49,6 +49,7 @@ k5_md5_hash(unsigned int icount, const krb5_data *input,
 }
 
 const struct krb5_hash_provider krb5int_hash_md5 = {
+    "MD5",
     RSA_MD5_CKSUM_LENGTH,
     64,
     k5_md5_hash
index ffc073cf140a1a008d1c966242a6fd9c9610611c..00ab72bda6c37a43b89a0b635f1358092d1896fe 100644 (file)
@@ -51,6 +51,7 @@ k5_sha1_hash(unsigned int icount, const krb5_data *input,
 }
 
 const struct krb5_hash_provider krb5int_hash_sha1 = {
+    "SHA1",
     SHS_DIGESTSIZE,
     SHS_DATASIZE,
     k5_sha1_hash
index d7f01e4692f6c14b76a953ba251fd35cd5f2b81e..b246c6cc05e9b85cb40de4b31178393bf3f64577 100644 (file)
@@ -2,7 +2,7 @@ thisconfigdir=../../../..
 myfulldir=lib/crypto/krb/yarrow
 mydir=lib/crypto/krb/yarrow
 BUILDTOP=$(REL)..$(S)..$(S)..$(S)..
-LOCALINCLUDES = -I$(srcdir)/.. -I$(srcdir)/../../@CRYPTO_IMPL@ -I$(srcdir)/../../@CRYPTO_IMPL@/sha1 -I$(srcdir)/../enc_provider
+LOCALINCLUDES = -I$(srcdir)/.. -I$(srcdir)/../../@CRYPTO_IMPL@ -I$(srcdir)/../../@CRYPTO_IMPL@/sha1 -I$(srcdir)/../../@CRYPTO_IMPL@/enc_provider
 DEFS=
 
 ##DOS##BUILDTOP = ..\..\..\..
index 8d69431f6191d938f473f1715d15a1030b94a90d..ed10e313735357defa8d7aba45e7a05ff090bb6d 100644 (file)
@@ -21,5 +21,5 @@ ycipher.so ycipher.po $(OUTPRE)ycipher.$(OBJEXT): $(BUILDTOP)/include/autoconf.h
   $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/krb5.h \
   $(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \
   $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
-  $(srcdir)/../../builtin/sha1/shs.h $(srcdir)/../enc_provider/enc_provider.h \
+  $(srcdir)/../../builtin/sha1/shs.h $(srcdir)/../../builtin/enc_provider/enc_provider.h \
   yarrow.h ycipher.c ycipher.h yhash.h ytypes.h
diff --git a/src/lib/crypto/openssl/enc_provider/deps b/src/lib/crypto/openssl/enc_provider/deps
new file mode 100644 (file)
index 0000000..1d4dcbe
--- /dev/null
@@ -0,0 +1,50 @@
+# 
+# Generated makefile dependencies follow.
+#
+des.so des.po $(OUTPRE)des.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+  $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/autoconf.h \
+  $(SRCTOP)/include/k5-buf.h $(SRCTOP)/include/k5-err.h \
+  $(SRCTOP)/include/k5-gmt_mktime.h $(SRCTOP)/include/k5-int-pkinit.h \
+  $(SRCTOP)/include/k5-int.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-plugin.h $(SRCTOP)/include/k5-thread.h \
+  $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \
+  $(SRCTOP)/include/krb5/preauth_plugin.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(srcdir)/../../builtin/des/des_int.h \
+  $(srcdir)/../../krb/aead.h $(srcdir)/../cksumtypes.h des.c \
+  enc_provider.h
+des3.so des3.po $(OUTPRE)des3.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+  $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/autoconf.h \
+  $(SRCTOP)/include/k5-buf.h $(SRCTOP)/include/k5-err.h \
+  $(SRCTOP)/include/k5-gmt_mktime.h $(SRCTOP)/include/k5-int-pkinit.h \
+  $(SRCTOP)/include/k5-int.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-plugin.h $(SRCTOP)/include/k5-thread.h \
+  $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \
+  $(SRCTOP)/include/krb5/preauth_plugin.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(srcdir)/../../builtin/des/des_int.h \
+  $(srcdir)/../../krb/aead.h $(srcdir)/../cksumtypes.h des3.c
+aes.so aes.po $(OUTPRE)aes.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+  $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/autoconf.h \
+  $(SRCTOP)/include/k5-buf.h $(SRCTOP)/include/k5-err.h \
+  $(SRCTOP)/include/k5-gmt_mktime.h $(SRCTOP)/include/k5-int-pkinit.h \
+  $(SRCTOP)/include/k5-int.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-plugin.h $(SRCTOP)/include/k5-thread.h \
+  $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \
+  $(SRCTOP)/include/krb5/preauth_plugin.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(srcdir)/../../builtin/aes/aes.h \
+  $(srcdir)/../../builtin/aes/uitypes.h $(srcdir)/../../krb/aead.h \
+  $(srcdir)/../cksumtypes.h aes.c enc_provider.h
+rc4.so rc4.po $(OUTPRE)rc4.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+  $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/autoconf.h \
+  $(SRCTOP)/include/k5-buf.h $(SRCTOP)/include/k5-err.h \
+  $(SRCTOP)/include/k5-gmt_mktime.h $(SRCTOP)/include/k5-int-pkinit.h \
+  $(SRCTOP)/include/k5-int.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-plugin.h $(SRCTOP)/include/k5-thread.h \
+  $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \
+  $(SRCTOP)/include/krb5/preauth_plugin.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(srcdir)/../../builtin/arcfour/arcfour-int.h \
+  $(srcdir)/../../builtin/arcfour/arcfour.h $(srcdir)/../../krb/aead.h \
+  $(srcdir)/../cksumtypes.h enc_provider.h rc4.c
diff --git a/src/lib/crypto/openssl/enc_provider/des.c b/src/lib/crypto/openssl/enc_provider/des.c
new file mode 100644 (file)
index 0000000..bc43136
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ */
+
+#include "k5-int.h"
+#include "des_int.h"
+#include "enc_provider.h"
+#include <aead.h>
+#include <openssl/evp.h>
+
+#define DES_BLOCK_SIZE  8
+#define DES_KEY_BYTES   7
+#define DES_KEY_LEN     8
+
+static krb5_error_code
+k5_des_encrypt(const krb5_keyblock *key, const krb5_data *ivec,
+           const krb5_data *input, krb5_data *output)
+{
+    int ret = 0, tmp_len = 0;
+    EVP_CIPHER_CTX  ciph_ctx;
+    unsigned char   *keybuf  = NULL;
+    unsigned char   *tmp_buf = NULL;
+    unsigned char   iv[EVP_MAX_IV_LENGTH];
+
+    if (key->length != DES_KEY_LEN)
+        return(KRB5_BAD_KEYSIZE);
+    if ((input->length%8) != 0)
+    return(KRB5_BAD_MSIZE);
+    if (ivec && (ivec->length != 8))
+    return(KRB5_BAD_MSIZE);
+    if (input->length != output->length)
+    return(KRB5_BAD_MSIZE);
+
+    keybuf=key->contents;
+    keybuf[key->length] = '\0';
+
+    if ( ivec && ivec->data ) {
+        memset(iv,0,sizeof(iv));
+        memcpy(iv,ivec->data,ivec->length);
+    }
+
+    tmp_buf=OPENSSL_malloc(output->length);
+    if (!tmp_buf)
+        return ENOMEM;
+    memset(tmp_buf,0,output->length);
+
+    EVP_CIPHER_CTX_init(&ciph_ctx);
+
+    ret = EVP_EncryptInit_ex(&ciph_ctx, EVP_des_cbc(), NULL, keybuf,
+                             (ivec && ivec->data) ? iv : NULL);
+    if (ret) {
+        EVP_CIPHER_CTX_set_padding(&ciph_ctx,0);
+        ret = EVP_EncryptUpdate(&ciph_ctx, tmp_buf,  &tmp_len,
+                                (unsigned char *)input->data, input->length);
+        if (ret) {
+            output->length = tmp_len;
+            ret = EVP_EncryptFinal_ex(&ciph_ctx, tmp_buf + tmp_len, &tmp_len);
+        }
+    }
+
+    EVP_CIPHER_CTX_cleanup(&ciph_ctx);
+
+    if (ret)
+        memcpy(output->data,tmp_buf, output->length);
+
+    memset(tmp_buf,0,output->length);
+    OPENSSL_free(tmp_buf);
+
+    if (!ret)
+        return KRB5_CRYPTO_INTERNAL;
+    return 0;
+}
+
+static krb5_error_code
+k5_des_decrypt(const krb5_keyblock *key, const krb5_data *ivec,
+           const krb5_data *input, krb5_data *output)
+{
+    /* key->enctype was checked by the caller */
+    int ret = 0, tmp_len = 0;
+    EVP_CIPHER_CTX  ciph_ctx;
+    unsigned char   *keybuf  = NULL;
+    unsigned char   *tmp_buf;
+    unsigned char   iv[EVP_MAX_IV_LENGTH];
+
+    if (key->length != DES_KEY_LEN)
+        return(KRB5_BAD_KEYSIZE);
+    if ((input->length%8) != 0)
+        return(KRB5_BAD_MSIZE);
+    if (ivec && (ivec->length != 8))
+        return(KRB5_BAD_MSIZE);
+    if (input->length != output->length)
+        return(KRB5_BAD_MSIZE);
+
+    keybuf=key->contents;
+    keybuf[key->length] = '\0';
+
+    if ( ivec != NULL && ivec->data ){
+        memset(iv,0,sizeof(iv));
+        memcpy(iv,ivec->data,ivec->length);
+    }
+
+    tmp_buf=OPENSSL_malloc(output->length);
+    if (!tmp_buf)
+        return ENOMEM;
+    memset(tmp_buf,0,output->length);
+
+    EVP_CIPHER_CTX_init(&ciph_ctx);
+
+    ret = EVP_DecryptInit_ex(&ciph_ctx, EVP_des_cbc(), NULL, keybuf,
+                             (ivec && ivec->data) ? iv : NULL);
+    if (ret) {
+        EVP_CIPHER_CTX_set_padding(&ciph_ctx,0);
+        ret = EVP_DecryptUpdate(&ciph_ctx, tmp_buf,  &tmp_len,
+                                (unsigned char *)input->data, input->length);
+        if (ret) {
+            output->length = tmp_len;
+            ret = EVP_DecryptFinal_ex(&ciph_ctx, tmp_buf+tmp_len, &tmp_len);
+        }
+    }
+
+    EVP_CIPHER_CTX_cleanup(&ciph_ctx);
+
+    if (ret)
+        memcpy(output->data,tmp_buf, output->length);
+
+    memset(tmp_buf,0,output->length );
+    OPENSSL_free(tmp_buf);
+
+    if (!ret)
+        return KRB5_CRYPTO_INTERNAL;
+    return 0;
+}
+
+static krb5_error_code
+k5_des_make_key(const krb5_data *randombits, krb5_keyblock *key)
+{
+    if (key->length != DES_KEY_LEN)
+    return(KRB5_BAD_KEYSIZE);
+    if (randombits->length != 7)
+    return(KRB5_CRYPTO_INTERNAL);
+
+    key->magic = KV5M_KEYBLOCK;
+
+    /* take the seven bytes, move them around into the top 7 bits of the
+       8 key bytes, then compute the parity bits */
+
+    memcpy(key->contents, randombits->data, randombits->length);
+    key->contents[7] = (((key->contents[0]&1)<<1) | ((key->contents[1]&1)<<2) |
+            ((key->contents[2]&1)<<3) | ((key->contents[3]&1)<<4) |
+            ((key->contents[4]&1)<<5) | ((key->contents[5]&1)<<6) |
+            ((key->contents[6]&1)<<7));
+
+    mit_des_fixup_key_parity(key->contents);
+
+    return(0);
+}
+
+static krb5_error_code
+k5_des_encrypt_iov(const krb5_keyblock *key,
+            const krb5_data *ivec,
+            krb5_crypto_iov *data,
+            size_t num_data)
+{
+    int ret = 0, tmp_len = 0;
+    unsigned int i = 0;
+    EVP_CIPHER_CTX  ciph_ctx;
+    unsigned char   *keybuf = NULL ;
+    krb5_crypto_iov *iov    = NULL;
+    unsigned char   *tmp_buf = NULL;
+    unsigned char   iv[EVP_MAX_IV_LENGTH];
+
+    if (ivec  && ivec->data){
+        memset(iv,0,sizeof(iv));
+        memcpy(iv,ivec->data,ivec->length);
+     }
+
+    EVP_CIPHER_CTX_init(&ciph_ctx);
+
+    ret = EVP_EncryptInit_ex(&ciph_ctx, EVP_des_cbc(), NULL,
+                             keybuf, (ivec && ivec->data) ? iv : NULL);
+    if (!ret)
+        return KRB5_CRYPTO_INTERNAL;
+
+    for (i = 0; i < num_data; i++) {
+        iov = &data[i];
+        if (iov->data.length <= 0) break;
+        tmp_len = iov->data.length;
+
+        if (ENCRYPT_DATA_IOV(iov)) {
+            tmp_buf=(unsigned char *)iov->data.data;
+            ret = EVP_EncryptUpdate(&ciph_ctx, tmp_buf, &tmp_len,
+                                    (unsigned char *)iov->data.data, iov->data.length);
+            if (!ret) break;
+            iov->data.length = tmp_len;
+        }
+    }
+    if(ret)
+        ret = EVP_EncryptFinal_ex(&ciph_ctx, (unsigned char *)tmp_buf, &tmp_len);
+
+    if (ret)
+        iov->data.length += tmp_len;
+
+    EVP_CIPHER_CTX_cleanup(&ciph_ctx);
+
+    if (!ret)
+        return KRB5_CRYPTO_INTERNAL;
+    return 0;
+
+}
+
+static krb5_error_code
+k5_des_decrypt_iov(const krb5_keyblock *key,
+           const krb5_data *ivec,
+           krb5_crypto_iov *data,
+           size_t num_data)
+{
+    int ret = 0, tmp_len = 0;
+    unsigned int i = 0;
+    EVP_CIPHER_CTX  ciph_ctx;
+    unsigned char   *keybuf = NULL ;
+    krb5_crypto_iov *iov    = NULL;
+    unsigned char   *tmp_buf = NULL;
+    unsigned char   iv[EVP_MAX_IV_LENGTH];
+
+    if (ivec  && ivec->data){
+        memset(iv,0,sizeof(iv));
+        memcpy(iv,ivec->data,ivec->length);
+     }
+
+    ret = EVP_DecryptInit_ex(&ciph_ctx, EVP_des_cbc(), NULL,
+                             keybuf, (ivec && ivec->data) ? iv : NULL);
+    if (!ret)
+        return KRB5_CRYPTO_INTERNAL;
+
+    for (i = 0; i < num_data; i++) {
+        iov = &data[i];
+        if (iov->data.length <= 0) break;
+        tmp_len = iov->data.length;
+
+        if (ENCRYPT_DATA_IOV(iov)) {
+            tmp_buf=(unsigned char *)iov->data.data;
+            ret = EVP_DecryptUpdate(&ciph_ctx, tmp_buf, &tmp_len,
+                                    (unsigned char *)iov->data.data, iov->data.length);
+            if (!ret) break;
+            iov->data.length = tmp_len;
+        }
+    }
+    if(ret)
+        ret = EVP_DecryptFinal_ex(&ciph_ctx, (unsigned char *)tmp_buf, &tmp_len);
+
+    if (ret)
+        iov->data.length += tmp_len;
+
+    EVP_CIPHER_CTX_cleanup(&ciph_ctx);
+
+    if (!ret)
+        return KRB5_CRYPTO_INTERNAL;
+    return 0;
+}
+
+const struct krb5_enc_provider krb5int_enc_des = {
+    DES_BLOCK_SIZE,
+    DES_KEY_BYTES, DES_KEY_LEN,
+    k5_des_encrypt,
+    k5_des_decrypt,
+    k5_des_make_key,
+    krb5int_des_init_state,
+    krb5int_default_free_state,
+    k5_des_encrypt_iov,
+    k5_des_decrypt_iov
+};
+
diff --git a/src/lib/crypto/openssl/enc_provider/des3.c b/src/lib/crypto/openssl/enc_provider/des3.c
new file mode 100644 (file)
index 0000000..1cc6748
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ */
+
+#include "k5-int.h"
+#include "des_int.h"
+#include <aead.h>
+#include <openssl/evp.h>
+
+
+#define DES_BLOCK_SIZE  8
+#define DES3_KEY_BYTES  21
+#define DES3_KEY_LEN    24
+
+static krb5_error_code
+validate(const krb5_keyblock *key, const krb5_data *ivec,
+                     const krb5_data *input, const krb5_data *output)
+{
+    mit_des3_key_schedule schedule;
+
+    /* key->enctype was checked by the caller */
+
+    if (key->length != DES3_KEY_LEN)
+       return(KRB5_BAD_KEYSIZE);
+    if ((input->length%DES_BLOCK_SIZE) != 0)
+       return(KRB5_BAD_MSIZE);
+    if (ivec && (ivec->length != 8))
+       return(KRB5_BAD_MSIZE);
+    if (input->length != output->length)
+       return(KRB5_BAD_MSIZE);
+
+    switch (mit_des3_key_sched(*(mit_des3_cblock *)key->contents,
+                              schedule)) {
+    case -1:
+       return(KRB5DES_BAD_KEYPAR);
+    case -2:
+       return(KRB5DES_WEAK_KEY);
+    }
+    return 0;
+}
+
+static krb5_error_code
+validate_iov(const krb5_keyblock *key, const krb5_data *ivec,
+                         const krb5_crypto_iov *data, size_t num_data)
+{
+    size_t i, input_length;
+    mit_des3_key_schedule schedule;
+
+    for (i = 0, input_length = 0; i < num_data; i++) {
+       const krb5_crypto_iov *iov = &data[i];
+
+       if (ENCRYPT_IOV(iov))
+           input_length += iov->data.length;
+    }
+
+    if (key->length != DES3_KEY_LEN)
+       return(KRB5_BAD_KEYSIZE);
+    if ((input_length%DES_BLOCK_SIZE) != 0)
+       return(KRB5_BAD_MSIZE);
+    if (ivec && (ivec->length != 8))
+       return(KRB5_BAD_MSIZE);
+
+    switch (mit_des3_key_sched(*(mit_des3_cblock *)key->contents,
+                              schedule)) {
+    case -1:
+       return(KRB5DES_BAD_KEYPAR);
+    case -2:
+       return(KRB5DES_WEAK_KEY);
+    }
+    return 0;
+}
+
+static krb5_error_code
+k5_des3_encrypt(const krb5_keyblock *key, const krb5_data *ivec,
+               const krb5_data *input, krb5_data *output)
+{
+
+    int ret = 0, tmp_len = 0;
+    EVP_CIPHER_CTX  ciph_ctx;
+    unsigned char   *keybuf  = NULL;
+    unsigned char   *tmp_buf = NULL;
+    unsigned char   iv[EVP_MAX_IV_LENGTH];
+
+    ret = validate(key, ivec, input, output);
+    if (ret)
+       return ret;
+
+    keybuf=key->contents;
+    keybuf[key->length] = '\0';
+
+    if (ivec && ivec->data) {
+        memset(iv,0,sizeof(iv));
+        memcpy(iv,ivec->data,ivec->length);
+    }
+
+    tmp_buf = OPENSSL_malloc(output->length);
+    if (!tmp_buf)
+        return ENOMEM;
+
+    EVP_CIPHER_CTX_init(&ciph_ctx);
+
+    ret = EVP_EncryptInit_ex(&ciph_ctx, EVP_des_ede3_cbc(), NULL, keybuf,
+                             (ivec && ivec->data) ? iv : NULL);
+    if (ret) {
+        EVP_CIPHER_CTX_set_padding(&ciph_ctx,0);
+        ret = EVP_EncryptUpdate(&ciph_ctx, tmp_buf,  &tmp_len,
+                                (unsigned char *)input->data, input->length);
+        if (ret) {
+            output->length = tmp_len;
+            ret = EVP_EncryptFinal_ex(&ciph_ctx, tmp_buf+tmp_len, &tmp_len);
+        }
+    }
+
+    EVP_CIPHER_CTX_cleanup(&ciph_ctx);
+
+    if (ret)
+        memcpy(output->data,tmp_buf, output->length);
+    memset(tmp_buf,0,output->length);
+    OPENSSL_free(tmp_buf);
+
+    if (!ret)
+        return KRB5_CRYPTO_INTERNAL;
+    return 0;
+
+}
+
+static krb5_error_code
+k5_des3_decrypt(const krb5_keyblock *key, const krb5_data *ivec,
+               const krb5_data *input, krb5_data *output)
+{
+    int ret = 0, tmp_len = 0;
+    EVP_CIPHER_CTX  ciph_ctx;
+    unsigned char   *keybuf  = NULL;
+    unsigned char   *tmp_buf = NULL;
+    unsigned char   iv[EVP_MAX_IV_LENGTH];
+
+    ret = validate(key, ivec, input, output);
+    if (ret)
+       return ret;
+
+    keybuf=key->contents;
+    keybuf[key->length] = '\0';
+
+    if (ivec && ivec->data) {
+        memset(iv,0,sizeof(iv));
+        memcpy(iv,ivec->data,ivec->length);
+    }
+
+    tmp_buf=OPENSSL_malloc(output->length);
+    if (!tmp_buf)
+        return ENOMEM;
+
+    EVP_CIPHER_CTX_init(&ciph_ctx);
+
+    ret = EVP_DecryptInit_ex(&ciph_ctx, EVP_des_ede3_cbc(), NULL, keybuf,
+                             (ivec && ivec->data) ? iv: NULL);
+    if (ret) {
+        EVP_CIPHER_CTX_set_padding(&ciph_ctx,0);
+        ret = EVP_DecryptUpdate(&ciph_ctx, tmp_buf,  &tmp_len,
+                                (unsigned char *)input->data, input->length);
+        if (ret) {
+            output->length = tmp_len;
+            ret = EVP_DecryptFinal_ex(&ciph_ctx, tmp_buf+tmp_len, &tmp_len);
+        }
+    }
+
+    EVP_CIPHER_CTX_cleanup(&ciph_ctx);
+
+    if (ret)
+        memcpy(output->data,tmp_buf, output->length);
+
+    memset(tmp_buf,0,output->length);
+    OPENSSL_free(tmp_buf);
+
+    if (!ret)
+        return KRB5_CRYPTO_INTERNAL;
+    return 0;
+
+}
+
+static krb5_error_code
+k5_des3_make_key(const krb5_data *randombits, krb5_keyblock *key)
+{
+    int i;
+
+    if (key->length != DES3_KEY_LEN)
+       return(KRB5_BAD_KEYSIZE);
+    if (randombits->length != DES3_KEY_BYTES)
+       return(KRB5_CRYPTO_INTERNAL);
+
+    key->magic = KV5M_KEYBLOCK;
+
+    /* take the seven bytes, move them around into the top 7 bits of the
+       8 key bytes, then compute the parity bits.  Do this three times. */
+
+    for (i=0; i<3; i++) {
+       memcpy(key->contents+i*8, randombits->data+i*7, 7);
+       key->contents[i*8+7] = (((key->contents[i*8]&1)<<1) |
+                               ((key->contents[i*8+1]&1)<<2) |
+                               ((key->contents[i*8+2]&1)<<3) |
+                               ((key->contents[i*8+3]&1)<<4) |
+                               ((key->contents[i*8+4]&1)<<5) |
+                               ((key->contents[i*8+5]&1)<<6) |
+                               ((key->contents[i*8+6]&1)<<7));
+
+       mit_des_fixup_key_parity(key->contents+i*8);
+    }
+
+    return(0);
+}
+
+static krb5_error_code
+validate_and_schedule_iov(const krb5_keyblock *key, const krb5_data *ivec,
+                          const krb5_crypto_iov *data, size_t num_data,
+                          mit_des3_key_schedule *schedule)
+{
+    size_t i, input_length;
+
+    for (i = 0, input_length = 0; i < num_data; i++) {
+        const krb5_crypto_iov *iov = &data[i];
+
+        if (ENCRYPT_IOV(iov))
+            input_length += iov->data.length;
+    }
+
+    if (key->length != 24)
+        return(KRB5_BAD_KEYSIZE);
+    if ((input_length%8) != 0)
+        return(KRB5_BAD_MSIZE);
+    if (ivec && (ivec->length != 8))
+        return(KRB5_BAD_MSIZE);
+
+    switch (mit_des3_key_sched(*(mit_des3_cblock *)key->contents,
+                               *schedule)) {
+    case -1:
+        return(KRB5DES_BAD_KEYPAR);
+    case -2:
+        return(KRB5DES_WEAK_KEY);
+    }
+    return 0;
+}
+
+static krb5_error_code
+k5_des3_encrypt_iov(const krb5_keyblock *key,
+                   const krb5_data *ivec,
+                   krb5_crypto_iov *data,
+                   size_t num_data)
+{
+#if 0
+    int ret = 0, tmp_len = 0;
+    unsigned int i = 0;
+    EVP_CIPHER_CTX  ciph_ctx;
+    unsigned char   *keybuf = NULL ;
+    krb5_crypto_iov *iov    = NULL;
+    unsigned char   *tmp_buf = NULL;
+    unsigned char   iv[EVP_MAX_IV_LENGTH];
+
+    ret = validate_iov(key, ivec, data, num_data);
+    if (ret)
+       return ret;
+
+    if (ivec && ivec->data){
+        memset(iv,0,sizeof(iv));
+        memcpy(iv,ivec->data,ivec->length);
+    }
+
+
+    EVP_CIPHER_CTX_init(&ciph_ctx);
+
+    ret = EVP_EncryptInit_ex(&ciph_ctx, EVP_des_ede3_cbc(), NULL,
+                             keybuf, (ivec && ivec->data) ? iv : NULL);
+    if (!ret)
+        return KRB5_CRYPTO_INTERNAL;
+
+    for (i = 0; i < num_data; i++) {
+        iov = &data[i];
+        if (iov->data.length <= 0) break;
+        tmp_len = iov->data.length;
+
+        if (ENCRYPT_IOV(iov)) {
+            tmp_buf=(unsigned char *)iov->data.data;
+            ret = EVP_EncryptUpdate(&ciph_ctx, tmp_buf, &tmp_len,
+                                    (unsigned char *)iov->data.data, iov->data.length);
+            if (!ret) break;
+            iov->data.length = tmp_len;
+        }
+    }
+    if(ret)
+        ret = EVP_EncryptFinal_ex(&ciph_ctx, (unsigned char *)tmp_buf, &tmp_len);
+
+    if (ret)
+        iov->data.length += tmp_len;
+
+    EVP_CIPHER_CTX_cleanup(&ciph_ctx);
+
+    if (!ret)
+        return KRB5_CRYPTO_INTERNAL;
+    return 0;
+#endif
+
+//#if 0
+    mit_des3_key_schedule schedule;
+    krb5_error_code err;
+
+    err = validate_and_schedule_iov(key, ivec, data, num_data, &schedule);
+    if (err)
+        return err;
+
+    /* this has a return value, but the code always returns zero */
+    krb5int_des3_cbc_encrypt_iov(data, num_data,
+                            schedule[0], schedule[1], schedule[2],
+                            ivec != NULL ? (unsigned char *) ivec->data : NULL);
+
+    zap(schedule, sizeof(schedule));
+    return(0);
+//#endif
+}
+
+static krb5_error_code
+k5_des3_decrypt_iov(const krb5_keyblock *key,
+                   const krb5_data *ivec,
+                   krb5_crypto_iov *data,
+                   size_t num_data)
+{
+    mit_des3_key_schedule schedule;
+    krb5_error_code err;
+
+    err = validate_and_schedule_iov(key, ivec, data, num_data, &schedule);
+    if (err)
+        return err;
+
+    /* this has a return value, but the code always returns zero */
+    krb5int_des3_cbc_decrypt_iov(data, num_data,
+                                 schedule[0], schedule[1], schedule[2],
+                                 ivec != NULL ? (unsigned char *) ivec->data : NULL);
+
+    zap(schedule, sizeof(schedule));
+
+    return(0);
+}
+
+const struct krb5_enc_provider krb5int_enc_des3 = {
+    DES_BLOCK_SIZE,
+    DES3_KEY_BYTES, DES3_KEY_LEN,
+    k5_des3_encrypt,
+    k5_des3_decrypt,
+    k5_des3_make_key,
+    krb5int_des_init_state,
+    krb5int_default_free_state,
+    k5_des3_encrypt_iov,
+    k5_des3_decrypt_iov
+};
+
diff --git a/src/lib/crypto/openssl/enc_provider/enc_provider.h b/src/lib/crypto/openssl/enc_provider/enc_provider.h
new file mode 100644 (file)
index 0000000..d46e1b4
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * 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 FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+
+extern const struct krb5_enc_provider krb5int_enc_des;
+extern const struct krb5_enc_provider krb5int_enc_des3;
+extern const struct krb5_enc_provider krb5int_enc_arcfour;
+extern const struct krb5_enc_provider krb5int_enc_aes128;
+extern const struct krb5_enc_provider krb5int_enc_aes256;
+extern const struct krb5_enc_provider krb5int_enc_aes128_ctr;
+extern const struct krb5_enc_provider krb5int_enc_aes256_ctr;
+
diff --git a/src/lib/crypto/openssl/enc_provider/rc4.c b/src/lib/crypto/openssl/enc_provider/rc4.c
new file mode 100644 (file)
index 0000000..b82af52
--- /dev/null
@@ -0,0 +1,167 @@
+/* arcfour.c 
+ *
+ * #include STD_DISCLAIMER
+ */
+
+#include "k5-int.h"
+#include "arcfour-int.h"
+#include "enc_provider.h"
+#include <aead.h>
+#include <openssl/evp.h>
+
+#define RC4_KEY_SIZE 16
+#define RC4_BLOCK_SIZE 1 
+
+/* Interface layer to kerb5 crypto layer */
+static krb5_error_code
+k5_arcfour_docrypt(const krb5_keyblock *, const krb5_data *,
+           const krb5_data *, krb5_data *);
+
+/* from a random bitstrem, construct a key */
+static krb5_error_code
+k5_arcfour_make_key(const krb5_data *, krb5_keyblock *);
+
+static krb5_error_code 
+k5_arcfour_free_state ( krb5_data *state);
+static krb5_error_code
+k5_arcfour_init_state (const krb5_keyblock *key,
+               krb5_keyusage keyusage, krb5_data *new_state);
+
+/* The workhorse of the arcfour system, this impliments the cipher */
+static krb5_error_code
+k5_arcfour_docrypt(const krb5_keyblock *key, const krb5_data *state,
+           const krb5_data *input, krb5_data *output)
+{
+    int ret = 0, tmp_len = 0;
+    unsigned char   *keybuf  = NULL;
+    unsigned char   *tmp_buf = NULL;
+    EVP_CIPHER_CTX  ciph_ctx;
+
+    if (key->length != RC4_KEY_SIZE)
+        return(KRB5_BAD_KEYSIZE);
+
+    if (input->length != output->length)
+        return(KRB5_BAD_MSIZE);
+
+    keybuf=key->contents;
+    keybuf[key->length] = '\0';
+
+    EVP_CIPHER_CTX_init(&ciph_ctx);
+    ret = EVP_EncryptInit_ex(&ciph_ctx, EVP_rc4(), NULL, keybuf, NULL);
+    if (ret) {
+        tmp_buf=(unsigned char *)output->data;
+        ret = EVP_EncryptUpdate(&ciph_ctx, tmp_buf,  &tmp_len, (unsigned char *)input->data, input->length);
+        output->length = tmp_len;
+    }
+    if (ret) {
+        tmp_buf += tmp_len;
+        ret = EVP_EncryptFinal_ex(&ciph_ctx, tmp_buf, &tmp_len);
+    }
+    EVP_CIPHER_CTX_cleanup(&ciph_ctx);
+    output->length += tmp_len;
+
+    if (!ret)
+        return KRB5_CRYPTO_INTERNAL;
+    return 0;
+}
+
+
+/* In-place decryption */
+static krb5_error_code
+k5_arcfour_docrypt_iov(const krb5_keyblock *key,
+               const krb5_data *state,
+               krb5_crypto_iov *data,
+               size_t num_data)
+{
+    size_t i;
+    int ret = 0, tmp_len = 0;
+    EVP_CIPHER_CTX  ciph_ctx;
+    unsigned char   *keybuf = NULL ;
+    krb5_crypto_iov *iov    = NULL;
+    unsigned char   *tmp_buf = NULL;
+
+    keybuf=key->contents;
+    keybuf[key->length] = '\0';
+
+    EVP_CIPHER_CTX_init(&ciph_ctx);
+
+    ret = EVP_EncryptInit_ex(&ciph_ctx, EVP_rc4(), NULL, keybuf, NULL);
+    if (!ret) 
+        return -1;
+
+    for (i = 0; i < num_data; i++) {
+        iov = &data[i];
+        if (iov->data.length <= 0) break;
+        tmp_len = iov->data.length;
+
+        if (ENCRYPT_IOV(iov)) {
+            tmp_buf=(unsigned char *)iov->data.data;
+            ret = EVP_EncryptUpdate(&ciph_ctx, 
+                      tmp_buf, &tmp_len,
+                      (unsigned char *)iov->data.data, iov->data.length);
+            if (!ret) break;
+            iov->data.length = tmp_len;
+        }
+    }
+    if(ret)
+        ret = EVP_EncryptFinal_ex(&ciph_ctx, (unsigned char *)tmp_buf, &tmp_len);
+    if (ret) 
+        iov->data.length += tmp_len;
+    EVP_CIPHER_CTX_cleanup(&ciph_ctx);
+
+    if (!ret) 
+        return -1;
+    return 0;
+}
+
+
+static krb5_error_code
+k5_arcfour_make_key(const krb5_data *randombits, krb5_keyblock *key)
+{
+    if (key->length != RC4_KEY_SIZE)
+        return(KRB5_BAD_KEYSIZE);
+    if (randombits->length != RC4_KEY_SIZE)
+        return(KRB5_CRYPTO_INTERNAL);
+
+    key->magic = KV5M_KEYBLOCK;
+
+    memcpy(key->contents, randombits->data, randombits->length);
+
+    return(0);
+}
+
+static krb5_error_code
+k5_arcfour_free_state ( krb5_data *state)
+{
+   return 0; /* not implemented */
+}
+
+static krb5_error_code
+k5_arcfour_init_state (const krb5_keyblock *key,
+                       krb5_keyusage keyusage, krb5_data *new_state)
+{
+   return 0; /* not implemented */
+
+}
+
+/* Since the arcfour cipher is identical going forwards and backwards, 
+   we just call "docrypt" directly
+*/
+const struct krb5_enc_provider krb5int_enc_arcfour = {
+    /* This seems to work... although I am not sure what the
+       implications are in other places in the kerberos library */
+    RC4_BLOCK_SIZE,
+    /* Keysize is arbitrary in arcfour, but the constraints of the
+       system, and to attempt to work with the MSFT system forces us
+       to 16byte/128bit.  Since there is no parity in the key, the
+       byte and length are the same.  */
+    RC4_KEY_SIZE, RC4_KEY_SIZE, 
+    k5_arcfour_docrypt,
+    k5_arcfour_docrypt,
+    k5_arcfour_make_key,
+    k5_arcfour_init_state, /*xxx not implemented */
+    k5_arcfour_free_state, /*xxx not implemented */
+    k5_arcfour_docrypt_iov,
+    k5_arcfour_docrypt_iov
+};
+
diff --git a/src/lib/crypto/openssl/hmac.c b/src/lib/crypto/openssl/hmac.c
new file mode 100644 (file)
index 0000000..a5543c9
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ */
+
+#include "k5-int.h"
+#include "aead.h"
+#include <openssl/hmac.h>
+#include <openssl/evp.h>
+
+/*
+ * the HMAC transform looks like:
+ *
+ * H(K XOR opad, H(K XOR ipad, text))
+ *
+ * where H is a cryptographic hash
+ * K is an n byte key
+ * ipad is the byte 0x36 repeated blocksize times
+ * opad is the byte 0x5c repeated blocksize times
+ * and text is the data being protected
+ */
+
+static const EVP_MD *
+map_digest(const struct krb5_hash_provider *hash)
+{
+    if (!strncmp(hash->hash_name, "SHA1",4))
+        return EVP_sha1();
+    else if (!strncmp(hash->hash_name, "MD5", 3))
+        return EVP_md5();
+    else if (!strncmp(hash->hash_name, "MD4", 3))
+        return EVP_md4();
+    else
+        return NULL;
+}
+
+krb5_error_code
+krb5_hmac(const struct krb5_hash_provider *hash, const krb5_keyblock *key,
+          unsigned int icount, const krb5_data *input, krb5_data *output)
+{
+    unsigned int i = 0, md_len = 0; 
+    unsigned char md[EVP_MAX_MD_SIZE];
+    HMAC_CTX c;
+    size_t hashsize, blocksize;
+
+    hashsize = hash->hashsize;
+    blocksize = hash->blocksize;
+
+    if (key->length > blocksize)
+        return(KRB5_CRYPTO_INTERNAL);
+    if (output->length < hashsize)
+        return(KRB5_BAD_MSIZE);
+    /* if this isn't > 0, then there won't be enough space in this
+       array to compute the outer hash */
+    if (icount == 0)
+        return(KRB5_CRYPTO_INTERNAL);
+
+    if (!map_digest(hash))
+        return(KRB5_CRYPTO_INTERNAL); // unsupported alg
+
+    HMAC_CTX_init(&c);
+    HMAC_Init(&c, key->contents, key->length, map_digest(hash));
+    for ( i = 0; i < icount; i++ ) {
+        HMAC_Update(&c,(const unsigned char*)input[i].data, input[i].length);
+    }
+    HMAC_Final(&c,(unsigned char *)md, &md_len);
+    if ( md_len <= output->length) {
+        output->length = md_len;
+        memcpy(output->data, md, output->length);
+    }
+    HMAC_CTX_cleanup(&c);
+    return 0;
+
+
+}
+
+krb5_error_code
+krb5int_hmac_iov(const struct krb5_hash_provider *hash, const krb5_keyblock *key,
+                 const krb5_crypto_iov *data, size_t num_data, krb5_data *output)
+{
+    krb5_data *sign_data;
+    size_t num_sign_data;
+    krb5_error_code ret;
+    size_t i, j;
+
+    /* Create a checksum over all the data to be signed */
+    for (i = 0, num_sign_data = 0; i < num_data; i++) {
+        const krb5_crypto_iov *iov = &data[i];
+
+        if (SIGN_IOV(iov))
+            num_sign_data++;
+    }
+
+    /* XXX cleanup to avoid alloc */
+    sign_data = (krb5_data *)calloc(num_sign_data, sizeof(krb5_data));
+    if (sign_data == NULL)
+        return ENOMEM;
+
+    for (i = 0, j = 0; i < num_data; i++) {
+        const krb5_crypto_iov *iov = &data[i];
+
+        if (SIGN_IOV(iov))
+            sign_data[j++] = iov->data;
+    }
+
+    /* caller must store checksum in iov as it may be TYPE_TRAILER or TYPE_CHECKSUM */
+    ret = krb5_hmac(hash, key, num_sign_data, sign_data, output);
+
+    free(sign_data);
+
+    return ret;
+}
+
diff --git a/src/lib/crypto/openssl/md4/deps b/src/lib/crypto/openssl/md4/deps
new file mode 100644 (file)
index 0000000..1decaf9
--- /dev/null
@@ -0,0 +1,13 @@
+# 
+# Generated makefile dependencies follow.
+#
+md4.so md4.po $(OUTPRE)md4.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+  $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/autoconf.h \
+  $(SRCTOP)/include/k5-buf.h $(SRCTOP)/include/k5-err.h \
+  $(SRCTOP)/include/k5-gmt_mktime.h $(SRCTOP)/include/k5-int-pkinit.h \
+  $(SRCTOP)/include/k5-int.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-plugin.h $(SRCTOP)/include/k5-thread.h \
+  $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \
+  $(SRCTOP)/include/krb5/preauth_plugin.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h md4.c rsa-md4.h
diff --git a/src/lib/crypto/openssl/md4/md4.c b/src/lib/crypto/openssl/md4/md4.c
new file mode 100644 (file)
index 0000000..88d5191
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ *     lib/crypto/openssl/md4/md4.c
+ */
+
+#include "k5-int.h"
+#include "rsa-md4.h"
+#include <openssl/evp.h>
+#include <openssl/md4.h>
+
+void
+krb5_MD4Init (krb5_MD4_CTX *mdContext)
+{
+    EVP_MD_CTX_init(&mdContext->ossl_md4_ctx );
+    EVP_DigestInit_ex(&mdContext->ossl_md4_ctx, EVP_md4(), NULL);
+
+}
+void
+krb5_MD4Update (krb5_MD4_CTX *mdContext, const unsigned char *inBuf, unsigned int inLen)
+{
+    EVP_DigestUpdate(&mdContext->ossl_md4_ctx, inBuf, inLen);
+}
+
+void
+krb5_MD4Final (krb5_MD4_CTX *mdContext)
+{
+    EVP_DigestFinal_ex(&mdContext->ossl_md4_ctx, mdContext->digest , NULL);
+    EVP_MD_CTX_cleanup(&mdContext->ossl_md4_ctx );
+}
+
diff --git a/src/lib/crypto/openssl/md4/rsa-md4.h b/src/lib/crypto/openssl/md4/rsa-md4.h
new file mode 100644 (file)
index 0000000..4b02047
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * lib/crypto/md4/rsa-md4.h
+ *
+ * Copyright 1991 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.
+ * 
+ *
+ * RSA MD4 header file, with Kerberos/STDC additions.
+ */
+
+#ifndef __KRB5_RSA_MD4_H__
+#define __KRB5_RSA_MD4_H__
+
+#ifdef unicos61
+#include <sys/types.h>
+#endif /* unicos61 */
+
+#include <openssl/evp.h>
+#include <openssl/md5.h>
+
+/* 16 u_char's in the digest */
+#define RSA_MD4_CKSUM_LENGTH            16
+/* des blocksize is 8, so this works nicely... */
+#define OLD_RSA_MD4_DES_CKSUM_LENGTH    16
+#define NEW_RSA_MD4_DES_CKSUM_LENGTH    24
+#define RSA_MD4_DES_CONFOUND_LENGTH     8
+
+/*
+ **********************************************************************
+ ** md4.h -- Header file for implementation of MD4                   **
+ ** RSA Data Security, Inc. MD4 Message Digest Algorithm             **
+ ** Created: 2/17/90 RLR                                             **
+ ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version              **
+ **********************************************************************
+ */
+
+/*
+ **********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
+ **                                                                  **
+ ** License to copy and use this software is granted provided that   **
+ ** it is identified as the "RSA Data Security, Inc. MD4 Message     **
+ ** Digest Algorithm" in all material mentioning or referencing this **
+ ** software or this function.                                       **
+ **                                                                  **
+ ** License is also granted to make and use derivative works         **
+ ** provided that such works are identified as "derived from the RSA **
+ ** Data Security, Inc. MD4 Message Digest Algorithm" in all         **
+ ** material mentioning or referencing the derived work.             **
+ **                                                                  **
+ ** RSA Data Security, Inc. makes no representations concerning      **
+ ** either the merchantability of this software or the suitability   **
+ ** of this software for any particular purpose.  It is provided "as **
+ ** is" without express or implied warranty of any kind.             **
+ **                                                                  **
+ ** These notices must be retained in any copies of any part of this **
+ ** documentation and/or software.                                   **
+ **********************************************************************
+ */
+
+/* Data structure for MD4 (Message Digest) computation */
+typedef struct {
+    EVP_MD_CTX ossl_md4_ctx;
+    krb5_int32 * digest_len;
+    krb5_ui_4 i[2];              /* number of _bits_ handled mod 2^64 */
+    krb5_ui_4 buf[4];            /* scratch buffer */
+    unsigned char in[64];        /* input buffer */
+    unsigned char digest[16];    /* actual digest after MD4Final call */
+} krb5_MD4_CTX;
+
+extern void krb5_MD4Init(krb5_MD4_CTX *);
+extern void krb5_MD4Update(krb5_MD4_CTX *, const unsigned char *, unsigned int);
+extern void krb5_MD4Final(krb5_MD4_CTX *);
+
+/*
+ **********************************************************************
+ ** End of md4.h                                                     **
+ ******************************* (cut) ********************************
+ */
+#endif /* __KRB5_RSA_MD4_H__ */
diff --git a/src/lib/crypto/openssl/md5/deps b/src/lib/crypto/openssl/md5/deps
new file mode 100644 (file)
index 0000000..fc3378d
--- /dev/null
@@ -0,0 +1,13 @@
+# 
+# Generated makefile dependencies follow.
+#
+md5.so md5.po $(OUTPRE)md5.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+  $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/autoconf.h \
+  $(SRCTOP)/include/k5-buf.h $(SRCTOP)/include/k5-err.h \
+  $(SRCTOP)/include/k5-gmt_mktime.h $(SRCTOP)/include/k5-int-pkinit.h \
+  $(SRCTOP)/include/k5-int.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-plugin.h $(SRCTOP)/include/k5-thread.h \
+  $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \
+  $(SRCTOP)/include/krb5/preauth_plugin.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h md5.c rsa-md5.h
diff --git a/src/lib/crypto/openssl/md5/md5.c b/src/lib/crypto/openssl/md5/md5.c
new file mode 100644 (file)
index 0000000..8519dd5
--- /dev/null
@@ -0,0 +1,36 @@
+
+#include "k5-int.h"
+#include "rsa-md5.h"
+#include <openssl/evp.h>
+#include <openssl/md5.h>
+
+/* The routine krb5_MD5Init initializes the message-digest context
+   mdContext. All fields are set to zero.
+ */
+void 
+krb5_MD5Init (krb5_MD5_CTX *mdContext)
+{
+    EVP_MD_CTX_init(&mdContext->ossl_md5_ctx);
+    EVP_DigestInit_ex(&mdContext->ossl_md5_ctx, EVP_md5(), NULL);
+}
+
+/* The routine krb5_MD5Update updates the message-digest context to
+   account for the presence of each of the characters inBuf[0..inLen-1]
+   in the message whose digest is being computed.
+ */
+void
+krb5_MD5Update (krb5_MD5_CTX *mdContext, const unsigned char *inBuf, unsigned int inLen)
+{
+    EVP_DigestUpdate(&mdContext->ossl_md5_ctx, inBuf, inLen);
+}
+
+/* The routine krb5_MD5Final terminates the message-digest computation and
+   ends with the desired message digest in mdContext->digest[0...15].
+ */
+void
+krb5_MD5Final (krb5_MD5_CTX *mdContext)
+{
+    EVP_DigestFinal_ex(&mdContext->ossl_md5_ctx, mdContext->digest, NULL);
+    EVP_MD_CTX_cleanup(&mdContext->ossl_md5_ctx);
+}
+
diff --git a/src/lib/crypto/openssl/md5/rsa-md5.h b/src/lib/crypto/openssl/md5/rsa-md5.h
new file mode 100644 (file)
index 0000000..7240b20
--- /dev/null
@@ -0,0 +1,27 @@
+
+#ifndef    KRB5_RSA_MD5__
+#define    KRB5_RSA_MD5__
+
+#include <openssl/evp.h>
+#include <openssl/md5.h>
+
+/* Data structure for MD5 (Message-Digest) computation */
+typedef struct {
+    EVP_MD_CTX ossl_md5_ctx;
+    krb5_int32 * digest_len;
+    krb5_ui_4 i[2];              /* number of _bits_ handled mod 2^64 */
+    krb5_ui_4 buf[4];            /* scratch buffer */
+    unsigned char in[64];        /* input buffer */
+    unsigned char digest[16];    /* actual digest after MD5Final call */
+} krb5_MD5_CTX;
+
+extern void krb5_MD5Init(krb5_MD5_CTX *);
+extern void krb5_MD5Update(krb5_MD5_CTX *,const unsigned char *,unsigned int);
+extern void krb5_MD5Final(krb5_MD5_CTX *);
+
+#define    RSA_MD5_CKSUM_LENGTH            16
+#define    OLD_RSA_MD5_DES_CKSUM_LENGTH    16
+#define    NEW_RSA_MD5_DES_CKSUM_LENGTH    24
+#define    RSA_MD5_DES_CONFOUND_LENGTH     8
+
+#endif /* KRB5_RSA_MD5__ */
diff --git a/src/lib/crypto/openssl/pbkdf2.c b/src/lib/crypto/openssl/pbkdf2.c
new file mode 100644 (file)
index 0000000..bef8be2
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * lib/crypto/openssl/pbkdf2.c
+ *
+ * Copyright 2002, 2008 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.
+ * 
+ *
+ * Implementation of PBKDF2 from RFC 2898.
+ * Not currently used; likely to be used when we get around to AES support.
+ */
+
+#include <ctype.h>
+#include "k5-int.h"
+#include "hash_provider.h"
+
+#include <openssl/x509.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+
+
+krb5_error_code
+krb5int_pbkdf2_hmac_sha1 (const krb5_data *out, unsigned long count,
+                         const krb5_data *pass, const krb5_data *salt)
+{
+/*
+ * This is an implementation of PKCS#5 v2.0 
+ * Does not return an error
+ */
+   PKCS5_PBKDF2_HMAC_SHA1(pass->data, pass->length,
+                           (unsigned char *)salt->data, salt->length, count,
+                           out->length, (unsigned char *)out->data);
+    return 0; 
+}
+
diff --git a/src/lib/crypto/openssl/sha1/deps b/src/lib/crypto/openssl/sha1/deps
new file mode 100644 (file)
index 0000000..a8f51a8
--- /dev/null
@@ -0,0 +1,13 @@
+# 
+# Generated makefile dependencies follow.
+#
+shs.so shs.po $(OUTPRE)shs.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+  $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/autoconf.h \
+  $(SRCTOP)/include/k5-buf.h $(SRCTOP)/include/k5-err.h \
+  $(SRCTOP)/include/k5-gmt_mktime.h $(SRCTOP)/include/k5-int-pkinit.h \
+  $(SRCTOP)/include/k5-int.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-plugin.h $(SRCTOP)/include/k5-thread.h \
+  $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \
+  $(SRCTOP)/include/krb5/preauth_plugin.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h shs.c shs.h
diff --git a/src/lib/crypto/openssl/sha1/shs.c b/src/lib/crypto/openssl/sha1/shs.c
new file mode 100644 (file)
index 0000000..9fb60f8
--- /dev/null
@@ -0,0 +1,34 @@
+#include "shs.h"
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <string.h>
+
+/* Initialize the SHS values */
+void shsInit(SHS_INFO *shsInfo)
+{
+    EVP_MD_CTX_init(&shsInfo->ossl_sha1_ctx );
+    EVP_DigestInit_ex(&shsInfo->ossl_sha1_ctx , EVP_sha1(), NULL);
+}
+
+/* Update SHS for a block of data */
+
+void shsUpdate(SHS_INFO *shsInfo, const SHS_BYTE *buffer, unsigned int count)
+{
+    EVP_DigestUpdate(&shsInfo->ossl_sha1_ctx , buffer, count);
+}
+/* Final wrapup - pad to SHS_DATASIZE-byte boundary with the bit pattern
+   1 0* (64-bit count of bits processed, MSB-first) */
+
+void shsFinal(SHS_INFO *shsInfo)
+{
+    unsigned char *digest_buf = NULL;
+
+    digest_buf =  (unsigned char *)OPENSSL_malloc( sizeof(shsInfo->digest));
+
+    EVP_DigestFinal_ex(&shsInfo->ossl_sha1_ctx , digest_buf , &shsInfo->digest_len); 
+
+    memcpy(shsInfo->digest, digest_buf, shsInfo->digest_len);
+    OPENSSL_free(digest_buf);
+    EVP_MD_CTX_cleanup(&shsInfo->ossl_sha1_ctx );
+}
diff --git a/src/lib/crypto/openssl/sha1/shs.h b/src/lib/crypto/openssl/sha1/shs.h
new file mode 100644 (file)
index 0000000..66e91b6
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef _SHS_DEFINED
+
+#include "k5-int.h"
+#include <openssl/evp.h>
+#include <openssl/sha.h>
+
+#define _SHS_DEFINED
+
+/* Some useful types */
+
+typedef krb5_octet     SHS_BYTE;
+typedef krb5_ui_4      SHS_LONG;
+
+/* Define the following to use the updated SHS implementation */
+#define NEW_SHS         /**/
+
+/* The SHS block size and message digest sizes, in bytes */
+
+#define SHS_DATASIZE    64
+#define SHS_DIGESTSIZE  20
+
+/* The structure for storing SHS info */
+
+typedef struct {
+    EVP_MD_CTX ossl_sha1_ctx;
+    unsigned int   digest_len;
+    SHS_LONG digest[ 5 ];            /* Message digest */
+    SHS_LONG countLo, countHi;       /* 64-bit bit count */
+    SHS_LONG data[ 16 ];             /* SHS data buffer */
+} SHS_INFO;
+
+/* Message digest functions (shs.c) */
+void shsInit(SHS_INFO *shsInfo);
+void shsUpdate(SHS_INFO *shsInfo, const SHS_BYTE *buffer, unsigned int count);
+void shsFinal(SHS_INFO *shsInfo);
+
+
+/* Keyed Message digest functions (hmac_sha.c) */
+krb5_error_code hmac_sha(krb5_octet *text,
+                       int text_len,
+                       krb5_octet *key,
+                       int key_len,
+                       krb5_octet *digest);
+
+
+#define NIST_SHA_CKSUM_LENGTH          SHS_DIGESTSIZE
+#define HMAC_SHA_CKSUM_LENGTH          SHS_DIGESTSIZE
+
+#endif /* _SHS_DEFINED */
index f7c35acfd495c5c9081fc2a4bffb2501ed2e5217..4a8db057b61edb6535ddbf4574e749dda33016a6 100644 (file)
@@ -254,6 +254,36 @@ OM_uint32 KRB5_CALLCONV gss_release_iov_buffer
     gss_iov_buffer_desc *, /* iov */
     int);              /* iov_count */
 
+/*
+ * Protocol transition
+ */
+OM_uint32 KRB5_CALLCONV
+gss_acquire_cred_impersonate_name(
+    OM_uint32 *,           /* minor_status */
+    const gss_cred_id_t,    /* impersonator_cred_handle */
+    const gss_name_t,      /* desired_name */
+    OM_uint32,             /* time_req */
+    const gss_OID_set,     /* desired_mechs */
+    gss_cred_usage_t,      /* cred_usage */
+    gss_cred_id_t *,       /* output_cred_handle */
+    gss_OID_set *,         /* actual_mechs */
+    OM_uint32 *);          /* time_rec */
+
+OM_uint32 KRB5_CALLCONV
+gss_add_cred_impersonate_name(
+    OM_uint32 *,           /* minor_status */
+    gss_cred_id_t,         /* input_cred_handle */
+    const gss_cred_id_t,    /* impersonator_cred_handle */
+    const gss_name_t,      /* desired_name */
+    const gss_OID,         /* desired_mech */
+    gss_cred_usage_t,      /* cred_usage */
+    OM_uint32,             /* initiator_time_req */
+    OM_uint32,             /* acceptor_time_req */
+    gss_cred_id_t *,       /* output_cred_handle */
+    gss_OID_set *,         /* actual_mechs */
+    OM_uint32 *,           /* initiator_time_rec */
+    OM_uint32 *);          /* acceptor_time_rec */
+
 /*
  * Naming extensions
  */
index 804e7803d599fc8631e09df620543eba82f6051b..b84efa1769d981ee015143626c9ed20189666559 100644 (file)
@@ -74,6 +74,7 @@ SRCS = \
        $(srcdir)/rel_cred.c \
        $(srcdir)/rel_oid.c \
        $(srcdir)/rel_name.c \
+       $(srcdir)/s4u_gss_glue.c \
        $(srcdir)/seal.c \
        $(srcdir)/set_allowable_enctypes.c \
        $(srcdir)/ser_sctx.c \
@@ -125,6 +126,7 @@ OBJS = \
        $(OUTPRE)rel_cred.$(OBJEXT) \
        $(OUTPRE)rel_oid.$(OBJEXT) \
        $(OUTPRE)rel_name.$(OBJEXT) \
+       $(OUTPRE)s4u_gss_glue.$(OBJEXT) \
        $(OUTPRE)seal.$(OBJEXT) \
        $(OUTPRE)set_allowable_enctypes.$(OBJEXT) \
        $(OUTPRE)ser_sctx.$(OBJEXT) \
@@ -179,6 +181,7 @@ STLIBOBJS = \
        rel_cred.o \
        rel_oid.o \
        rel_name.o \
+       s4u_gss_glue.o \
        seal.o \
        set_allowable_enctypes.o \
        ser_sctx.o \
index f50da2ab785b9bed7446fe5972df020e1f496df9..934302cffddd176cd1cf1247520af996cc8f21a8 100644 (file)
 
 #ifndef LEAN_CLIENT
 
+static OM_uint32
+create_constrained_deleg_creds(OM_uint32 *minor_status,
+                               krb5_gss_cred_id_t verifier_cred_handle,
+                               krb5_ticket *ticket,
+                               krb5_gss_cred_id_t *out_cred,
+                               krb5_context context)
+{
+    OM_uint32 major_status;
+    krb5_creds krb_creds;
+    krb5_data *data;
+    krb5_error_code code;
+
+    assert(out_cred != NULL);
+    assert(verifier_cred_handle->usage == GSS_C_BOTH);
+
+    memset(&krb_creds, 0, sizeof(krb_creds));
+    krb_creds.client = ticket->enc_part2->client;
+    krb_creds.server = ticket->server;
+    krb_creds.keyblock = *(ticket->enc_part2->session);
+    krb_creds.ticket_flags = ticket->enc_part2->flags;
+    krb_creds.times = ticket->enc_part2->times;
+    krb_creds.magic = KV5M_CREDS;
+    krb_creds.authdata = NULL;
+
+    code = encode_krb5_ticket(ticket, &data);
+    if (code) {
+        *minor_status = code;
+        return GSS_S_FAILURE;
+    }
+
+    krb_creds.ticket = *data;
+
+    major_status = kg_compose_deleg_cred(minor_status,
+                                         verifier_cred_handle,
+                                         &krb_creds,
+                                         GSS_C_INDEFINITE,
+                                         GSS_C_NO_OID_SET,
+                                         out_cred,
+                                         NULL,
+                                         NULL,
+                                         context);
+
+    krb5_free_data(context, data);
+
+    return major_status;
+}
+
 /* Decode, decrypt and store the forwarded creds in the local ccache. */
 static krb5_error_code
 rd_and_store_for_creds(context, auth_context, inbuf, out_cred)
@@ -873,6 +920,23 @@ kg_accept_krb5(minor_status, context_handle,
     ctx->krb_times = ticket->enc_part2->times; /* struct copy */
     ctx->krb_flags = ticket->enc_part2->flags;
 
+    if (delegated_cred_handle != NULL &&
+        deleg_cred == NULL && /* no unconstrained delegation */
+        cred->usage == GSS_C_BOTH &&
+        (ticket->enc_part2->flags & TKT_FLG_FORWARDABLE)) {
+        /*
+         * Now, we always fabricate a delegated credentials handle
+         * containing the service ticket to ourselves, which can be
+         * used for S4U2Proxy.
+         */
+        major_status = create_constrained_deleg_creds(minor_status, cred,
+                                                      ticket, &deleg_cred,
+                                                      context);
+        if (GSS_ERROR(major_status))
+            goto fail;
+        ctx->gss_flags |= GSS_C_DELEG_FLAG;
+    }
+
     krb5_free_ticket(context, ticket); /* Done with ticket */
 
     {
@@ -1057,8 +1121,8 @@ kg_accept_krb5(minor_status, context_handle,
     if (src_name)
         *src_name = (gss_name_t) name;
 
-    if (delegated_cred_handle && deleg_cred) {
-        if (!kg_save_cred_id((gss_cred_id_t) deleg_cred)) {
+    if (delegated_cred_handle) {
+       if (!kg_save_cred_id((gss_cred_id_t) deleg_cred)) {
             major_status = GSS_S_FAILURE;
             code = G_VALIDATE_FAILED;
             goto fail;
index 681f18a67d6c4076cc62d840baecddde1c63c417..8f8cf1e2ce776ff95eb32ec4ef3e9af9f72048ca 100644 (file)
@@ -538,8 +538,8 @@ krb5_gss_acquire_cred(minor_status, desired_name, time_req,
 
     cred->usage = cred_usage;
     cred->name = NULL;
-    cred->prerfc_mech = req_old;
-    cred->rfc_mech = req_new;
+    cred->prerfc_mech = (req_old != 0);
+    cred->rfc_mech = (req_new != 0);
 
 #ifndef LEAN_CLIENT
     cred->keytab = NULL;
@@ -766,3 +766,4 @@ gss_krb5int_set_cred_rcache(OM_uint32 *minor_status,
    *minor_status = 0;
    return GSS_S_COMPLETE;
 }
+
index e7b48e04f11a5e86fbccc3957ce25edfca554f69..19fe1d788a3b0819b58c9eff6604161d55fc8b5f 100644 (file)
@@ -50,8 +50,11 @@ gss_krb5int_copy_ccache(OM_uint32 *minor_status,
         krb5_free_context(context);
         return(GSS_S_FAILURE);
     }
-    while (!code && !krb5_cc_next_cred(context, k5creds->ccache, &cursor, &creds))
+    while (!code && !krb5_cc_next_cred(context, k5creds->ccache, &cursor,
+                                       &creds)) {
         code = krb5_cc_store_cred(context, out_ccache, &creds);
+        krb5_free_cred_contents(context, &creds);
+    }
     krb5_cc_end_seq_get(context, k5creds->ccache, &cursor);
     k5_mutex_unlock(&k5creds->lock);
     *minor_status = code;
index 2591b2a1c891e48e0aa8336373ae44cce135240f..f85e03835dc5c10031e7deacd66a1e661585139b 100644 (file)
@@ -166,8 +166,9 @@ typedef struct _krb5_gss_cred_id_rec {
     /* name/type of credential */
     gss_cred_usage_t usage;
     krb5_gss_name_t name;
-    int prerfc_mech;
-    int rfc_mech;
+    unsigned int prerfc_mech : 1;
+    unsigned int rfc_mech : 1;
+    unsigned int proxy_cred : 1;
 
     /* keytab (accept) data */
     krb5_keytab keytab;
@@ -470,6 +471,29 @@ krb5_boolean kg_integ_only_iov(gss_iov_buffer_desc *iov, int iov_count);
 
 krb5_error_code kg_allocate_iov(gss_iov_buffer_t iov, size_t size);
 
+krb5_error_code
+krb5_to_gss_cred(krb5_context context,
+                 krb5_creds *creds,
+                 krb5_gss_cred_id_t *out_cred);
+
+OM_uint32
+kg_new_connection(
+    OM_uint32 *minor_status,
+    krb5_gss_cred_id_t cred,
+    gss_ctx_id_t *context_handle,
+    gss_name_t target_name,
+    gss_OID mech_type,
+    OM_uint32 req_flags,
+    OM_uint32 time_req,
+    gss_channel_bindings_t input_chan_bindings,
+    gss_buffer_t input_token,
+    gss_OID *actual_mech_type,
+    gss_buffer_t output_token,
+    OM_uint32 *ret_flags,
+    OM_uint32 *time_rec,
+    krb5_context context,
+    int default_mech);
+
 /** declarations of internal name mechanism functions **/
 
 OM_uint32 krb5_gss_acquire_cred
@@ -770,6 +794,17 @@ OM_uint32 krb5_gss_validate_cred
  gss_cred_id_t               /* cred */
 );
 
+OM_uint32 krb5_gss_acquire_cred_impersonate_name(
+    OM_uint32 *,            /* minor_status */
+    const gss_cred_id_t,    /* impersonator_cred_handle */
+    const gss_name_t,       /* desired_name */
+    OM_uint32,              /* time_req */
+    const gss_OID_set,      /* desired_mechs */
+    gss_cred_usage_t,       /* cred_usage */
+    gss_cred_id_t *,        /* output_cred_handle */
+    gss_OID_set *,          /* actual_mechs */
+    OM_uint32 *);           /* time_rec */
+
 OM_uint32
 krb5_gss_validate_cred_1(OM_uint32 * /* minor_status */,
                          gss_cred_id_t /* cred_handle */,
@@ -876,6 +911,18 @@ krb5_gss_release_any_name_mapping(OM_uint32 *minor_status,
                                   gss_buffer_t type_id,
                                   gss_any_t *input);
 
+/* s4u_gss_glue.c */
+OM_uint32
+kg_compose_deleg_cred(OM_uint32 *minor_status,
+                      krb5_gss_cred_id_t impersonator_cred,
+                      krb5_creds *subject_creds,
+                      OM_uint32 time_req,
+                      const gss_OID_set desired_mechs,
+                      krb5_gss_cred_id_t *output_cred,
+                      gss_OID_set *actual_mechs,
+                      OM_uint32 *time_rec,
+                      krb5_context context);
+
 /*
  * These take unglued krb5-mech-specific contexts.
  */
index 445647e38dafb56a8d14fc3a5a8cc85b76f25012..d7acd52b78e0fd4d75cab401f04c424b6e121823 100644 (file)
@@ -140,6 +140,7 @@ const gss_OID_desc krb5_gss_oid_array[] = {
 
     /* gss_nt_krb5_principal.  Object identifier for a krb5_principal. Do not use. */
     {10, "\052\206\110\206\367\022\001\002\002\002"},
+
     { 0, 0 }
 };
 
@@ -447,13 +448,11 @@ krb5_gss_inquire_cred_by_oid(OM_uint32 *minor_status,
 /*
  * gss_set_sec_context_option() methods
  */
-#if 0
 static struct {
     gss_OID_desc oid;
     OM_uint32 (*func)(OM_uint32 *, gss_ctx_id_t *, const gss_OID, const gss_buffer_t);
 } krb5_gss_set_sec_context_option_ops[] = {
 };
-#endif
 
 static OM_uint32
 krb5_gss_set_sec_context_option (OM_uint32 *minor_status,
@@ -481,12 +480,8 @@ krb5_gss_set_sec_context_option (OM_uint32 *minor_status,
             return GSS_S_NO_CONTEXT;
 
         ctx = (krb5_gss_ctx_id_rec *) context_handle;
-
-        if (!ctx->established)
-            return GSS_S_NO_CONTEXT;
     }
 
-#if 0
     for (i = 0; i < sizeof(krb5_gss_set_sec_context_option_ops)/
                     sizeof(krb5_gss_set_sec_context_option_ops[0]); i++) {
         if (g_OID_prefix_equal(desired_object, &krb5_gss_set_sec_context_option_ops[i].oid)) {
@@ -496,7 +491,6 @@ krb5_gss_set_sec_context_option (OM_uint32 *minor_status,
                                                                   value);
         }
     }
-#endif
 
     *minor_status = EINVAL;
 
@@ -521,7 +515,7 @@ static struct {
     {
         {GSS_KRB5_SET_CRED_RCACHE_OID_LENGTH, GSS_KRB5_SET_CRED_RCACHE_OID},
         gss_krb5int_set_cred_rcache
-    }
+    },
 };
 
 static OM_uint32
@@ -587,7 +581,7 @@ static struct {
     {
         {GSS_KRB5_USE_KDC_CONTEXT_OID_LENGTH, GSS_KRB5_USE_KDC_CONTEXT_OID},
         krb5int_gss_use_kdc_context
-    }
+    },
 };
 
 static OM_uint32
@@ -683,6 +677,8 @@ static struct gss_config krb5_mechanism = {
     krb5_gss_unwrap_iov,
     krb5_gss_wrap_iov_length,
     NULL,               /* complete_auth_token */
+    krb5_gss_acquire_cred_impersonate_name,
+    NULL,               /* krb5_gss_add_cred_impersonate_name */
     NULL,               /* display_name_ext */
     krb5_gss_inquire_name,
     krb5_gss_get_name_attribute,
index 0fb412730cce46e16a62e988be59b4146348b4b6..eace54f3444920180dd14dad6a6afc7e2d0dc983 100644 (file)
@@ -128,15 +128,54 @@ static krb5_error_code get_credentials(context, cred, server, now,
     krb5_creds **out_creds;
 {
     krb5_error_code     code;
-    krb5_creds          in_creds;
+    krb5_creds          in_creds, evidence_creds;
+    krb5_flags          flags = 0;
+    krb5_principal      cc_princ = NULL;
 
     k5_mutex_assert_locked(&cred->lock);
     memset(&in_creds, 0, sizeof(krb5_creds));
+    memset(&evidence_creds, 0, sizeof(krb5_creds));
     in_creds.client = in_creds.server = NULL;
 
     assert(cred->name != NULL);
 
-    in_creds.client = cred->name->princ;
+    if ((code = krb5_cc_get_principal(context, cred->ccache, &cc_princ)))
+        goto cleanup;
+
+    /*
+     * Do constrained delegation if we have proxy credentials and
+     * we're not trying to get a ticket to ourselves (in which case
+     * we can just use the S4U2Self or evidence ticket directly).
+     */
+    if (cred->proxy_cred &&
+        !krb5_principal_compare(context, cc_princ, server->princ)) {
+        krb5_creds mcreds;
+
+        flags |= KRB5_GC_CANONICALIZE |
+                 KRB5_GC_NO_STORE |
+                 KRB5_GC_CONSTRAINED_DELEGATION;
+
+        memset(&mcreds, 0, sizeof(mcreds));
+
+        mcreds.magic = KV5M_CREDS;
+        mcreds.times.endtime = cred->tgt_expire;
+        mcreds.server = cc_princ;
+        mcreds.client = cred->name->princ;
+
+        code = krb5_cc_retrieve_cred(context, cred->ccache,
+                                     KRB5_TC_MATCH_TIMES, &mcreds,
+                                     &evidence_creds);
+        if (code)
+            goto cleanup;
+
+        assert(evidence_creds.ticket_flags & TKT_FLG_FORWARDABLE);
+
+        in_creds.client = cc_princ;
+        in_creds.second_ticket = evidence_creds.ticket;
+    } else {
+        in_creds.client = cred->name->princ;
+    }
+
     in_creds.server = server->princ;
     in_creds.times.endtime = endtime;
     in_creds.authdata = NULL;
@@ -155,11 +194,20 @@ static krb5_error_code get_credentials(context, cred, server, now,
             goto cleanup;
     }
 
-    code = krb5_get_credentials(context, 0, cred->ccache,
+    code = krb5_get_credentials(context, flags, cred->ccache,
                                 &in_creds, out_creds);
     if (code)
         goto cleanup;
 
+    if (flags & KRB5_GC_CONSTRAINED_DELEGATION) {
+        if (!krb5_principal_compare(context, cred->name->princ,
+                                    (*out_creds)->client)) {
+            /* server did not support constrained delegation */
+            code = KRB5_KDCREP_MODIFIED;
+            goto cleanup;
+        }
+    }
+
     /*
      * Enforce a stricter limit (without timeskew forgiveness at the
      * boundaries) because accept_sec_context code is also similarly
@@ -173,6 +221,8 @@ static krb5_error_code get_credentials(context, cred, server, now,
 
 cleanup:
     krb5_free_authdata(context, in_creds.authdata);
+    krb5_free_principal(context, cc_princ);
+    krb5_free_cred_contents(context, &evidence_creds);
 
     return code;
 }
@@ -407,8 +457,8 @@ cleanup:
  *
  * Do the grunt work of setting up a new context.
  */
-static OM_uint32
-new_connection(
+OM_uint32
+kg_new_connection(
     OM_uint32 *minor_status,
     krb5_gss_cred_id_t cred,
     gss_ctx_id_t *context_handle,
@@ -947,12 +997,12 @@ krb5_gss_init_sec_context(minor_status, claimant_cred_handle,
 
     /*SUPPRESS 29*/
     if (*context_handle == GSS_C_NO_CONTEXT) {
-        major_status = new_connection(minor_status, cred, context_handle,
-                                      target_name, mech_type, req_flags,
-                                      time_req, input_chan_bindings,
-                                      input_token, actual_mech_type,
-                                      output_token, ret_flags, time_rec,
-                                      context, default_mech);
+        major_status = kg_new_connection(minor_status, cred, context_handle,
+                                        target_name, mech_type, req_flags,
+                                        time_req, input_chan_bindings,
+                                        input_token, actual_mech_type,
+                                        output_token, ret_flags, time_rec,
+                                        context, default_mech);
         k5_mutex_unlock(&cred->lock);
         if (*context_handle == GSS_C_NO_CONTEXT) {
             save_error_info (*minor_status, context);
index f9bf03016f5d4643652e586ac8de55a6f6b1d46b..0345501221fe6aa18cc13cc6f3f836beccd15649 100644 (file)
@@ -416,3 +416,4 @@ gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status,
 
     return GSS_S_COMPLETE;
 }
+
diff --git a/src/lib/gssapi/krb5/s4u_gss_glue.c b/src/lib/gssapi/krb5/s4u_gss_glue.c
new file mode 100644 (file)
index 0000000..f91d4fb
--- /dev/null
@@ -0,0 +1,359 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2009  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"
+#include "gssapiP_krb5.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <assert.h>
+
+static OM_uint32
+kg_set_desired_mechs(OM_uint32 *minor_status,
+                     const gss_OID_set desired_mechs,
+                     krb5_gss_cred_id_t cred)
+{
+    unsigned int i;
+
+    if (desired_mechs == GSS_C_NULL_OID_SET) {
+        cred->prerfc_mech = 1;
+        cred->rfc_mech = 1;
+    } else {
+        cred->prerfc_mech = 0;
+        cred->rfc_mech = 0;
+
+        for (i = 0; i < desired_mechs->count; i++) {
+            if (g_OID_equal(gss_mech_krb5_old, &desired_mechs->elements[i]))
+                cred->prerfc_mech = 1;
+            else if (g_OID_equal(gss_mech_krb5, &desired_mechs->elements[i]))
+                cred->rfc_mech = 1;
+        }
+
+        if (!cred->prerfc_mech && !cred->rfc_mech) {
+            *minor_status = 0;
+            return GSS_S_BAD_MECH;
+        }
+    }
+
+    return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+kg_return_mechs(OM_uint32 *minor_status,
+                krb5_gss_cred_id_t cred,
+                gss_OID_set *actual_mechs)
+{
+    OM_uint32 major_status, minor;
+    gss_OID_set mechs;
+
+    if (actual_mechs == NULL)
+        return GSS_S_COMPLETE;
+
+    major_status = generic_gss_create_empty_oid_set(minor_status, &mechs);
+    if (GSS_ERROR(major_status))
+        return major_status;
+
+    if (cred->prerfc_mech) {
+        major_status = generic_gss_add_oid_set_member(minor_status,
+                                                      gss_mech_krb5_old,
+                                                      &mechs);
+        if (GSS_ERROR(major_status)) {
+            generic_gss_release_oid_set(&minor, &mechs);
+            return major_status;
+        }
+    }
+    if (cred->rfc_mech) {
+        major_status = generic_gss_add_oid_set_member(minor_status,
+                                                      gss_mech_krb5,
+                                                      &mechs);
+        if (GSS_ERROR(major_status)) {
+            generic_gss_release_oid_set(&minor, &mechs);
+            return major_status;
+        }
+    }
+
+    *actual_mechs = mechs;
+
+    return GSS_S_COMPLETE;
+}
+
+static int
+kg_is_initiator_cred(krb5_gss_cred_id_t cred)
+{
+    return (cred->usage == GSS_C_INITIATE || cred->usage == GSS_C_BOTH) &&
+           (cred->ccache != NULL);
+}
+
+static OM_uint32
+kg_impersonate_name(OM_uint32 *minor_status,
+                    const krb5_gss_cred_id_t impersonator_cred,
+                    const krb5_gss_name_t user,
+                    OM_uint32 time_req,
+                    const gss_OID_set desired_mechs,
+                    krb5_gss_cred_id_t *output_cred,
+                    gss_OID_set *actual_mechs,
+                    OM_uint32 *time_rec,
+                    krb5_context context)
+{
+    OM_uint32 major_status;
+    krb5_error_code code;
+    krb5_creds in_creds, *out_creds = NULL;
+
+    memset(&in_creds, 0, sizeof(in_creds));
+    memset(&out_creds, 0, sizeof(out_creds));
+
+    in_creds.client = user->princ;
+    in_creds.server = impersonator_cred->name->princ;
+
+    if (impersonator_cred->req_enctypes != NULL)
+        in_creds.keyblock.enctype = impersonator_cred->req_enctypes[0];
+
+    if (user->ad_context != NULL) {
+        code = krb5_authdata_export_attributes(context,
+                                               user->ad_context,
+                                               AD_USAGE_TGS_REQ,
+                                               &in_creds.authdata);
+        if (code != 0) {
+            *minor_status = code;
+            return GSS_S_FAILURE;
+        }
+    }
+
+    code = krb5_get_credentials_for_user(context,
+                                         KRB5_GC_CANONICALIZE | KRB5_GC_NO_STORE,
+                                         impersonator_cred->ccache,
+                                         &in_creds,
+                                         NULL, &out_creds);
+    if (code != 0) {
+        krb5_free_authdata(context, in_creds.authdata);
+        *minor_status = code;
+        return GSS_S_FAILURE;
+    }
+
+    major_status = kg_compose_deleg_cred(minor_status,
+                                         impersonator_cred,
+                                         out_creds,
+                                         time_req,
+                                         desired_mechs,
+                                         output_cred,
+                                         actual_mechs,
+                                         time_rec,
+                                         context);
+
+    krb5_free_authdata(context, in_creds.authdata);
+    krb5_free_creds(context, out_creds);
+
+    return major_status;
+}
+
+OM_uint32
+krb5_gss_acquire_cred_impersonate_name(OM_uint32 *minor_status,
+                                       const gss_cred_id_t impersonator_cred_handle,
+                                       const gss_name_t desired_name,
+                                       OM_uint32 time_req,
+                                       const gss_OID_set desired_mechs,
+                                       gss_cred_usage_t cred_usage,
+                                       gss_cred_id_t *output_cred_handle,
+                                       gss_OID_set *actual_mechs,
+                                       OM_uint32 *time_rec)
+{
+    OM_uint32 major_status;
+    krb5_error_code code;
+    krb5_gss_cred_id_t cred;
+    krb5_context context;
+
+    if (impersonator_cred_handle == GSS_C_NO_CREDENTIAL)
+        return GSS_S_CALL_INACCESSIBLE_READ;
+
+    if (desired_name == GSS_C_NO_NAME)
+        return GSS_S_CALL_INACCESSIBLE_READ;
+
+    if (output_cred_handle == NULL)
+        return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+    if (cred_usage != GSS_C_INITIATE) {
+        *minor_status = (OM_uint32)G_BAD_USAGE;
+        return GSS_S_FAILURE;
+    }
+
+    *output_cred_handle = GSS_C_NO_CREDENTIAL;
+    if (actual_mechs != NULL)
+        *actual_mechs = GSS_C_NO_OID_SET;
+    if (time_rec != NULL)
+        *time_rec = 0;
+
+    code = krb5_gss_init_context(&context);
+    if (code != 0) {
+        *minor_status = code;
+        return GSS_S_FAILURE;
+    }
+
+    major_status = krb5_gss_validate_cred_1(minor_status,
+                                            impersonator_cred_handle,
+                                            context);
+    if (GSS_ERROR(major_status)) {
+        krb5_free_context(context);
+        return major_status;
+    }
+
+    major_status = kg_impersonate_name(minor_status,
+                                       (krb5_gss_cred_id_t)impersonator_cred_handle,
+                                       (krb5_gss_name_t)desired_name,
+                                       time_req,
+                                       desired_mechs,
+                                       &cred,
+                                       actual_mechs,
+                                       time_rec,
+                                       context);
+
+    *output_cred_handle = (gss_cred_id_t)cred;
+
+    k5_mutex_unlock(&((krb5_gss_cred_id_t)impersonator_cred_handle)->lock);
+    krb5_free_context(context);
+
+    return major_status;
+
+}
+
+OM_uint32
+kg_compose_deleg_cred(OM_uint32 *minor_status,
+                      krb5_gss_cred_id_t impersonator_cred,
+                      krb5_creds *subject_creds,
+                      OM_uint32 time_req,
+                      const gss_OID_set desired_mechs,
+                      krb5_gss_cred_id_t *output_cred,
+                      gss_OID_set *actual_mechs,
+                      OM_uint32 *time_rec,
+                      krb5_context context)
+{
+    OM_uint32 major_status;
+    krb5_error_code code;
+    krb5_gss_cred_id_t cred = NULL;
+
+    k5_mutex_assert_locked(&impersonator_cred->lock);
+
+    if (!kg_is_initiator_cred(impersonator_cred) ||
+        impersonator_cred->name == NULL ||
+        impersonator_cred->proxy_cred) {
+        code = G_BAD_USAGE;
+        goto cleanup;
+    }
+
+    assert(impersonator_cred->name->princ != NULL);
+
+    assert(subject_creds != NULL);
+    assert(subject_creds->client != NULL);
+
+    cred = xmalloc(sizeof(*cred));
+    if (cred == NULL) {
+        code = ENOMEM;
+        goto cleanup;
+    }
+    memset(cred, 0, sizeof(*cred));
+
+    code = k5_mutex_init(&cred->lock);
+    if (code != 0)
+        goto cleanup;
+
+    /*
+     * Only return a "proxy" credential for use with constrained
+     * delegation if the subject credentials are forwardable.
+     * Submitting non-forwardable credentials to the KDC for use
+     * with constrained delegation will only return an error.
+     */
+    cred->usage = GSS_C_INITIATE;
+    cred->proxy_cred = !!(subject_creds->ticket_flags & TKT_FLG_FORWARDABLE);
+
+    major_status = kg_set_desired_mechs(minor_status, desired_mechs, cred);
+    if (GSS_ERROR(major_status))
+        goto cleanup;
+
+    cred->tgt_expire = impersonator_cred->tgt_expire;
+
+    code = kg_init_name(context, subject_creds->client, NULL, 0, &cred->name);
+    if (code != 0)
+        goto cleanup;
+
+    code = krb5_cc_new_unique(context, "MEMORY", NULL, &cred->ccache);
+    if (code != 0)
+        goto cleanup;
+
+    code = krb5_cc_initialize(context, cred->ccache,
+                              cred->proxy_cred ? impersonator_cred->name->princ :
+                                    subject_creds->client);
+    if (code != 0)
+        goto cleanup;
+
+    if (cred->proxy_cred) {
+        /* Impersonator's TGT will be necessary for S4U2Proxy */
+        code = krb5_cc_copy_creds(context, impersonator_cred->ccache,
+                                  cred->ccache);
+        if (code != 0)
+            goto cleanup;
+    }
+
+    code = krb5_cc_store_cred(context, cred->ccache, subject_creds);
+    if (code != 0)
+        goto cleanup;
+
+    if (time_rec != NULL) {
+        krb5_timestamp now;
+
+        code = krb5_timeofday(context, &now);
+        if (code != 0)
+            goto cleanup;
+
+        *time_rec = cred->tgt_expire - now;
+    }
+
+    major_status = kg_return_mechs(minor_status, cred, actual_mechs);
+    if (GSS_ERROR(major_status))
+        goto cleanup;
+
+    if (!kg_save_cred_id((gss_cred_id_t)cred)) {
+        code = G_VALIDATE_FAILED;
+        goto cleanup;
+    }
+
+    major_status = GSS_S_COMPLETE;
+    *minor_status = 0;
+    *output_cred = cred;
+
+cleanup:
+    if (code != 0) {
+        *minor_status = code;
+        major_status = GSS_S_FAILURE;
+    }
+
+    if (GSS_ERROR(major_status) && cred != NULL) {
+        k5_mutex_destroy(&cred->lock);
+        krb5_cc_destroy(context, cred->ccache);
+        kg_release_name(context, 0, &cred->name);
+        xfree(cred);
+    }
+
+    return major_status;
+}
+
index 4bd1f33793fbb59552e22ded576f1a6d69080a33..747d8222e6372ea21a80adb580a23404425bdf76 100644 (file)
@@ -58,7 +58,8 @@ krb5_gss_validate_cred_1(OM_uint32 *minor_status, gss_cred_id_t cred_handle,
             *minor_status = code;
             return(GSS_S_DEFECTIVE_CREDENTIAL);
         }
-        if (!krb5_principal_compare(context, princ, cred->name->princ)) {
+        if (!cred->proxy_cred &&
+            !krb5_principal_compare(context, princ, cred->name->princ)) {
             k5_mutex_unlock(&cred->lock);
             *minor_status = KG_CCACHE_NOMATCH;
             return(GSS_S_DEFECTIVE_CREDENTIAL);
index 8d560cecf43022d6efe6485d000d53de62944d3f..60754df7a768d2414cda145efc154b9d3e9e3b1b 100644 (file)
@@ -9,8 +9,10 @@ GSS_C_NT_USER_NAME
 GSS_KRB5_NT_PRINCIPAL_NAME
 gss_accept_sec_context
 gss_acquire_cred
+gss_acquire_cred_impersonate_name
 gss_add_buffer_set_member
 gss_add_cred
+gss_add_cred_impersonate_name
 gss_add_oid_set_member
 gss_canonicalize_name
 gss_compare_name
index c645357bbb9acd1e5c566cc9d1187e12a1ea74d3..61972ab759028ceddc2f6ceb19c934f6533dc426 100644 (file)
@@ -14,6 +14,7 @@ DEFS=-D_GSS_STATIC_LINK=1
 SRCS = \
        $(srcdir)/g_accept_sec_context.c \
        $(srcdir)/g_acquire_cred.c \
+       $(srcdir)/g_acquire_cred_imp_name.c \
        $(srcdir)/g_buffer_set.c \
        $(srcdir)/g_canon_name.c \
        $(srcdir)/g_compare_name.c \
@@ -66,6 +67,7 @@ SRCS = \
 OBJS = \
        $(OUTPRE)g_accept_sec_context.$(OBJEXT) \
        $(OUTPRE)g_acquire_cred.$(OBJEXT) \
+       $(OUTPRE)g_acquire_cred_imp_name.$(OBJEXT) \
        $(OUTPRE)g_buffer_set.$(OBJEXT) \
        $(OUTPRE)g_canon_name.$(OBJEXT) \
        $(OUTPRE)g_compare_name.$(OBJEXT) \
@@ -118,6 +120,7 @@ OBJS = \
 STLIBOBJS = \
        g_accept_sec_context.o \
        g_acquire_cred.o \
+       g_acquire_cred_imp_name.o \
        g_buffer_set.o \
        g_canon_name.o \
        g_compare_name.o \
index fa703d34d2b2d200327e2ccb41895ffcb9618361..dc439159351ae9532b8716cec5950303be09f9a0 100644 (file)
@@ -121,6 +121,7 @@ gss_cred_id_t *             d_cred;
     gss_name_t         tmp_src_name = GSS_C_NO_NAME;
     gss_OID_desc       token_mech_type_desc;
     gss_OID            token_mech_type = &token_mech_type_desc;
+    gss_OID            actual_mech = GSS_C_NO_OID;
     gss_mechanism      mech;
 
     status = val_acc_sec_ctx_args(minor_status,
@@ -198,8 +199,8 @@ gss_cred_id_t *             d_cred;
                                                  input_cred_handle,
                                                  input_token_buffer,
                                                  input_chan_bindings,
-                                                 &internal_name,
-                                                 mech_type,
+                                                 src_name ? &internal_name : NULL,
+                                                 &actual_mech,
                                                  output_token,
                                                  &temp_ret_flags,
                                                  time_rec,
@@ -222,110 +223,120 @@ gss_cred_id_t *         d_cred;
             * then call gss_import_name() to create
             * the union name struct cast to src_name
             */
-           if (internal_name != NULL) {
-               temp_status = gssint_convert_name_to_union_name(
-                      &temp_minor_status, mech,
-                      internal_name, &tmp_src_name);
-               if (temp_status != GSS_S_COMPLETE) {
-                   *minor_status = temp_minor_status;
-                   map_error(minor_status, mech);
-                   if (output_token->length)
-                       (void) gss_release_buffer(&temp_minor_status,
-                                                 output_token);
-                   if (internal_name != GSS_C_NO_NAME)
-                       mech->gss_release_name(
-                           &temp_minor_status,
-                           &internal_name);
-                   return (temp_status);
-               }
-               if (src_name != NULL) {
+           if (src_name != NULL) {
+               if (internal_name != GSS_C_NO_NAME) {
+                   /* consumes internal_name regardless of success */
+                   temp_status = gssint_convert_name_to_union_name(
+                           &temp_minor_status, mech,
+                           internal_name, &tmp_src_name);
+                   if (temp_status != GSS_S_COMPLETE) {
+                       *minor_status = temp_minor_status;
+                       map_error(minor_status, mech);
+                       if (output_token->length)
+                           (void) gss_release_buffer(&temp_minor_status,
+                                                     output_token);
+                       return (temp_status);
+                   }
                    *src_name = tmp_src_name;
-               }
-           } else if (src_name != NULL) {
-               *src_name = GSS_C_NO_NAME;
+               } else
+                   *src_name = GSS_C_NO_NAME;
            }
 
+#define g_OID_prefix_equal(o1, o2) \
+        (((o1)->length >= (o2)->length) && \
+        (memcmp((o1)->elements, (o2)->elements, (o2)->length) == 0))
+
            /* Ensure we're returning correct creds format */
            if ((temp_ret_flags & GSS_C_DELEG_FLAG) &&
                tmp_d_cred != GSS_C_NO_CREDENTIAL) {
-               gss_union_cred_t d_u_cred = NULL;
-
-               d_u_cred = malloc(sizeof (gss_union_cred_desc));
-               if (d_u_cred == NULL) {
-                   status = GSS_S_FAILURE;
-                   goto error_out;
-               }
-               (void) memset(d_u_cred, 0,
-                             sizeof (gss_union_cred_desc));
-
-               d_u_cred->count = 1;
+               if (actual_mech != GSS_C_NO_OID &&
+                   !g_OID_prefix_equal(actual_mech, token_mech_type)) {
+                   *d_cred = tmp_d_cred; /* unwrapped pseudo-mech */
+               } else {
+                   gss_union_cred_t d_u_cred = NULL;
 
-               status = generic_gss_copy_oid(&temp_minor_status,
-                                             token_mech_type,
-                                             &d_u_cred->mechs_array);
+                   d_u_cred = malloc(sizeof (gss_union_cred_desc));
+                   if (d_u_cred == NULL) {
+                       status = GSS_S_FAILURE;
+                       goto error_out;
+                   }
+                   (void) memset(d_u_cred, 0, sizeof (gss_union_cred_desc));
 
-               if (status != GSS_S_COMPLETE) {
-                   free(d_u_cred);
-                   goto error_out;
-               }
+                   d_u_cred->count = 1;
 
-               d_u_cred->cred_array = malloc(sizeof (gss_cred_id_t));
-               if (d_u_cred->cred_array != NULL) {
-                   d_u_cred->cred_array[0] = tmp_d_cred;
-               } else {
-                   free(d_u_cred);
-                   status = GSS_S_FAILURE;
-                   goto error_out;
-               }
+                   status = generic_gss_copy_oid(&temp_minor_status,
+                                                 token_mech_type,
+                                                 &d_u_cred->mechs_array);
 
-               internal_name = GSS_C_NO_NAME;
+                   if (status != GSS_S_COMPLETE) {
+                       free(d_u_cred);
+                       goto error_out;
+                   }
 
-               d_u_cred->auxinfo.creation_time = time(0);
-               d_u_cred->auxinfo.time_rec = 0;
-               d_u_cred->loopback = d_u_cred;
+                   d_u_cred->cred_array = malloc(sizeof(gss_cred_id_t));
+                   if (d_u_cred->cred_array != NULL) {
+                       d_u_cred->cred_array[0] = tmp_d_cred;
+                   } else {
+                       free(d_u_cred);
+                       status = GSS_S_FAILURE;
+                       goto error_out;
+                   }
 
-               if (mech->gss_inquire_cred) {
-                   status = mech->gss_inquire_cred(minor_status,
-                                                   tmp_d_cred,
-                                                   &internal_name,
-                                                   &d_u_cred->auxinfo.time_rec,
-                                                   &d_u_cred->auxinfo.cred_usage,
-                                                   NULL);
-                   if (status != GSS_S_COMPLETE)
-                       map_error(minor_status, mech);
-               }
+                   d_u_cred->auxinfo.creation_time = time(0);
+                   d_u_cred->auxinfo.time_rec = 0;
+                   d_u_cred->loopback = d_u_cred;
+
+                   internal_name = GSS_C_NO_NAME;
+
+                   if (mech->gss_inquire_cred) {
+                       status = mech->gss_inquire_cred(minor_status,
+                                                       tmp_d_cred,
+                                                       &internal_name,
+                                                       &d_u_cred->auxinfo.time_rec,
+                                                       &d_u_cred->auxinfo.cred_usage,
+                                                       NULL);
+                       if (status != GSS_S_COMPLETE)
+                           map_error(minor_status, mech);
+                   }
 
-               if (internal_name != NULL) {
-                   temp_status = gssint_convert_name_to_union_name(
-                       &temp_minor_status, mech,
-                       internal_name, &tmp_src_name);
-                   if (temp_status != GSS_S_COMPLETE) {
-                       *minor_status = temp_minor_status;
-                       map_error(minor_status, mech);
-                       if (output_token->length)
-                           (void) gss_release_buffer(
+                   if (internal_name != GSS_C_NO_NAME) {
+                       /* consumes internal_name regardless of success */
+                       temp_status = gssint_convert_name_to_union_name(
+                           &temp_minor_status, mech,
+                           internal_name, &tmp_src_name);
+                       if (temp_status != GSS_S_COMPLETE) {
+                           *minor_status = temp_minor_status;
+                           map_error(minor_status, mech);
+                           if (output_token->length)
+                               (void) gss_release_buffer(
+                                   &temp_minor_status,
+                                   output_token);
+                           (void) gss_release_oid(&temp_minor_status,
+                                                  &actual_mech);
+                           free(d_u_cred->cred_array);
+                           free(d_u_cred);
+                           return (temp_status);
+                       }
+
+                       if (tmp_src_name != GSS_C_NO_NAME) {
+                           status = gss_display_name(
                                &temp_minor_status,
-                               output_token);
-                       free(d_u_cred->cred_array);
-                       free(d_u_cred);
-                       return (temp_status);
+                               tmp_src_name,
+                               &d_u_cred->auxinfo.name,
+                               &d_u_cred->auxinfo.name_type);
+                           (void) gss_release_name(&temp_minor_status,
+                                                   &tmp_src_name);
+                       }
                    }
-               }
 
-               if (tmp_src_name != NULL) {
-                   status = gss_display_name(
-                       &temp_minor_status,
-                       tmp_src_name,
-                       &d_u_cred->auxinfo.name,
-                       &d_u_cred->auxinfo.name_type);
+                   *d_cred = (gss_cred_id_t)d_u_cred;
                }
-
-               *d_cred = (gss_cred_id_t)d_u_cred;
            }
 
-           if (src_name == NULL && tmp_src_name != NULL)
-               (void) gss_release_name(&temp_minor_status,
-                                       &tmp_src_name);
+           if (mech_type != NULL)
+               *mech_type = actual_mech;
+           else
+               (void) gss_release_oid(&temp_minor_status, &actual_mech);
            if (ret_flags != NULL)
                *ret_flags = temp_ret_flags;
            return      (status);
index fada9e88725c31ead0cd59dc402a4a998af6e4f4..6dfc65f7b290e68f9005d5f8828537ce9d677165 100644 (file)
@@ -2,7 +2,7 @@
 
 /*
  * Copyright 1996 by Sun Microsystems, Inc.
- * 
+ *
  * Permission to use, copy, modify, distribute, and sell this software
  * and its documentation for any purpose is hereby granted without fee,
  * provided that the above copyright notice appears in all copies and
@@ -12,7 +12,7 @@
  * without specific, written prior permission. Sun Microsystems makes no
  * representations about the suitability of this software for any
  * purpose.  It is provided "as is" without express or implied warranty.
- * 
+ *
  * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 #include <errno.h>
 #include <time.h>
 
-static gss_OID_set
-create_actual_mechs(mechs_array, count)
-    const gss_OID      mechs_array;
-    int count;
-{
-    gss_OID_set        actual_mechs;
-    int                        i;
-    OM_uint32          minor;
-
-    actual_mechs = (gss_OID_set) malloc(sizeof(gss_OID_set_desc));
-    if (!actual_mechs)
-       return NULL;
-
-    actual_mechs->elements = (gss_OID)
-       malloc(sizeof (gss_OID_desc) * count);
-    if (!actual_mechs->elements) {
-       free(actual_mechs);
-       return NULL;
-    }
-    
-    actual_mechs->count = 0;
-
-    for (i = 0; i < count; i++) {
-       actual_mechs->elements[i].elements = (void *)
-           malloc(mechs_array[i].length);
-       if (actual_mechs->elements[i].elements == NULL) {
-           (void) gss_release_oid_set(&minor, &actual_mechs);
-           return (NULL);
-       }
-       g_OID_copy(&actual_mechs->elements[i], &mechs_array[i]);
-       actual_mechs->count++;
-    }
-
-    return actual_mechs;
-}
-
 static OM_uint32
 val_acq_cred_args(
     OM_uint32 *minor_status,
@@ -172,7 +136,7 @@ OM_uint32 *         time_rec;
        mech = gssint_get_mechanism(NULL);
        if (mech == NULL)
            return (GSS_S_BAD_MECH);
-       
+
        mechs = &default_OID_set;
        default_OID_set.count = 1;
        default_OID_set.elements = &default_OID;
@@ -234,12 +198,16 @@ OM_uint32 *               time_rec;
      * setup the actual mechs output parameter
      */
     if (actual_mechs != NULL) {
-       if ((*actual_mechs = create_actual_mechs(creds->mechs_array,
-                                                creds->count)) == NULL) {
+       gss_OID_set_desc oids;
+
+       oids.count = creds->count;
+       oids.elements = creds->mechs_array;
+
+       major = generic_gss_copy_oid_set(minor_status, &oids, actual_mechs);
+       if (GSS_ERROR(major)) {
            (void) gss_release_cred(minor_status,
                                    (gss_cred_id_t *)&creds);
-           *minor_status = 0;
-           return (GSS_S_FAILURE);
+           return (major);
        }
     }
 
@@ -312,7 +280,7 @@ OM_uint32 KRB5_CALLCONV
 gss_add_cred(minor_status, input_cred_handle,
                  desired_name, desired_mech, cred_usage,
                  initiator_time_req, acceptor_time_req,
-                 output_cred_handle, actual_mechs, 
+                 output_cred_handle, actual_mechs,
                  initiator_time_rec, acceptor_time_rec)
     OM_uint32          *minor_status;
     gss_cred_id_t      input_cred_handle;
@@ -434,7 +402,7 @@ gss_add_cred(minor_status, input_cred_handle,
            status = mech->gss_display_name(&temp_minor_status, internal_name,
                                            &union_cred->auxinfo.name,
                                            &union_cred->auxinfo.name_type);
-       
+
            if (status != GSS_S_COMPLETE)
                goto errout;
        }
@@ -475,10 +443,14 @@ gss_add_cred(minor_status, input_cred_handle,
     g_OID_copy(&new_mechs_array[union_cred->count],
               &mech->mech_type);
 
-    if (actual_mechs) {
-       *actual_mechs = create_actual_mechs(new_mechs_array,
-                                           union_cred->count + 1);
-       if (*actual_mechs == NULL) {
+    if (actual_mechs != NULL) {
+       gss_OID_set_desc oids;
+
+       oids.count = union_cred->count + 1;
+       oids.elements = new_mechs_array;
+
+       status = generic_gss_copy_oid_set(minor_status, &oids, actual_mechs);
+       if (GSS_ERROR(status)) {
            free(new_mechs_array[union_cred->count].elements);
            goto errout;
        }
diff --git a/src/lib/gssapi/mechglue/g_acquire_cred_imp_name.c b/src/lib/gssapi/mechglue/g_acquire_cred_imp_name.c
new file mode 100644 (file)
index 0000000..9ba6a1f
--- /dev/null
@@ -0,0 +1,549 @@
+/* #pragma ident       "@(#)g_acquire_cred.c   1.22    04/02/23 SMI" */
+
+/*
+ * Copyright 2009 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.
+ *
+ */
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine for gss_acquire_cred_impersonate_name
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+static OM_uint32
+val_acq_cred_impersonate_name_args(
+    OM_uint32 *minor_status,
+    const gss_cred_id_t impersonator_cred_handle,
+    const gss_name_t desired_name,
+    OM_uint32 time_req,
+    gss_OID_set desired_mechs,
+    gss_cred_usage_t cred_usage,
+    gss_cred_id_t *output_cred_handle,
+    gss_OID_set *actual_mechs,
+    OM_uint32 *time_rec)
+{
+
+    /* Initialize outputs. */
+
+    if (minor_status != NULL)
+       *minor_status = 0;
+
+    if (output_cred_handle != NULL)
+       *output_cred_handle = GSS_C_NO_CREDENTIAL;
+
+    if (actual_mechs != NULL)
+       *actual_mechs = GSS_C_NULL_OID_SET;
+
+    if (time_rec != NULL)
+       *time_rec = 0;
+
+    /* Validate arguments. */
+
+    if (minor_status == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    if (impersonator_cred_handle == GSS_C_NO_CREDENTIAL)
+       return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED);
+
+    if (desired_name == GSS_C_NO_NAME)
+       return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+    if (output_cred_handle == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    if (cred_usage != GSS_C_ACCEPT
+       && cred_usage != GSS_C_INITIATE
+       && cred_usage != GSS_C_BOTH) {
+       if (minor_status) {
+           *minor_status = EINVAL;
+           map_errcode(minor_status);
+       }
+       return GSS_S_FAILURE;
+    }
+
+    return (GSS_S_COMPLETE);
+}
+
+
+OM_uint32 KRB5_CALLCONV
+gss_acquire_cred_impersonate_name(OM_uint32 *minor_status,
+                                 const gss_cred_id_t impersonator_cred_handle,
+                                 const gss_name_t desired_name,
+                                 OM_uint32 time_req,
+                                 const gss_OID_set desired_mechs,
+                                 gss_cred_usage_t cred_usage,
+                                 gss_cred_id_t *output_cred_handle,
+                                 gss_OID_set *actual_mechs,
+                                 OM_uint32 *time_rec)
+{
+    OM_uint32 major = GSS_S_FAILURE;
+    OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE;
+    gss_OID_set_desc default_OID_set;
+    gss_OID_set mechs;
+    gss_OID_desc default_OID;
+    gss_mechanism mech;
+    unsigned int i;
+    gss_union_cred_t creds;
+
+    major = val_acq_cred_impersonate_name_args(minor_status,
+                                              impersonator_cred_handle,
+                                              desired_name,
+                                              time_req,
+                                              desired_mechs,
+                                              cred_usage,
+                                              output_cred_handle,
+                                              actual_mechs,
+                                              time_rec);
+    if (major != GSS_S_COMPLETE)
+       return (major);
+
+    /* Initial value needed below. */
+    major = GSS_S_FAILURE;
+
+    /*
+     * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an
+     * appropriate default.  We use the first mechanism in the
+     * mechansim list as the default. This set is created with
+     * statics thus needs not be freed
+     */
+    if(desired_mechs == GSS_C_NULL_OID_SET) {
+       mech = gssint_get_mechanism(NULL);
+       if (mech == NULL)
+           return (GSS_S_BAD_MECH);
+
+       mechs = &default_OID_set;
+       default_OID_set.count = 1;
+       default_OID_set.elements = &default_OID;
+       default_OID.length = mech->mech_type.length;
+       default_OID.elements = mech->mech_type.elements;
+    } else
+       mechs = desired_mechs;
+
+    if (mechs->count == 0)
+       return (GSS_S_BAD_MECH);
+
+    /* allocate the output credential structure */
+    creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc));
+    if (creds == NULL)
+       return (GSS_S_FAILURE);
+
+    /* initialize to 0s */
+    (void) memset(creds, 0, sizeof (gss_union_cred_desc));
+    creds->loopback = creds;
+
+    /* for each requested mech attempt to obtain a credential */
+    for (i = 0; i < mechs->count; i++) {
+       major = gss_add_cred_impersonate_name(minor_status,
+                                             (gss_cred_id_t)creds,
+                                             impersonator_cred_handle,
+                                             desired_name,
+                                             &mechs->elements[i],
+                                             cred_usage,
+                                             time_req,
+                                             time_req, NULL,
+                                             NULL,
+                                             &initTimeOut,
+                                             &acceptTimeOut);
+       if (major == GSS_S_COMPLETE) {
+           /* update the credential's time */
+           if (cred_usage == GSS_C_ACCEPT) {
+               if (outTime > acceptTimeOut)
+                   outTime = acceptTimeOut;
+           } else if (cred_usage == GSS_C_INITIATE) {
+               if (outTime > initTimeOut)
+                   outTime = initTimeOut;
+           } else {
+               /*
+                * time_rec is the lesser of the
+                * init/accept times
+                */
+               if (initTimeOut > acceptTimeOut)
+                   outTime = (outTime > acceptTimeOut) ?
+                       acceptTimeOut : outTime;
+               else
+                   outTime = (outTime > initTimeOut) ?
+                       initTimeOut : outTime;
+           }
+       }
+    } /* for */
+
+    /* ensure that we have at least one credential element */
+    if (creds->count < 1) {
+       free(creds);
+       return (major);
+    }
+
+    /*
+     * fill in output parameters
+     * setup the actual mechs output parameter
+     */
+    if (actual_mechs != NULL) {
+       gss_OID_set_desc oids;
+
+       oids.count = creds->count;
+       oids.elements = creds->mechs_array;
+
+       major = generic_gss_copy_oid_set(minor_status, &oids, actual_mechs);
+       if (GSS_ERROR(major)) {
+           (void) gss_release_cred(minor_status,
+                                   (gss_cred_id_t *)&creds);
+           return (major);
+       }
+    }
+
+    if (time_rec)
+       *time_rec = outTime;
+
+
+    creds->loopback = creds;
+    *output_cred_handle = (gss_cred_id_t)creds;
+    return (GSS_S_COMPLETE);
+}
+
+static OM_uint32
+val_add_cred_impersonate_name_args(
+    OM_uint32 *minor_status,
+    gss_cred_id_t input_cred_handle,
+    const gss_cred_id_t impersonator_cred_handle,
+    gss_name_t desired_name,
+    gss_OID desired_mech,
+    gss_cred_usage_t cred_usage,
+    OM_uint32 initiator_time_req,
+    OM_uint32 acceptor_time_req,
+    gss_cred_id_t *output_cred_handle,
+    gss_OID_set *actual_mechs,
+    OM_uint32 *initiator_time_rec,
+    OM_uint32 *acceptor_time_rec)
+{
+
+    /* Initialize outputs. */
+
+    if (minor_status != NULL)
+       *minor_status = 0;
+
+    if (output_cred_handle != NULL)
+       *output_cred_handle = GSS_C_NO_CREDENTIAL;
+
+    if (actual_mechs != NULL)
+       *actual_mechs = GSS_C_NO_OID_SET;
+
+    if (acceptor_time_rec != NULL)
+       *acceptor_time_rec = 0;
+
+    if (initiator_time_rec != NULL)
+       *initiator_time_rec = 0;
+
+    /* Validate arguments. */
+
+    if (minor_status == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    if (impersonator_cred_handle == GSS_C_NO_CREDENTIAL)
+       return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED);
+
+    if (desired_name == GSS_C_NO_NAME)
+       return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+    if (input_cred_handle == GSS_C_NO_CREDENTIAL &&
+       output_cred_handle == NULL)
+       return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
+
+    if (cred_usage != GSS_C_ACCEPT
+       && cred_usage != GSS_C_INITIATE
+       && cred_usage != GSS_C_BOTH) {
+       if (minor_status) {
+           *minor_status = EINVAL;
+           map_errcode(minor_status);
+       }
+       return GSS_S_FAILURE;
+    }
+
+    return (GSS_S_COMPLETE);
+}
+
+
+/* V2 KRB5_CALLCONV */
+OM_uint32 KRB5_CALLCONV
+gss_add_cred_impersonate_name(OM_uint32 *minor_status,
+                             gss_cred_id_t input_cred_handle,
+                             const gss_cred_id_t impersonator_cred_handle,
+                             const gss_name_t desired_name,
+                             const gss_OID desired_mech,
+                             gss_cred_usage_t cred_usage,
+                             OM_uint32 initiator_time_req,
+                             OM_uint32 acceptor_time_req,
+                             gss_cred_id_t *output_cred_handle,
+                             gss_OID_set *actual_mechs,
+                             OM_uint32 *initiator_time_rec,
+                             OM_uint32 *acceptor_time_rec)
+{
+    OM_uint32          status, temp_minor_status;
+    OM_uint32          time_req, time_rec;
+    gss_union_name_t   union_name;
+    gss_union_cred_t   new_union_cred, union_cred;
+    gss_cred_id_t      mech_impersonator_cred;
+    gss_name_t         internal_name = GSS_C_NO_NAME;
+    gss_name_t         allocated_name = GSS_C_NO_NAME;
+    gss_mechanism      mech;
+    gss_cred_id_t      cred = NULL;
+    gss_OID            new_mechs_array = NULL;
+    gss_cred_id_t *    new_cred_array = NULL;
+
+    status = val_add_cred_impersonate_name_args(minor_status,
+                                               input_cred_handle,
+                                               impersonator_cred_handle,
+                                               desired_name,
+                                               desired_mech,
+                                               cred_usage,
+                                               initiator_time_req,
+                                               acceptor_time_req,
+                                               output_cred_handle,
+                                               actual_mechs,
+                                               initiator_time_rec,
+                                               acceptor_time_rec);
+    if (status != GSS_S_COMPLETE)
+       return (status);
+
+    mech = gssint_get_mechanism(desired_mech);
+    if (!mech)
+       return GSS_S_BAD_MECH;
+    else if (!mech->gss_acquire_cred)
+       return (GSS_S_UNAVAILABLE);
+
+    if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
+       union_cred = malloc(sizeof (gss_union_cred_desc));
+       if (union_cred == NULL)
+           return (GSS_S_FAILURE);
+
+       (void) memset(union_cred, 0, sizeof (gss_union_cred_desc));
+
+       /* for default credentials we will use GSS_C_NO_NAME */
+       internal_name = GSS_C_NO_NAME;
+    } else {
+       union_cred = (gss_union_cred_t)input_cred_handle;
+       if (gssint_get_mechanism_cred(union_cred, desired_mech) !=
+           GSS_C_NO_CREDENTIAL)
+           return (GSS_S_DUPLICATE_ELEMENT);
+    }
+
+    mech_impersonator_cred =
+       gssint_get_mechanism_cred((gss_union_cred_t)impersonator_cred_handle,
+                                 desired_mech);
+    if (mech_impersonator_cred == GSS_C_NO_CREDENTIAL)
+       return (GSS_S_NO_CRED);
+
+    /* may need to create a mechanism specific name */
+    union_name = (gss_union_name_t)desired_name;
+    if (union_name->mech_type &&
+       g_OID_equal(union_name->mech_type,
+                   &mech->mech_type))
+       internal_name = union_name->mech_name;
+    else {
+       if (gssint_import_internal_name(minor_status,
+                                       &mech->mech_type, union_name,
+                                       &allocated_name) != GSS_S_COMPLETE)
+           return (GSS_S_BAD_NAME);
+       internal_name = allocated_name;
+    }
+
+    if (cred_usage == GSS_C_ACCEPT)
+       time_req = acceptor_time_req;
+    else if (cred_usage == GSS_C_INITIATE)
+       time_req = initiator_time_req;
+    else if (cred_usage == GSS_C_BOTH)
+       time_req = (acceptor_time_req > initiator_time_req) ?
+           acceptor_time_req : initiator_time_req;
+    else
+       time_req = 0;
+
+    status = mech->gss_acquire_cred_impersonate_name(minor_status,
+                                                    mech_impersonator_cred,
+                                                    internal_name,
+                                                    time_req,
+                                                    GSS_C_NULL_OID_SET,
+                                                    cred_usage,
+                                                    &cred,
+                                                    NULL,
+                                                    &time_rec);
+    if (status != GSS_S_COMPLETE) {
+       map_error(minor_status, mech);
+       goto errout;
+    }
+
+    /* may need to set credential auxinfo strucutre */
+    if (union_cred->auxinfo.creation_time == 0) {
+       union_cred->auxinfo.creation_time = time(NULL);
+       union_cred->auxinfo.time_rec = time_rec;
+       union_cred->auxinfo.cred_usage = cred_usage;
+
+       /*
+        * we must set the name; if name is not supplied
+        * we must do inquire cred to get it
+        */
+       if (internal_name == NULL) {
+           if (mech->gss_inquire_cred == NULL ||
+               ((status = mech->gss_inquire_cred(
+                     &temp_minor_status, cred,
+                     &allocated_name, NULL, NULL,
+                     NULL)) != GSS_S_COMPLETE))
+               goto errout;
+           internal_name = allocated_name;
+       }
+
+       if (internal_name != GSS_C_NO_NAME) {
+           status = mech->gss_display_name(&temp_minor_status, internal_name,
+                                           &union_cred->auxinfo.name,
+                                           &union_cred->auxinfo.name_type);
+
+           if (status != GSS_S_COMPLETE)
+               goto errout;
+       }
+    }
+
+    /* now add the new credential elements */
+    new_mechs_array = (gss_OID)
+       malloc(sizeof (gss_OID_desc) * (union_cred->count+1));
+
+    new_cred_array = (gss_cred_id_t *)
+       malloc(sizeof (gss_cred_id_t) * (union_cred->count+1));
+
+    if (!new_mechs_array || !new_cred_array) {
+       status = GSS_S_FAILURE;
+       goto errout;
+    }
+
+    if (acceptor_time_rec)
+       if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
+           *acceptor_time_rec = time_rec;
+    if (initiator_time_rec)
+       if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)
+           *initiator_time_rec = time_rec;
+
+    /*
+     * OK, expand the mechanism array and the credential array
+     */
+    (void) memcpy(new_mechs_array, union_cred->mechs_array,
+                 sizeof (gss_OID_desc) * union_cred->count);
+    (void) memcpy(new_cred_array, union_cred->cred_array,
+                 sizeof (gss_cred_id_t) * union_cred->count);
+
+    new_cred_array[union_cred->count] = cred;
+    if ((new_mechs_array[union_cred->count].elements =
+        malloc(mech->mech_type.length)) == NULL)
+       goto errout;
+
+    g_OID_copy(&new_mechs_array[union_cred->count],
+              &mech->mech_type);
+
+    if (actual_mechs != NULL) {
+       gss_OID_set_desc oids;
+
+       oids.count = union_cred->count + 1;
+       oids.elements = new_mechs_array;
+
+       status = generic_gss_copy_oid_set(minor_status, &oids, actual_mechs);
+       if (GSS_ERROR(status)) {
+           free(new_mechs_array[union_cred->count].elements);
+           goto errout;
+       }
+    }
+
+    if (output_cred_handle == NULL) {
+       free(union_cred->mechs_array);
+       free(union_cred->cred_array);
+       new_union_cred = union_cred;
+    } else {
+       new_union_cred = malloc(sizeof (gss_union_cred_desc));
+       if (new_union_cred == NULL) {
+           free(new_mechs_array[union_cred->count].elements);
+           goto errout;
+       }
+       *new_union_cred = *union_cred;
+       *output_cred_handle = (gss_cred_id_t)new_union_cred;
+    }
+
+    new_union_cred->mechs_array = new_mechs_array;
+    new_union_cred->cred_array = new_cred_array;
+    new_union_cred->count++;
+    new_union_cred->loopback = new_union_cred;
+
+    /* We're done with the internal name. Free it if we allocated it. */
+
+    if (allocated_name)
+       (void) gssint_release_internal_name(&temp_minor_status,
+                                          &mech->mech_type,
+                                          &allocated_name);
+
+    return (GSS_S_COMPLETE);
+
+errout:
+    if (new_mechs_array)
+       free(new_mechs_array);
+    if (new_cred_array)
+       free(new_cred_array);
+
+    if (cred != NULL && mech->gss_release_cred)
+       mech->gss_release_cred(&temp_minor_status, &cred);
+
+    if (allocated_name)
+       (void) gssint_release_internal_name(&temp_minor_status,
+                                          &mech->mech_type,
+                                          &allocated_name);
+
+    if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred) {
+       if (union_cred->auxinfo.name.value)
+           free(union_cred->auxinfo.name.value);
+       free(union_cred);
+    }
+
+    return (status);
+}
index aafc20e06e7f845fcc2a0fd9b8a3a17d83aff155..711c58fd8acc5a08b3f2996bb1ffa0e595a8fabe 100644 (file)
@@ -660,25 +660,9 @@ gssint_get_mechanism_cred(union_cred, mech_type)
     if (union_cred == GSS_C_NO_CREDENTIAL)
        return GSS_C_NO_CREDENTIAL;
 
-    /* SPNEGO mechanism will again call into GSSAPI */
-    if (g_OID_equal(&gss_spnego_mechanism_oid_desc, mech_type))
-       return (gss_cred_id_t)union_cred;
-
     for (i=0; i < union_cred->count; i++) {
        if (g_OID_equal(mech_type, &union_cred->mechs_array[i]))
            return union_cred->cred_array[i];
-
-       /* for SPNEGO, check the next-lower set of creds */
-       if (g_OID_equal(&gss_spnego_mechanism_oid_desc, &union_cred->mechs_array[i])) {
-           gss_union_cred_t candidate_cred;
-           gss_cred_id_t    sub_cred;
-
-           candidate_cred = (gss_union_cred_t)union_cred->cred_array[i];
-           sub_cred = gssint_get_mechanism_cred(candidate_cred, mech_type);
-
-           if(sub_cred != GSS_C_NO_CREDENTIAL)
-               return sub_cred;
-       }
     }
     return GSS_C_NO_CREDENTIAL;
 }
index b944131647a7e0d8dc80d09d2d299474af68e695..41aa6821bbbcfda3975401137b4859684000999b 100644 (file)
@@ -761,7 +761,10 @@ build_dynamicMech(void *dl, const gss_OID mech_type)
        GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_unwrap_iov);
        GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_wrap_iov_length);
        GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_complete_auth_token);
-       /* Naming extensions */
+       /* Services4User (introduced in 1.8) */
+       GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_acquire_cred_impersonate_name);
+       GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_add_cred_impersonate_name);
+       /* Naming extensions (introduced in 1.8) */
        GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_display_name_ext);
        GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_inquire_name);
        GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_get_name_attribute);
index 68625242be49383fd7688db26cd2f01e429bbcac..91e4eb4531270240d458f06c62c95cb03b4f675e 100644 (file)
@@ -71,8 +71,8 @@ gss_set_sec_context_option (OM_uint32 *minor_status,
        return GSS_S_UNAVAILABLE;
 
     status = mech->gss_set_sec_context_option(minor_status,
-                                             ctx ? &internal_ctx :
-                                               &ctx->internal_ctx_id,
+                                             ctx ? &ctx->internal_ctx_id :
+                                             &internal_ctx,
                                              desired_object,
                                              value);
     if (status == GSS_S_COMPLETE) {
index b60cfb196adddeca22b40407db622332c229e51d..93e9a2b071f8fb832211e848415842f48250c8ac 100644 (file)
@@ -473,6 +473,37 @@ typedef struct gss_config {
                    gss_buffer_t        /* input_message_buffer */
                    );
 
+       /* New for 1.8 */
+
+       OM_uint32       (*gss_acquire_cred_impersonate_name)
+       (
+           OM_uint32 *,                /* minor_status */
+           const gss_cred_id_t,        /* impersonator_cred_handle */
+           const gss_name_t,           /* desired_name */
+           OM_uint32,                  /* time_req */
+           const gss_OID_set,          /* desired_mechs */
+           gss_cred_usage_t,           /* cred_usage */
+           gss_cred_id_t *,            /* output_cred_handle */
+           gss_OID_set *,              /* actual_mechs */
+           OM_uint32 *                 /* time_rec */
+       /* */);
+
+       OM_uint32       (*gss_add_cred_impersonate_name)
+       (
+           OM_uint32 *,                /* minor_status */
+           gss_cred_id_t,              /* input_cred_handle */
+           const gss_cred_id_t,        /* impersonator_cred_handle */
+           const gss_name_t,           /* desired_name */
+           const gss_OID,              /* desired_mech */
+           gss_cred_usage_t,           /* cred_usage */
+           OM_uint32,                  /* initiator_time_req */
+           OM_uint32,                  /* acceptor_time_req */
+           gss_cred_id_t *,            /* output_cred_handle */
+           gss_OID_set *,              /* actual_mechs */
+           OM_uint32 *,                /* initiator_time_rec */
+           OM_uint32 *                 /* acceptor_time_rec */
+       /* */);
+
        OM_uint32       (*gss_display_name_ext)
        (
            OM_uint32 *,                /* minor_status */
@@ -543,6 +574,7 @@ typedef struct gss_config {
            gss_buffer_t,               /* type_id */
            gss_any_t *                 /* input */
        /* */);
+
 } *gss_mechanism;
 
 /* This structure MUST NOT be used by any code outside libgss */
index 181f44b07798c903c03aa66da7c47fb0a866efe4..7793383ca1f83d7b24e79e59501265c90ace6e21 100644 (file)
@@ -218,6 +218,16 @@ OM_uint32 spnego_gss_release_name
        gss_name_t *            /* input_name */
 );
 
+OM_uint32 spnego_gss_inquire_cred
+(
+       OM_uint32 *,            /* minor_status */
+       gss_cred_id_t,          /* cred_handle */
+       gss_name_t *,           /* name */
+       OM_uint32 *,            /* lifetime */
+       int *,                  /* cred_usage */
+       gss_OID_set *           /* mechanisms */
+);
+
 OM_uint32 spnego_gss_inquire_names_for_mech
 (
        OM_uint32 *,            /* minor_status */
@@ -332,6 +342,15 @@ spnego_gss_inquire_sec_context_by_oid
        gss_buffer_set_t *data_set
 );
 
+OM_uint32
+spnego_gss_inquire_cred_by_oid
+(
+       OM_uint32 *minor_status,
+       const gss_cred_id_t cred_handle,
+       const gss_OID desired_object,
+       gss_buffer_set_t *data_set
+);
+
 OM_uint32
 spnego_gss_set_sec_context_option
 (
@@ -411,6 +430,18 @@ spnego_gss_complete_auth_token
        gss_buffer_t input_message_buffer
 );
 
+OM_uint32
+spnego_gss_acquire_cred_impersonate_name(
+    OM_uint32 *,           /* minor_status */
+    const gss_cred_id_t,    /* impersonator_cred_handle */
+    const gss_name_t,      /* desired_name */
+    OM_uint32,             /* time_req */
+    const gss_OID_set,     /* desired_mechs */
+    gss_cred_usage_t,      /* cred_usage */
+    gss_cred_id_t *,       /* output_cred_handle */
+    gss_OID_set *,         /* actual_mechs */
+    OM_uint32 *);          /* time_rec */
+
 OM_uint32
 spnego_gss_display_name_ext
 (
index 178223e43006d1c85a44b306d8ea69f9c5c6ac3a..740ae8e9d8f5a455d37fc0a065553a770b2c30b4 100644 (file)
@@ -231,7 +231,7 @@ static struct gss_config spnego_mechanism =
        spnego_gss_display_name,
        spnego_gss_import_name,
        spnego_gss_release_name,
-       NULL,                           /* gss_inquire_cred */
+       spnego_gss_inquire_cred,        /* gss_inquire_cred */
        NULL,                           /* gss_add_cred */
 #ifndef LEAN_CLIENT
        spnego_gss_export_sec_context,          /* gss_export_sec_context */
@@ -248,7 +248,7 @@ static struct gss_config spnego_mechanism =
        NULL,                           /* gss_export_name */
        NULL,                           /* gss_store_cred */
        spnego_gss_inquire_sec_context_by_oid, /* gss_inquire_sec_context_by_oid */
-       NULL,                           /* gss_inquire_cred_by_oid */
+       spnego_gss_inquire_cred_by_oid, /* gss_inquire_cred_by_oid */
        spnego_gss_set_sec_context_option, /* gss_set_sec_context_option */
        NULL,                           /* gssspi_set_cred_option */
        NULL,                           /* gssspi_mech_invoke */
@@ -258,6 +258,9 @@ static struct gss_config spnego_mechanism =
        spnego_gss_unwrap_iov,
        spnego_gss_wrap_iov_length,
        spnego_gss_complete_auth_token,
+       spnego_gss_complete_auth_token,
+       spnego_gss_acquire_cred_impersonate_name,
+       NULL,                           /* gss_add_cred_impersonate_name */
        spnego_gss_display_name_ext,
        spnego_gss_inquire_name,
        spnego_gss_get_name_attribute,
@@ -1689,6 +1692,13 @@ cleanup:
                        *src_name = sc->internal_name;
                }
                release_spnego_ctx(&sc);
+       } else if (ret != GSS_S_CONTINUE_NEEDED) {
+               if (sc != NULL) {
+                       gss_delete_sec_context(&tmpmin, &sc->ctx_handle,
+                                              GSS_C_NO_BUFFER);
+                       release_spnego_ctx(&sc);
+               }
+               *context_handle = GSS_C_NO_CONTEXT;
        }
        gss_release_buffer(&tmpmin, &mechtok_out);
        if (mechtok_in != GSS_C_NO_BUFFER) {
@@ -1788,6 +1798,76 @@ spnego_gss_release_name(
        return (status);
 }
 
+OM_uint32
+spnego_gss_inquire_cred(
+                       OM_uint32 *minor_status,
+                       gss_cred_id_t cred_handle,
+                       gss_name_t *name,
+                       OM_uint32 *lifetime,
+                       int *cred_usage,
+                       gss_OID_set *mechanisms)
+{
+       OM_uint32 status;
+       gss_cred_id_t creds = GSS_C_NO_CREDENTIAL;
+       OM_uint32 tmp_minor_status;
+       OM_uint32 initiator_lifetime, acceptor_lifetime;
+
+       dsyslog("Entering inquire_cred\n");
+
+       /*
+        * To avoid infinite recursion, if GSS_C_NO_CREDENTIAL is
+        * supplied we call gss_inquire_cred_by_mech() on the
+        * first non-SPNEGO mechanism.
+        */
+       if (cred_handle == GSS_C_NO_CREDENTIAL) {
+               status = get_available_mechs(minor_status,
+                       GSS_C_NO_NAME,
+                       GSS_C_BOTH,
+                       &creds,
+                       mechanisms);
+               if (status != GSS_S_COMPLETE) {
+                       dsyslog("Leaving inquire_cred\n");
+                       return (status);
+               }
+
+               if ((*mechanisms)->count == 0) {
+                       gss_release_cred(&tmp_minor_status, &creds);
+                       gss_release_oid_set(&tmp_minor_status, mechanisms);
+                       dsyslog("Leaving inquire_cred\n");
+                       return (GSS_S_DEFECTIVE_CREDENTIAL);
+               }
+
+               assert((*mechanisms)->elements != NULL);
+
+               status = gss_inquire_cred_by_mech(minor_status,
+                       creds,
+                       &(*mechanisms)->elements[0],
+                       name,
+                       &initiator_lifetime,
+                       &acceptor_lifetime,
+                       cred_usage);
+               if (status != GSS_S_COMPLETE) {
+                       gss_release_cred(&tmp_minor_status, &creds);
+                       dsyslog("Leaving inquire_cred\n");
+                       return (status);
+               }
+
+               if (lifetime != NULL)
+                       *lifetime = (*cred_usage == GSS_C_ACCEPT) ?
+                               acceptor_lifetime : initiator_lifetime;
+
+               gss_release_cred(&tmp_minor_status, &creds);
+       } else {
+               status = gss_inquire_cred(minor_status, cred_handle,
+                                         name, lifetime,
+                                         cred_usage, mechanisms);
+       }
+
+       dsyslog("Leaving inquire_cred\n");
+
+       return (status);
+}
+
 /*ARGSUSED*/
 OM_uint32
 spnego_gss_compare_name(
@@ -2091,6 +2171,21 @@ spnego_gss_inquire_sec_context_by_oid(
        return (ret);
 }
 
+OM_uint32
+spnego_gss_inquire_cred_by_oid(
+               OM_uint32 *minor_status,
+               const gss_cred_id_t cred_handle,
+               const gss_OID desired_object,
+               gss_buffer_set_t *data_set)
+{
+       OM_uint32 ret;
+       ret = gss_inquire_cred_by_oid(minor_status,
+                               cred_handle,
+                               desired_object,
+                               data_set);
+       return (ret);
+}
+
 OM_uint32
 spnego_gss_set_sec_context_option(
                OM_uint32 *minor_status,
@@ -2221,6 +2316,53 @@ spnego_gss_complete_auth_token(
        return (ret);
 }
 
+OM_uint32
+spnego_gss_acquire_cred_impersonate_name(OM_uint32 *minor_status,
+                                        const gss_cred_id_t impersonator_cred_handle,
+                                        gss_name_t desired_name,
+                                        OM_uint32 time_req,
+                                        gss_OID_set desired_mechs,
+                                        gss_cred_usage_t cred_usage,
+                                        gss_cred_id_t *output_cred_handle,
+                                        gss_OID_set *actual_mechs,
+                                        OM_uint32 *time_rec)
+{
+       OM_uint32 status;
+       gss_OID_set amechs = GSS_C_NULL_OID_SET;
+
+       dsyslog("Entering spnego_gss_acquire_cred_impersonate_name\n");
+
+       if (actual_mechs)
+               *actual_mechs = NULL;
+
+       if (time_rec)
+               *time_rec = 0;
+
+       if (desired_mechs == GSS_C_NO_OID_SET) {
+               status = gss_inquire_cred(minor_status,
+                                         impersonator_cred_handle,
+                                         NULL, NULL,
+                                         NULL, &amechs);
+               if (status != GSS_S_COMPLETE)
+                       return status;
+
+               desired_mechs = amechs;
+       }
+
+       status = gss_acquire_cred_impersonate_name(minor_status,
+                       impersonator_cred_handle,
+                       desired_name, time_req,
+                       desired_mechs, cred_usage,
+                       output_cred_handle, actual_mechs,
+                       time_rec);
+
+       if (amechs != GSS_C_NULL_OID_SET)
+               (void) gss_release_oid_set(minor_status, &amechs);
+
+       dsyslog("Leaving spnego_gss_acquire_cred_impersonate_name\n");
+       return (status);
+}
+
 OM_uint32
 spnego_gss_display_name_ext(OM_uint32 *minor_status,
                            gss_name_t name,
index 2bd99adbc1536d2d70ed0964ca9263ca22dcab62..51637f7de4615339e0b79dc16a42fd61ccd81210 100644 (file)
@@ -78,6 +78,8 @@ static const char flags_pwchange_in[] = "pwchange";
 static const char flags_service_in[]   = "service";
 static const char flags_pwsvc_in[]     = "pwservice";
 static const char flags_md5_in[]       = "md5";
+static const char flags_ok_to_auth_as_delegate_in[] = "ok-to-auth-as-delegate";
+static const char flags_no_auth_data_required_in[] = "no-auth-data-required";
 static const char flags_pdate_out[]    = "Not Postdateable";
 static const char flags_fwd_out[]      = "Not Forwardable";
 static const char flags_tgtbased_out[] = "No TGT-based requests";
@@ -85,13 +87,15 @@ static const char flags_renew_out[] = "Not renewable";
 static const char flags_proxy_out[]    = "Not proxiable";
 static const char flags_dup_skey_out[] = "No DUP_SKEY requests";
 static const char flags_tickets_out[]  = "All Tickets Disallowed";
-static const char flags_preauth_out[]  = "Preauthorization required";
-static const char flags_hwauth_out[]   = "HW Authorization required";
+static const char flags_preauth_out[]  = "Preauthentication required";
+static const char flags_hwauth_out[]   = "HW authentication required";
 static const char flags_ok_as_delegate_out[]   = "OK as Delegate";
 static const char flags_pwchange_out[] = "Password Change required";
 static const char flags_service_out[]  = "Service Disabled";
 static const char flags_pwsvc_out[]    = "Password Changing Service";
 static const char flags_md5_out[]      = "RSA-MD5 supported";
+static const char flags_ok_to_auth_as_delegate_out[] = "Protocol transition with delegation allowed";
+static const char flags_no_auth_data_required_out[] = "No authorization data required";
 static const char flags_default_neg[]  = "-";
 static const char flags_default_sep[]  = " ";
 
@@ -115,7 +119,9 @@ static const struct flags_lookup_entry flags_table[] = {
 { KRB5_KDB_REQUIRES_PWCHANGE,  1,      flags_pwchange_in, flags_pwchange_out},
 { KRB5_KDB_DISALLOW_SVR,       0,      flags_service_in,  flags_service_out },
 { KRB5_KDB_PWCHANGE_SERVICE,   1,      flags_pwsvc_in,    flags_pwsvc_out   },
-{ KRB5_KDB_SUPPORT_DESMD5,     1,      flags_md5_in,      flags_md5_out     }
+{ KRB5_KDB_SUPPORT_DESMD5,     1,      flags_md5_in,      flags_md5_out     },
+{ KRB5_KDB_OK_TO_AUTH_AS_DELEGATE,  1, flags_ok_to_auth_as_delegate_in, flags_ok_to_auth_as_delegate_out },
+{ KRB5_KDB_NO_AUTH_DATA_REQUIRED,   1, flags_no_auth_data_required_in, flags_no_auth_data_required_out }
 };
 static const int flags_table_nents = sizeof(flags_table)/
                                     sizeof(flags_table[0]);
index f14f1263bab615160db45e0b908bd3fe46e8a8cf..0bbd72dad541d1a59f1e7ab600d263ffea7a0b09 100644 (file)
@@ -131,85 +131,85 @@ proc api_start {} {
        set pid [spawn $API]
        expect {
                -re "$prompt$" {}
-               eof { error "EOF starting API" }
-               timeout { error "Timeout starting API" }
+               eof { perror "EOF starting API" }
+               timeout { perror "Timeout starting API" }
        }
        if {! [info exists env(TCLUTIL)]} {
-               error "TCLUTIL environment variable isn't set"
+               perror "TCLUTIL environment variable isn't set"
        }
        # tcl 8.4 for some reason screws up autodetection of output
        # EOL translation.  Work around it for now.
        send "if { \[info commands fconfigure\] ne \"\" } { fconfigure stdout -translation lf }\n"
        expect {
                -re "$prompt$" {}
-               eof { error "EOF starting API" }
-               timeout { error "Timeout starting API" }
+               eof { perror "EOF starting API" }
+               timeout { perror "Timeout starting API" }
        }
        send "source $env(TCLUTIL)\n"
        expect {
                -re "$prompt$" {}
-               eof { error "EOF starting API" }
-               timeout { error "Timeout starting API" }
+               eof { perror "EOF starting API" }
+               timeout { perror "Timeout starting API" }
        }
        send "set current_struct_version \[expr \$KADM5_STRUCT_VERSION &~ \$KADM5_STRUCT_VERSION_MASK\]\n"
        expect {
                -re "$prompt$" {}
-               eof { error "EOF setting API varibles"}
-               timeout { error "timeout setting API varibles"}
+               eof { perror "EOF setting API varibles"}
+               timeout { perror "timeout setting API varibles"}
        }
        send "set current_api_version \[expr \$KADM5_API_VERSION_2 &~ \$KADM5_API_VERSION_MASK\]\n"
        expect {
                -re "$prompt$" {}
-               eof { error "EOF setting API varibles"}
-               timeout { error "timeout setting API varibles"}
+               eof { perror "EOF setting API varibles"}
+               timeout { perror "timeout setting API varibles"}
        }
        send "set bad_struct_version_mask \[expr 0x65432100 | \$current_struct_version\]\n"
        expect {
                -re "$prompt$" {}
-               eof { error "EOF setting API varibles"}
-               timeout { error "timeout setting API varibles"}
+               eof { perror "EOF setting API varibles"}
+               timeout { perror "timeout setting API varibles"}
        }
        send "set bad_api_version_mask \[expr 0x65432100 | \$current_api_version\]\n"
        expect {
                -re "$prompt$" {}
-               eof { error "EOF setting API varibles"}
-               timeout { error "timeout setting API varibles"}
+               eof { perror "EOF setting API varibles"}
+               timeout { perror "timeout setting API varibles"}
        }
        send "set no_api_version_mask \$current_api_version\n"
        expect {
                -re "$prompt$" {}
-               eof { error "EOF setting API varibles"}
-               timeout { error "timeout setting API varibles"}
+               eof { perror "EOF setting API varibles"}
+               timeout { perror "timeout setting API varibles"}
        }
        send "set no_struct_version_mask \$current_struct_version\n"
        expect {
                -re "$prompt$" {}
-               eof { error "EOF setting API varibles"}
-               timeout { error "timeout setting API varibles"}
+               eof { perror "EOF setting API varibles"}
+               timeout { perror "timeout setting API varibles"}
        }
        send "set old_api_version \[expr \$KADM5_API_VERSION_MASK | 0x00\]\n"
        expect {
                -re "$prompt$" {}
-               eof { error "EOF setting API varibles"}
-               timeout { error "timeout setting API varibles"}
+               eof { perror "EOF setting API varibles"}
+               timeout { perror "timeout setting API varibles"}
        }
        send "set old_struct_version \[expr \$KADM5_STRUCT_VERSION_MASK | 0x00\]\n"
        expect {
                -re "$prompt$" {}
-               eof { error "EOF setting API varibles"}
-               timeout { error "timeout setting API varibles"}
+               eof { perror "EOF setting API varibles"}
+               timeout { perror "timeout setting API varibles"}
        }
        send "set new_api_version \[expr \$KADM5_API_VERSION_MASK | 0xca\]\n"
        expect {
                -re "$prompt$" {}
-               eof { error "EOF setting API varibles"}
-               timeout { error "timeout setting API varibles"}
+               eof { perror "EOF setting API varibles"}
+               timeout { perror "timeout setting API varibles"}
        }
        send "set new_struct_version \[expr \$KADM5_STRUCT_VERSION_MASK | 0xca\]\n"
        expect {
                -re "$prompt$" {}
-               eof { error "EOF setting API varibles"}
-               timeout { error "timeout setting API varibles"}
+               eof { perror "EOF setting API varibles"}
+               timeout { perror "timeout setting API varibles"}
        }
 
        set api_pid $pid
index 361c727da83af692e8ce340c45cc2071a5f8f013..9537fc36aad32dd6d5b520e97f4d6c106d21b187 100644 (file)
@@ -22,7 +22,7 @@ proc lib_start_api {} {
                    $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
                    lib_handle
        }]} {
-           error "$test: unexpected failure in init"
+           perror "$test: unexpected failure in init"
            return
        }
        verbose "+++ restarted api ($lib_pid) for lib"
@@ -40,7 +40,7 @@ proc cmd {command} {
     expect {
        -re "OK .*$prompt$" { return 1 }
         -re "ERROR .*$prompt$" { return 0 }
-       "wrong # args" { error "$test: wrong number args"; return 0 }
+       "wrong # args" { perror "$test: wrong number args"; return 0 }
         timeout { fail "$test: timeout"; return 0 }
         eof { fail "$test: eof"; api_exit; lib_start_api; return 0 }
     }
@@ -52,7 +52,7 @@ proc tcl_cmd {command} {
     send "[string trim $command]\n"
     expect {
        -re "$prompt$" { return 1}
-       "wrong # args" { error "$test: wrong number args"; return 0 }
+       "wrong # args" { perror "$test: wrong number args"; return 0 }
        timeout { error_and_restart "timeout" }
        eof { api_exit; lib_start_api; return 0 }
     }
@@ -69,7 +69,7 @@ proc one_line_succeed_test {command} {
        -re "ERROR .*$prompt$" { 
                fail "$test: $expect_out(buffer)"; return 0
        }
-       "wrong # args" { error "$test: wrong number args"; return 0 }
+       "wrong # args" { perror "$test: wrong number args"; return 0 }
        timeout                         { fail "$test: timeout"; return 0 }
        eof                             { fail "$test: eof"; api_exit; lib_start_api; return 0 }
     }
@@ -85,7 +85,7 @@ proc one_line_fail_test {command code} {
        -re "ERROR .*$code.*$prompt$"   { pass "$test"; return 1 }
        -re "ERROR .*$prompt$"  { fail "$test: bad failure"; return 0 }
        -re "OK .*$prompt$"             { fail "$test: bad success"; return 0 }
-       "wrong # args" { error "$test: wrong number args"; return 0 }
+       "wrong # args" { perror "$test: wrong number args"; return 0 }
        timeout                         { fail "$test: timeout"; return 0 }
        eof                             { fail "$test: eof"; api_exit; lib_start_api; return 0 }
     }
@@ -100,7 +100,7 @@ proc one_line_fail_test_nochk {command} {
     expect {
        -re "ERROR .*$prompt$"  { pass "$test:"; return 1 }
        -re "OK .*$prompt$"             { fail "$test: bad success"; return 0 }
-       "wrong # args" { error "$test: wrong number args"; return 0 }
+       "wrong # args" { perror "$test: wrong number args"; return 0 }
        timeout                         { fail "$test: timeout"; return 0 }
        eof                             { fail "$test: eof"; api_exit; lib_start_api; return 0 }
     }
@@ -111,7 +111,7 @@ proc resync {} {
 
     expect {
        -re "$prompt$"  {}
-       "wrong # args" { error "$test: wrong number args"; return 0 }
+       "wrong # args" { perror "$test: wrong number args"; return 0 }
        eof { api_exit; lib_start_api }
     }
 }
@@ -173,7 +173,8 @@ proc principal_exists {name} {
     lib_start_api
 
     set ret [cmd [format {
-       kadm5_get_principal $lib_handle "%s" principal
+       kadm5_get_principal $lib_handle "%s" principal \
+         KADM5_PRINCIPAL_NORMAL_MASK
     } $name]]
 
 #   puts stdout "Finishing principal_exists."
@@ -246,7 +247,7 @@ proc kinit { princ pass {opts ""} } {
        # the parent, which is us, to read pending data.
 
        expect {
-               "when initializing cache" { error "kinit failed: $expect_out(buffer)" }
+               "when initializing cache" { perror "kinit failed: $expect_out(buffer)" }
                eof {}
        }
        wait
@@ -282,20 +283,20 @@ proc create_principal_with_keysalts {name keysalts} {
     spawn $kadmin_local -e "$keysalts"
     expect {
        "kadmin.local:" {}
-       default { error "waiting for kadmin.local prompt"; return 1}
+       default { perror "waiting for kadmin.local prompt"; return 1}
     }
     send "ank -pw \"$name\" \"$name\"\n"
     expect {
        -re "Principal \"$name.*\" created." {}
        "kadmin.local:" {
-           error "expecting principal created message"; 
+           perror "expecting principal created message"; 
            return 1
        }
-       default { error "waiting for principal created message"; return 1 }
+       default { perror "waiting for principal created message"; return 1 }
     }
     expect {
        "kadmin.local:" {}
-       default { error "waiting for kadmin.local prompt"; return 1 }
+       default { perror "waiting for kadmin.local prompt"; return 1 }
     }
     close
     wait
index a232ffcf65ecb407823d119dda924265662c2c5a..91dfd90d22833bdc59cf8b7e98184b09238bf7eb 100644 (file)
@@ -1616,6 +1616,47 @@ error_out:
     return retval;
 }
 
+asn1_error_code asn1_decode_s4u_userid(asn1buf *buf, krb5_s4u_userid *val)
+{
+    setup();
+    val->nonce = 0;
+    val->user = NULL;
+    val->subject_cert.data = NULL;
+    val->options = 0;
+    { begin_structure();
+        get_field(val->nonce,0,asn1_decode_int32);
+        alloc_principal(val->user);
+        opt_field(val->user,1,asn1_decode_principal_name,0);
+        get_field(val->user,2,asn1_decode_realm);
+        opt_lenfield(val->subject_cert.length,val->subject_cert.data,3,asn1_decode_charstring);
+        opt_field(val->options,4,asn1_decode_krb5_flags,0);
+        end_structure();
+    }
+    return 0;
+error_out:
+    krb5_free_principal(NULL, val->user);
+    krb5_free_data_contents(NULL, &val->subject_cert);
+    val->user = NULL;
+    val->subject_cert.data = NULL;
+    return retval;
+}
+
+asn1_error_code asn1_decode_pa_s4u_x509_user(asn1buf *buf, krb5_pa_s4u_x509_user *val)
+{
+    setup();
+    val->cksum.contents = NULL;
+    { begin_structure();
+        get_field(val->user_id,0,asn1_decode_s4u_userid);
+        get_field(val->cksum,1,asn1_decode_checksum);
+        end_structure();
+    }
+    return 0;
+error_out:
+    krb5_free_s4u_userid_contents(NULL, &val->user_id);
+    krb5_free_checksum_contents(NULL, &val->cksum);
+    return retval;
+}
+
 asn1_error_code asn1_decode_pa_pac_req(asn1buf *buf, krb5_pa_pac_req *val)
 {
     setup();
index 0532ad46770ec35f721f5e6d74e6b3f1f386a13e..f0d99dcc0d91f5579b764eba57dc3b8d583b9231 100644 (file)
@@ -263,6 +263,10 @@ asn1_error_code asn1_decode_setpw_req
         (asn1buf *buf, krb5_data *rep, krb5_principal *principal);
 asn1_error_code asn1_decode_pa_for_user
         (asn1buf *buf, krb5_pa_for_user *val);
+asn1_error_code asn1_decode_s4u_userid
+        (asn1buf *buf, krb5_s4u_userid *val);
+asn1_error_code asn1_decode_pa_s4u_x509_user
+        (asn1buf *buf, krb5_pa_s4u_x509_user *val);
 asn1_error_code asn1_decode_pa_pac_req
         (asn1buf *buf, krb5_pa_pac_req *val);
 
index f53ac7cd7d8e2be9580e70c7c6e60713ef124af6..1e9f11fe8cc2a1e76718190b659d069470d5ff37 100644 (file)
@@ -263,6 +263,8 @@ static unsigned int optional_enc_kdc_rep_part(const void *p)
         optional |= (1u << 8);
     if (val->caddrs != NULL && val->caddrs[0] != NULL)
         optional |= (1u << 11);
+    if (val->enc_padata != NULL)
+        optional |= (1u << 12);
 
     return optional;
 }
@@ -1147,6 +1149,36 @@ static const struct field_info pa_for_user_fields[] = {
 
 DEFSEQTYPE(pa_for_user, krb5_pa_for_user, pa_for_user_fields, 0);
 
+/* [MS-SFU] Section 2.2.2. */
+static const struct field_info s4u_userid_fields[] = {
+    FIELDOF_NORM(krb5_s4u_userid, int32, nonce, 0),
+    FIELDOF_OPT(krb5_s4u_userid, principal, user, 1, 1),
+    FIELDOF_NORM(krb5_s4u_userid, realm_of_principal, user, 2),
+    FIELDOF_OPT(krb5_s4u_userid, ostring_data, subject_cert, 3, 3),
+    FIELDOF_OPT(krb5_s4u_userid, krb5_flags, options, 4, 4),
+};
+
+static unsigned int s4u_userid_optional (const void *p) {
+    const krb5_s4u_userid *val = p;
+    unsigned int optional = 0;
+    if (val->user != NULL && val->user->length != 0)
+        optional |= (1u)<<1;
+    if (val->subject_cert.length != 0)
+        optional |= (1u)<<3;
+    if (val->options != 0)
+        optional |= (1u)<<4;
+    return optional;
+}
+
+DEFSEQTYPE(s4u_userid, krb5_s4u_userid, s4u_userid_fields, s4u_userid_optional);
+
+static const struct field_info pa_s4u_x509_user_fields[] = {
+    FIELDOF_NORM(krb5_pa_s4u_x509_user, s4u_userid, user_id, 0),
+    FIELDOF_NORM(krb5_pa_s4u_x509_user, checksum, cksum, 1),
+};
+
+DEFSEQTYPE(pa_s4u_x509_user, krb5_pa_s4u_x509_user, pa_s4u_x509_user_fields, 0);
+
 /* draft-ietf-krb-wg-kerberos-referrals Appendix A. */
 static const struct field_info pa_svr_referral_data_fields[] = {
     FIELDOF_NORM(krb5_pa_svr_referral_data, realm_of_principal, principal, 0),
@@ -1340,6 +1372,8 @@ MAKE_FULL_ENCODER(encode_krb5_predicted_sam_response,
                   predicted_sam_response);
 MAKE_FULL_ENCODER(encode_krb5_setpw_req, setpw_req);
 MAKE_FULL_ENCODER(encode_krb5_pa_for_user, pa_for_user);
+MAKE_FULL_ENCODER(encode_krb5_s4u_userid, s4u_userid);
+MAKE_FULL_ENCODER(encode_krb5_pa_s4u_x509_user, pa_s4u_x509_user);
 MAKE_FULL_ENCODER(encode_krb5_pa_svr_referral_data, pa_svr_referral_data);
 MAKE_FULL_ENCODER(encode_krb5_pa_server_referral_data, pa_server_referral_data);
 MAKE_FULL_ENCODER(encode_krb5_etype_list, etype_list);
index e5df1428c3356267efbec950807b9bf1d8e23a43..215608d33aea4aff94d4e45a0b634f3daf279f0d 100644 (file)
@@ -1060,6 +1060,18 @@ decode_krb5_pa_for_user(const krb5_data *code, krb5_pa_for_user **repptr)
     cleanup(free);
 }
 
+krb5_error_code
+decode_krb5_pa_s4u_x509_user(const krb5_data *code, krb5_pa_s4u_x509_user **repptr)
+{
+    setup_buf_only(krb5_pa_s4u_x509_user *);
+    alloc_field(rep);
+
+    retval = asn1_decode_pa_s4u_x509_user(&buf, rep);
+    if (retval) clean_return(retval);
+
+    cleanup(free);
+}
+
 krb5_error_code
 decode_krb5_pa_pac_req(const krb5_data *code, krb5_pa_pac_req **repptr)
 {
index ca4edd893f26b61f9ba277e10a71910487a8c495..44cce52f0e62e007c166d7109589730f4cf25230 100644 (file)
@@ -80,6 +80,7 @@ STLIBOBJS= \
        rd_req_dec.o    \
        rd_safe.o       \
        recvauth.o      \
+       s4u_creds.o     \
        sendauth.o      \
        send_tgs.o      \
        ser_actx.o      \
@@ -169,6 +170,7 @@ OBJS=       $(OUTPRE)addr_comp.$(OBJEXT)    \
        $(OUTPRE)rd_req_dec.$(OBJEXT)   \
        $(OUTPRE)rd_safe.$(OBJEXT)      \
        $(OUTPRE)recvauth.$(OBJEXT)     \
+       $(OUTPRE)s4u_creds.$(OBJEXT)    \
        $(OUTPRE)sendauth.$(OBJEXT)     \
        $(OUTPRE)send_tgs.$(OBJEXT)     \
        $(OUTPRE)ser_actx.$(OBJEXT)     \
@@ -259,6 +261,7 @@ SRCS=       $(srcdir)/addr_comp.c   \
        $(srcdir)/rd_req_dec.c  \
        $(srcdir)/rd_safe.c     \
        $(srcdir)/recvauth.c    \
+       $(srcdir)/s4u_creds.c   \
        $(srcdir)/sendauth.c    \
        $(srcdir)/send_tgs.c    \
        $(srcdir)/ser_actx.c    \
index 6e4a8b4cc1c8dc595cf18b37d3edf7c73ced0930..4102dd728df67c85b761129342f7bfc10bb2adfb 100644 (file)
@@ -1018,6 +1018,11 @@ krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache,
 
     DUMP_PRINC("gc_from_kdc: server as requested", supplied_server);
 
+    if (in_cred->second_ticket.length != 0 &&
+       (kdcopt & KDC_OPT_CNAME_IN_ADDL_TKT) == 0) {
+       kdcopt |= KDC_OPT_ENC_TKT_IN_SKEY;
+    }
+
     /*
      * Try requesting a service ticket from our local KDC with referrals
      * turned on.  If the first referral succeeds, follow a referral-only
@@ -1039,9 +1044,7 @@ krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache,
         retval = krb5_get_cred_via_tkt(context, tgtptr,
                                       KDC_OPT_CANONICALIZE | 
                                       FLAGS2OPTS(tgtptr->ticket_flags) |  
-                                      kdcopt |
-                                      (in_cred->second_ticket.length ?
-                                       KDC_OPT_ENC_TKT_IN_SKEY : 0),
+                                      kdcopt,
                                       tgtptr->addresses, in_cred, out_cred);
        if (retval) {
            DPRINTF(("gc_from_kdc: referral TGS-REQ request failed: <%s>\n",
@@ -1059,9 +1062,7 @@ krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache,
                     "retrying without option.\n", referral_count + 1));
            retval = krb5_get_cred_via_tkt(context, tgtptr,
                                           FLAGS2OPTS(tgtptr->ticket_flags) |  
-                                          kdcopt |
-                                          (in_cred->second_ticket.length ?
-                                           KDC_OPT_ENC_TKT_IN_SKEY : 0),
+                                          kdcopt,
                                           tgtptr->addresses,
                                           in_cred, out_cred);
            /* Whether or not that succeeded, we're done. */
@@ -1101,9 +1102,7 @@ krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache,
            retval = krb5_get_cred_via_tkt(context, tgtptr,
                                           KDC_OPT_CANONICALIZE | 
                                           FLAGS2OPTS(tgtptr->ticket_flags) |  
-                                          kdcopt |
-                                          (in_cred->second_ticket.length ?
-                                           KDC_OPT_ENC_TKT_IN_SKEY : 0),
+                                          kdcopt,
                                           tgtptr->addresses,
                                           in_cred, out_cred);
            goto cleanup;
@@ -1278,9 +1277,7 @@ krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache,
     context->use_conf_ktypes = old_use_conf_ktypes;
     retval = krb5_get_cred_via_tkt(context, tgtptr,
                                   FLAGS2OPTS(tgtptr->ticket_flags) |
-                                  kdcopt |
-                                  (in_cred->second_ticket.length ?
-                                   KDC_OPT_ENC_TKT_IN_SKEY : 0),
+                                  kdcopt,
                                   tgtptr->addresses, in_cred, out_cred);
 
 cleanup:
index 83c8026fcdafb181a207cdf17f86ce1aaa5043f8..273655ab5d03164ed7766665c7556b935345edbf 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * lib/krb5/krb/gc_via_tgt.c
  *
- * Copyright 1990,1991,2007,2008 by the Massachusetts Institute of Technology.
+ * Copyright 1990,1991,2007-2009 by the Massachusetts Institute of Technology.
  * All Rights Reserved.
  *
  * Export of this software from the United States of America may
@@ -158,6 +158,27 @@ krb5_error_code
 krb5_get_cred_via_tkt (krb5_context context, krb5_creds *tkt,
                       krb5_flags kdcoptions, krb5_address *const *address,
                       krb5_creds *in_cred, krb5_creds **out_cred)
+{
+    return krb5_get_cred_via_tkt_ext (context, tkt,
+                                     kdcoptions, address,
+                                     NULL, in_cred, NULL, NULL,
+                                     NULL, NULL, out_cred, NULL);
+}
+
+krb5_error_code
+krb5_get_cred_via_tkt_ext (krb5_context context, krb5_creds *tkt,
+                          krb5_flags kdcoptions, krb5_address *const *address,
+                          krb5_pa_data **in_padata,
+                          krb5_creds *in_cred,
+                          krb5_error_code (*pacb_fct)(krb5_context,
+                                                      krb5_keyblock *,
+                                                      krb5_kdc_req *,
+                                                      void *),
+                          void *pacb_data,
+                          krb5_pa_data ***out_padata,
+                          krb5_pa_data ***out_enc_padata,
+                          krb5_creds **out_cred,
+                          krb5_keyblock **out_subkey)
 {
     krb5_error_code retval;
     krb5_kdc_rep *dec_rep;
@@ -165,6 +186,7 @@ krb5_get_cred_via_tkt (krb5_context context, krb5_creds *tkt,
     krb5_response tgsrep;
     krb5_enctype *enctypes = 0;
     krb5_keyblock *subkey = NULL;
+    krb5_boolean s4u2self = FALSE, second_tkt;
 
 #ifdef DEBUG_REFERRALS
     printf("krb5_get_cred_via_tkt starting; referral flag is %s\n", kdcoptions&KDC_OPT_CANONICALIZE?"on":"off");
@@ -179,10 +201,13 @@ krb5_get_cred_via_tkt (krb5_context context, krb5_creds *tkt,
     if (!tkt->ticket.length)
        return KRB5_NO_TKT_SUPPLIED;
 
-    if ((kdcoptions & KDC_OPT_ENC_TKT_IN_SKEY) && 
-       (!in_cred->second_ticket.length))
+    second_tkt = ((kdcoptions & (KDC_OPT_ENC_TKT_IN_SKEY | KDC_OPT_CNAME_IN_ADDL_TKT)) != 0);
+
+    if (second_tkt && !in_cred->second_ticket.length)
         return(KRB5_NO_2ND_TKT);
 
+    s4u2self = krb5int_find_pa_data(context, in_padata, KRB5_PADATA_S4U_X509_USER) ||
+              krb5int_find_pa_data(context, in_padata, KRB5_PADATA_FOR_USER);
 
     /* check if we have the right TGT                    */
     /* tkt->server must be equal to                      */
@@ -210,13 +235,12 @@ krb5_get_cred_via_tkt (krb5_context context, krb5_creds *tkt,
        enctypes[0] = in_cred->keyblock.enctype;
        enctypes[1] = 0;
     }
-    
+
     retval = krb5int_send_tgs(context, kdcoptions, &in_cred->times, enctypes, 
                           in_cred->server, address, in_cred->authdata,
-                          0,           /* no padata */
-                          (kdcoptions & KDC_OPT_ENC_TKT_IN_SKEY) ? 
-                          &in_cred->second_ticket : NULL,
-                          tkt, &tgsrep, &subkey);
+                          in_padata,
+                          second_tkt ? &in_cred->second_ticket : NULL,
+                          tkt, pacb_fct, pacb_data, &tgsrep, &subkey);
     if (enctypes)
        free(enctypes);
     if (retval) {
@@ -318,8 +342,17 @@ krb5_get_cred_via_tkt (krb5_context context, krb5_creds *tkt,
     /* make sure the response hasn't been tampered with..... */
     retval = 0;
 
-    if (!krb5_principal_compare(context, dec_rep->client, tkt->client))
-       retval = KRB5_KDCREP_MODIFIED;
+    if (s4u2self && !IS_TGS_PRINC(context, dec_rep->ticket->server)) {
+       /* Final hop, check whether KDC supports S4U2Self */
+       if (krb5_principal_compare(context, dec_rep->client, in_cred->server))
+           retval = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
+    } else if ((kdcoptions & KDC_OPT_CNAME_IN_ADDL_TKT) == 0) {
+       /* XXX for constrained delegation this check must be performed by caller
+        * as we don't have access to the key to decrypt the evidence ticket.
+        */
+       if (!krb5_principal_compare(context, dec_rep->client, tkt->client))
+           retval = KRB5_KDCREP_MODIFIED;
+    }
 
     if (retval == 0)
        retval = check_reply_server(context, kdcoptions, in_cred, dec_rep);
@@ -356,13 +389,26 @@ krb5_get_cred_via_tkt (krb5_context context, krb5_creds *tkt,
        retval = KRB5_KDCREP_SKEW;
        goto error_3;
     }
+
+    if (out_padata != NULL) {
+       *out_padata = dec_rep->padata;
+       dec_rep->padata = NULL;
+    }
+    if (out_enc_padata != NULL) {
+       *out_enc_padata = dec_rep->enc_part2->enc_padata;
+       dec_rep->enc_part2->enc_padata = NULL;
+    }
     
     retval = krb5_kdcrep2creds(context, dec_rep, address, 
                               &in_cred->second_ticket,  out_cred);
 
 error_3:;
-    if (subkey != NULL)
-      krb5_free_keyblock(context, subkey);
+    if (subkey != NULL) {
+      if (retval == 0 && out_subkey != NULL)
+         *out_subkey = subkey;
+      else
+         krb5_free_keyblock(context, subkey);
+    }
     
     memset(dec_rep->enc_part2->session->contents, 0,
           dec_rep->enc_part2->session->length);
index c02ddedc6bc73f4aefb06a9f8d2724a0eb6bc948..dad3e1a9175de6c80cac15654da987a1327288ec 100644 (file)
@@ -46,7 +46,7 @@
 #include "k5-int.h"
 #include "int-proto.h"
 
-static krb5_error_code
+krb5_error_code
 krb5_get_credentials_core(krb5_context context, krb5_flags options,
                          krb5_creds *in_creds, krb5_creds *mcreds,
                          krb5_flags *fields)
@@ -87,11 +87,14 @@ krb5_get_credentials_core(krb5_context context, krb5_flags options,
        if (ret)
            return ret;
     }
-    if (options & KRB5_GC_USER_USER) {
+    if (options & (KRB5_GC_USER_USER | KRB5_GC_CONSTRAINED_DELEGATION)) {
        /* also match on identical 2nd tkt and tkt encrypted in a
           session key */
-       *fields |= KRB5_TC_MATCH_2ND_TKT|KRB5_TC_MATCH_IS_SKEY;
-       mcreds->is_skey = TRUE;
+       *fields |= KRB5_TC_MATCH_2ND_TKT;
+       if (options & KRB5_GC_USER_USER) {
+           *fields |= KRB5_TC_MATCH_IS_SKEY;
+           mcreds->is_skey = TRUE;
+       }
        mcreds->second_ticket = in_creds->second_ticket;
        if (!in_creds->second_ticket.length)
            return KRB5_NO_2ND_TKT;
@@ -113,25 +116,35 @@ krb5_get_credentials(krb5_context context, krb5_flags options,
     int not_ktype;
     int kdcopt = 0;
 
-    retval = krb5_get_credentials_core(context, options,
-                                      in_creds,
-                                      &mcreds, &fields);
+    if ((options & KRB5_GC_CONSTRAINED_DELEGATION) == 0) {
+       retval = krb5_get_credentials_core(context, options,
+                                          in_creds,
+                                          &mcreds, &fields);
 
-    if (retval) return retval;
+       if (retval)
+           return retval;
 
-    if ((ncreds = (krb5_creds *)malloc(sizeof(krb5_creds))) == NULL)
-       return ENOMEM;
+       if ((ncreds = (krb5_creds *)malloc(sizeof(krb5_creds))) == NULL)
+           return ENOMEM;
 
-    memset(ncreds, 0, sizeof(krb5_creds));
-    ncreds->magic = KV5M_CREDS;
+       memset(ncreds, 0, sizeof(krb5_creds));
+       ncreds->magic = KV5M_CREDS;
 
-    /* The caller is now responsible for cleaning up in_creds */
-    if ((retval = krb5_cc_retrieve_cred(context, ccache, fields, &mcreds,
-                                       ncreds))) {
-       free(ncreds);
-       ncreds = in_creds;
+       /* The caller is now responsible for cleaning up in_creds */
+       if ((retval = krb5_cc_retrieve_cred(context, ccache, fields, &mcreds,
+                                           ncreds))) {
+           free(ncreds);
+           ncreds = in_creds;
+       } else {
+           *out_creds = ncreds;
+       }
     } else {
-       *out_creds = ncreds;
+       /*
+        * To do this usefully for constrained delegation, we would
+        * need to look inside second_ticket, which we can't do.
+        */
+       ncreds = in_creds;
+       retval = KRB5_CC_NOTFOUND;
     }
 
     if ((retval != KRB5_CC_NOTFOUND && retval != KRB5_CC_NOT_KTYPE)
@@ -145,6 +158,15 @@ krb5_get_credentials(krb5_context context, krb5_flags options,
 
     if (options & KRB5_GC_CANONICALIZE)
        kdcopt |= KDC_OPT_CANONICALIZE;
+    if (options & KRB5_GC_FORWARDABLE)
+       kdcopt |= KDC_OPT_FORWARDABLE;
+    if (options & KRB5_GC_NO_TRANSIT_CHECK)
+       kdcopt |= KDC_OPT_DISABLE_TRANSITED_CHECK;
+    if (options & KRB5_GC_CONSTRAINED_DELEGATION) {
+       if (options & KRB5_GC_USER_USER)
+           return EINVAL;
+       kdcopt |= KDC_OPT_FORWARDABLE | KDC_OPT_CNAME_IN_ADDL_TKT;
+    }
 
     retval = krb5_get_cred_from_kdc_opt(context, ccache, ncreds,
                                        out_creds, &tgts, kdcopt);
@@ -160,6 +182,13 @@ krb5_get_credentials(krb5_context context, krb5_flags options,
        }
        krb5_free_tgt_creds(context, tgts);
     }
+    if (!retval && (options & KRB5_GC_CONSTRAINED_DELEGATION)) {
+       if (((*out_creds)->ticket_flags & TKT_FLG_FORWARDABLE) == 0) {
+           retval = KRB5_TKT_NOT_FORWARDABLE;
+           krb5_free_creds(context, *out_creds);
+           *out_creds = NULL;
+       }
+    }
     /*
      * Translate KRB5_CC_NOTFOUND if we previously got
      * KRB5_CC_NOT_KTYPE from krb5_cc_retrieve_cred(), in order to
@@ -175,7 +204,7 @@ krb5_get_credentials(krb5_context context, krb5_flags options,
        && not_ktype)
        retval = KRB5_CC_NOT_KTYPE;
 
-    if (!retval) {
+    if (!retval && (options & KRB5_GC_NO_STORE) == 0) {
         /* the purpose of the krb5_get_credentials call is to 
          * obtain a set of credentials for the caller.  the 
          * krb5_cc_store_cred() call is to optimize performance
@@ -184,6 +213,7 @@ krb5_get_credentials(krb5_context context, krb5_flags options,
          */
        krb5_cc_store_cred(context, ccache, *out_creds);
     }
+
     return retval;
 }
 
@@ -337,3 +367,4 @@ krb5_get_renewed_creds(krb5_context context, krb5_creds *creds, krb5_principal c
     return(krb5_validate_or_renew_creds(context, creds, client, ccache,
                                        in_tkt_service, 0));
 }
+
index 018676dbee8d80f194015ac99f072e2951d6d3c6..63594ddfd5b4e8b39e8788addb8973499b87e8aa 100644 (file)
@@ -493,6 +493,55 @@ static const krb5_enctype get_in_tkt_enctypes[] = {
     0
 };
 
+static krb5_error_code
+rewrite_server_realm(krb5_context context,
+                    krb5_const_principal old_server,
+                    const krb5_data *realm,
+                    krb5_boolean tgs,
+                    krb5_principal *server)
+{
+    krb5_error_code retval;
+
+    assert(*server == NULL);
+
+    retval = krb5_copy_principal(context, old_server, server);
+    if (retval)
+       return retval;
+
+    krb5_free_data_contents(context, &(*server)->realm);
+    (*server)->realm.data = NULL;
+
+    retval = krb5int_copy_data_contents(context, realm, &(*server)->realm);
+    if (retval)
+       goto cleanup;
+
+    if (tgs) {
+       krb5_free_data_contents(context, &(*server)->data[1]);
+       (*server)->data[1].data = NULL;
+
+       retval = krb5int_copy_data_contents(context, realm, &(*server)->data[1]);
+       if (retval)
+           goto cleanup;
+    }
+
+cleanup:
+    if (retval) {
+       krb5_free_principal(context, *server);
+       *server = NULL;
+    }
+
+    return retval;
+}
+
+static inline int
+tgt_is_local_realm(krb5_creds *tgt)
+{
+    return (tgt->server->length == 2
+            && data_eq_string(tgt->server->data[0], KRB5_TGS_NAME)
+            && data_eq(tgt->server->data[1], tgt->client->realm)
+            && data_eq(tgt->server->realm, tgt->client->realm));
+}
+
 krb5_error_code KRB5_CALLCONV
 krb5_get_in_tkt(krb5_context context,
                krb5_flags options,
@@ -521,6 +570,8 @@ krb5_get_in_tkt(krb5_context context,
     int             use_master = 0;
     int                        referral_count = 0;
     krb5_principal_data        referred_client;
+    krb5_principal     referred_server = NULL;
+    krb5_boolean       is_tgt_req;
 
 #if APPLE_PKINIT
     inTktDebug("krb5_get_in_tkt top\n");
@@ -616,6 +667,8 @@ krb5_get_in_tkt(krb5_context context,
            goto cleanup;
     }
            
+    is_tgt_req = tgt_is_local_realm(creds);
+
     while (1) {
        if (loopcount++ > MAX_IN_TKT_LOOPS) {
            retval = KRB5_GET_IN_TKT_LOOP;
@@ -687,6 +740,21 @@ krb5_get_in_tkt(krb5_context context,
                if (retval)
                    goto cleanup;
                request.client = &referred_client;
+
+               if (referred_server != NULL) {
+                   krb5_free_principal(context, referred_server);
+                   referred_server = NULL;
+               }
+
+               retval = rewrite_server_realm(context,
+                                             creds->server,
+                                             &referred_client.realm,
+                                             is_tgt_req,
+                                             &referred_server);
+               if (retval)
+                   goto cleanup;
+               request.server = referred_server;
+
                continue;
            } else {
                retval = (krb5_error_code) err_reply->error 
@@ -739,6 +807,8 @@ cleanup:
     }
     if (referred_client.realm.data)
        krb5_free_data_contents(context, &referred_client.realm);
+    if (referred_server)
+       krb5_free_principal(context, referred_server);
     return (retval);
 }
 
@@ -939,6 +1009,52 @@ sort_krb5_padata_sequence(krb5_context context, krb5_data *realm,
     return 0;
 }
 
+static krb5_error_code
+build_in_tkt_name(krb5_context context,
+                 char *in_tkt_service,
+                 krb5_const_principal client,
+                 krb5_principal *server)
+{
+    krb5_error_code ret;
+
+    *server = NULL;
+
+    if (in_tkt_service) {
+       /* this is ugly, because so are the data structures involved.  I'm
+          in the library, so I'm going to manipulate the data structures
+          directly, otherwise, it will be worse. */
+
+        if ((ret = krb5_parse_name(context, in_tkt_service, server)))
+           return ret;
+
+       /* stuff the client realm into the server principal.
+          realloc if necessary */
+       if ((*server)->realm.length < client->realm.length) {
+           char *p = realloc((*server)->realm.data,
+                             client->realm.length);
+           if (p == NULL) {
+               krb5_free_principal(context, *server);
+               *server = NULL;
+               return ENOMEM;
+           }
+           (*server)->realm.data = p;
+       }
+
+       (*server)->realm.length = client->realm.length;
+       memcpy((*server)->realm.data, client->realm.data, client->realm.length);
+    } else {
+       ret = krb5_build_principal_ext(context, server,
+                                      client->realm.length,
+                                      client->realm.data,
+                                      KRB5_TGS_NAME_SIZE,
+                                      KRB5_TGS_NAME,
+                                      client->realm.length,
+                                      client->realm.data,
+                                      0);
+    }
+    return ret;
+}
+
 krb5_error_code KRB5_CALLCONV
 krb5_get_init_creds(krb5_context context,
                    krb5_creds *creds,
@@ -1125,41 +1241,9 @@ krb5_get_init_creds(krb5_context context,
        client->type == KRB5_NT_ENTERPRISE_PRINCIPAL;
 
     /* service */
-    
-    if (in_tkt_service) {
-       /* this is ugly, because so are the data structures involved.  I'm
-          in the library, so I'm going to manipulate the data structures
-          directly, otherwise, it will be worse. */
-
-        if ((ret = krb5_parse_name(context, in_tkt_service, &request.server)))
-           goto cleanup;
-
-       /* stuff the client realm into the server principal.
-          realloc if necessary */
-       if (request.server->realm.length < request.client->realm.length) {
-           char *p = realloc(request.server->realm.data,
-                             request.client->realm.length);
-           if (p == NULL) {
-               ret = ENOMEM;
-               goto cleanup;
-           }
-           request.server->realm.data = p;
-       }
-
-       request.server->realm.length = request.client->realm.length;
-       memcpy(request.server->realm.data, request.client->realm.data,
-              request.client->realm.length);
-    } else {
-       if ((ret = krb5_build_principal_ext(context, &request.server,
-                                          request.client->realm.length,
-                                          request.client->realm.data,
-                                          KRB5_TGS_NAME_SIZE,
-                                          KRB5_TGS_NAME,
-                                          request.client->realm.length,
-                                          request.client->realm.data,
-                                          0)))
-           goto cleanup;
-    }
+    if ((ret = build_in_tkt_name(context, in_tkt_service,
+                                request.client, &request.server)))
+       goto cleanup;
 
     krb5_preauth_request_context_init(context);
 
@@ -1337,8 +1421,10 @@ krb5_get_init_creds(krb5_context context,
                }
                preauth_to_use = out_padata;
                out_padata = NULL;
-               krb5_free_error(context, err_reply);
-               err_reply = NULL;
+               if (err_reply->error == KDC_ERR_PREAUTH_REQUIRED) {
+                   krb5_free_error(context, err_reply);
+                   err_reply = NULL;
+               }
                ret = sort_krb5_padata_sequence(context,
                                                &request.server->realm,
                                                preauth_to_use);
@@ -1365,6 +1451,14 @@ krb5_get_init_creds(krb5_context context,
                if (ret)
                    goto cleanup;
                request.client = &referred_client;
+
+               krb5_free_principal(context, request.server);
+               request.server = NULL;
+
+               ret = build_in_tkt_name(context, in_tkt_service,
+                                       request.client, &request.server);
+               if (ret)
+                   goto cleanup;
            } else {
                if (retry)  {
                    /* continue to next iteration */
index b81fe2566bc50154e6b2274cbf57a16e236fa4ca..cc0c9f2de03f04ac292be5d5d5a34c62a4378f4f 100644 (file)
@@ -59,11 +59,31 @@ krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache,
                           krb5_creds *in_cred, krb5_creds **out_cred,
                           krb5_creds ***tgts, int kdcopt);
 
+krb5_error_code
+krb5_get_credentials_core(krb5_context context, krb5_flags options,
+                         krb5_creds *in_creds, krb5_creds *mcreds,
+                         krb5_flags *fields);
+
 #define in_clock_skew(date, now) (labs((date)-(now)) < context->clockskew)
 
 #define IS_TGS_PRINC(c, p)                                             \
     (krb5_princ_size((c), (p)) == 2 &&                                 \
      data_eq_string(*krb5_princ_component((c), (p), 0), KRB5_TGS_NAME))
 
+krb5_error_code
+krb5_get_cred_via_tkt_ext (krb5_context context, krb5_creds *tkt,
+                          krb5_flags kdcoptions, krb5_address *const *address,
+                          krb5_pa_data **in_padata,
+                          krb5_creds *in_cred,
+                          krb5_error_code (*gcvt_fct)(krb5_context,
+                                                      krb5_keyblock *,
+                                                      krb5_kdc_req *,
+                                                      void *),
+                          void *gcvt_data,
+                          krb5_pa_data ***out_padata,
+                          krb5_pa_data ***enc_padata,
+                          krb5_creds **out_cred,
+                          krb5_keyblock **out_subkey);
+
 #endif /* KRB5_INT_FUNC_PROTO__ */
 
index 49dec8b3f3bf8d46436d4e7c7ca33cbe1e1ad467..0995b302215040b5ab8535aa0297cda71272075e 100644 (file)
@@ -170,7 +170,7 @@ krb5_free_checksum_contents(krb5_context context, register krb5_checksum *val)
     if (val == NULL)
        return;
     free(val->contents);
-    val->contents = 0;
+    val->contents = NULL;
 }
 
 void KRB5_CALLCONV
@@ -297,6 +297,7 @@ krb5_free_enc_kdc_rep_part(krb5_context context, register krb5_enc_kdc_rep_part
     krb5_free_last_req(context, val->last_req);
     krb5_free_principal(context, val->server);
     krb5_free_addresses(context, val->caddrs);
+    krb5_free_pa_data(context, val->enc_padata);
     free(val);
 }
 
@@ -755,6 +756,30 @@ krb5_free_pa_for_user(krb5_context context, krb5_pa_for_user *req)
     free(req);
 }
 
+void KRB5_CALLCONV
+krb5_free_s4u_userid_contents(krb5_context context, krb5_s4u_userid *user_id)
+{
+    if (user_id == NULL)
+       return;
+    user_id->nonce = 0;
+    krb5_free_principal(context, user_id->user);
+    user_id->user = NULL;
+    krb5_free_data_contents(context, &user_id->subject_cert);
+    user_id->subject_cert.length = 0;
+    user_id->subject_cert.data = NULL;
+    user_id->options = 0;
+}
+
+void KRB5_CALLCONV
+krb5_free_pa_s4u_x509_user(krb5_context context, krb5_pa_s4u_x509_user *req)
+{
+    if (req == NULL)
+       return;
+    krb5_free_s4u_userid_contents(context, &req->user_id);
+    krb5_free_checksum_contents(context, &req->cksum);
+    free(req);
+}
+
 void KRB5_CALLCONV
 krb5_free_pa_server_referral_data(krb5_context context,
                                  krb5_pa_server_referral_data *ref)
index e6f4215d5c4d0502db51e6077591fc575eefbc3d..996cbfd364402977d81383b9e8683d32f61ae335 100644 (file)
@@ -1706,6 +1706,59 @@ krb5_error_code pa_sam_2(krb5_context context,
    return(0);
 }
 
+static krb5_error_code pa_s4u_x509_user(
+    krb5_context context,
+    krb5_kdc_req *request,
+    krb5_pa_data *in_padata,
+    krb5_pa_data **out_padata,
+    krb5_data *salt,
+    krb5_data *s2kparams,
+    krb5_enctype *etype,
+    krb5_keyblock *as_key,
+    krb5_prompter_fct prompter,
+    void *prompter_data,
+    krb5_gic_get_as_key_fct gak_fct,
+    void *gak_data)
+{
+    krb5_s4u_userid *userid = (krb5_s4u_userid *)gak_data; /* XXX private contract */
+    krb5_pa_data *s4u_padata;
+    krb5_error_code code;
+    krb5_principal client;
+
+    *out_padata = NULL;
+
+    if (userid == NULL)
+       return EINVAL;
+
+    code = krb5_copy_principal(context, request->client, &client);
+    if (code != 0)
+       return code;
+
+    if (userid->user != NULL)
+       krb5_free_principal(context, userid->user);
+    userid->user = client;
+
+    if (userid->subject_cert.length != 0) {
+       s4u_padata = malloc(sizeof(*s4u_padata));
+       if (s4u_padata == NULL)
+           return ENOMEM;
+
+       s4u_padata->magic = KV5M_PA_DATA;
+       s4u_padata->pa_type = KRB5_PADATA_S4U_X509_USER;
+       s4u_padata->contents = malloc(userid->subject_cert.length);
+       if (s4u_padata->contents == NULL) {
+           free(s4u_padata);
+           return ENOMEM;
+       }
+       memcpy(s4u_padata->contents, userid->subject_cert.data, userid->subject_cert.length);
+       s4u_padata->length = userid->subject_cert.length;
+
+       *out_padata = s4u_padata;
+    }
+
+    return 0;
+}
+
 /* FIXME - order significant? */
 static const pa_types_t pa_types[] = {
     {
@@ -1750,6 +1803,11 @@ static const pa_types_t pa_types[] = {
        pa_fx_cookie,
        PA_INFO,
     },
+    {
+       KRB5_PADATA_S4U_X509_USER,
+       pa_s4u_x509_user,
+       PA_INFO,
+    },
     {
        -1,
        NULL,
diff --git a/src/lib/krb5/krb/s4u_creds.c b/src/lib/krb5/krb/s4u_creds.c
new file mode 100644 (file)
index 0000000..613bbef
--- /dev/null
@@ -0,0 +1,829 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * lib/krb5/krb/s4u_creds.c
+ *
+ * Copyright (C) 2009 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"
+#include "int-proto.h"
+
+/* Convert ticket flags to necessary KDC options */
+#define FLAGS2OPTS(flags) (flags & KDC_TKT_COMMON_MASK)
+
+/*
+ * Implements S4U2Self, by which a service can request a ticket to
+ * itself on behalf of an arbitrary principal.
+ */
+
+static krb5_error_code
+krb5_get_as_key_noop(
+    krb5_context context,
+    krb5_principal client,
+    krb5_enctype etype,
+    krb5_prompter_fct prompter,
+    void *prompter_data,
+    krb5_data *salt,
+    krb5_data *params,
+    krb5_keyblock *as_key,
+    void *gak_data)
+{
+    /* force a hard error, we don't actually have the key */
+    return KDC_ERR_PREAUTH_FAILED;
+}
+
+static krb5_error_code
+s4u_identify_user(krb5_context context,
+                  krb5_creds *in_creds,
+                  krb5_data *subject_cert,
+                  krb5_principal *canon_user)
+{
+    krb5_error_code code;
+    krb5_preauthtype ptypes[1] = { KRB5_PADATA_S4U_X509_USER };
+    krb5_creds creds;
+    int use_master = 0;
+    krb5_get_init_creds_opt *opts = NULL;
+    krb5_gic_opt_ext *opte = NULL;
+    krb5_principal_data client_data;
+    krb5_principal client;
+    krb5_s4u_userid userid;
+
+    *canon_user = NULL;
+
+    if (in_creds->client == NULL && subject_cert == NULL) {
+        return EINVAL;
+    }
+
+    if (in_creds->client != NULL &&
+        krb5_princ_type(context, in_creds->client) !=
+            KRB5_NT_ENTERPRISE_PRINCIPAL)
+        /* we already know the realm of the user */
+        return krb5_copy_principal(context, in_creds->client, canon_user);
+
+    memset(&creds, 0, sizeof(creds));
+
+    memset(&userid, 0, sizeof(userid));
+    if (subject_cert != NULL)
+        userid.subject_cert = *subject_cert;
+
+    code = krb5_get_init_creds_opt_alloc(context, &opts);
+    if (code != 0)
+        goto cleanup;
+    krb5_get_init_creds_opt_set_tkt_life(opts, 15);
+    krb5_get_init_creds_opt_set_renew_life(opts, 0);
+    krb5_get_init_creds_opt_set_forwardable(opts, 0);
+    krb5_get_init_creds_opt_set_proxiable(opts, 0);
+    krb5_get_init_creds_opt_set_canonicalize(opts, 1);
+    krb5_get_init_creds_opt_set_preauth_list(opts, ptypes, 1);
+    code = krb5int_gic_opt_to_opte(context, opts, &opte,
+                                   0, "s4u_identify_user");
+    if (code != 0)
+        goto cleanup;
+
+    if (in_creds->client != NULL)
+        client = in_creds->client;
+    else {
+        client_data.magic = KV5M_PRINCIPAL;
+        client_data.realm = in_creds->server->realm;
+        /* should this be NULL, empty or a fixed string? XXX */
+        client_data.data = NULL;
+        client_data.length = 0;
+        client_data.type = KRB5_NT_ENTERPRISE_PRINCIPAL;
+        client = &client_data;
+    }
+
+    code = krb5_get_init_creds(context, &creds, in_creds->client,
+                               NULL, NULL, 0, NULL, opte,
+                               krb5_get_as_key_noop, &userid,
+                               &use_master, NULL);
+    if (code == 0 ||
+        code == KDC_ERR_PREAUTH_REQUIRED ||
+        code == KDC_ERR_PREAUTH_FAILED) {
+        *canon_user = userid.user;
+        userid.user = NULL;
+        code = 0;
+    }
+
+cleanup:
+    krb5_free_cred_contents(context, &creds);
+    if (opts != NULL)
+        krb5_get_init_creds_opt_free(context, opts);
+    if (userid.user != NULL)
+        krb5_free_principal(context, userid.user);
+
+    return code;
+}
+
+static krb5_error_code
+make_pa_for_user_checksum(krb5_context context,
+                          krb5_keyblock *key,
+                          krb5_pa_for_user *req,
+                          krb5_checksum *cksum)
+{
+    krb5_error_code code;
+    int i;
+    krb5_int32 name_type;
+    char *p;
+    krb5_data data;
+    krb5_cksumtype cksumtype;
+
+    data.length = 4;
+    for (i = 0; i < krb5_princ_size(context, req->user); i++) {
+        data.length += krb5_princ_component(context, req->user, i)->length;
+    }
+    data.length += krb5_princ_realm(context, req->user)->length;
+    data.length += req->auth_package.length;
+
+    p = data.data = malloc(data.length);
+    if (data.data == NULL)
+        return ENOMEM;
+
+    name_type = krb5_princ_type(context, req->user);
+    p[0] = (name_type >> 0 ) & 0xFF;
+    p[1] = (name_type >> 8 ) & 0xFF;
+    p[2] = (name_type >> 16) & 0xFF;
+    p[3] = (name_type >> 24) & 0xFF;
+    p += 4;
+
+    for (i = 0; i < krb5_princ_size(context, req->user); i++) {
+        memcpy(p, krb5_princ_component(context, req->user, i)->data,
+               krb5_princ_component(context, req->user, i)->length);
+        p += krb5_princ_component(context, req->user, i)->length;
+    }
+
+    memcpy(p, krb5_princ_realm(context, req->user)->data,
+           krb5_princ_realm(context, req->user)->length);
+    p += krb5_princ_realm(context, req->user)->length;
+
+    memcpy(p, req->auth_package.data, req->auth_package.length);
+
+    code = krb5int_c_mandatory_cksumtype(context, key->enctype, &cksumtype);
+    if (code != 0) {
+        free(data.data);
+        return code;
+    }
+
+    code = krb5_c_make_checksum(context, cksumtype, key,
+                                KRB5_KEYUSAGE_APP_DATA_CKSUM, &data,
+                                cksum);
+
+    free(data.data);
+
+    return code;
+}
+
+static krb5_error_code
+build_pa_for_user(krb5_context context,
+                  krb5_creds *tgt,
+                  krb5_s4u_userid *userid,
+                  krb5_pa_data **out_padata)
+{
+    krb5_error_code code;
+    krb5_pa_data *padata;
+    krb5_pa_for_user for_user;
+    krb5_data *for_user_data = NULL;
+    char package[] = "Kerberos";
+
+    if (userid->user == NULL) {
+        code = EINVAL;
+        goto cleanup;
+    }
+
+    memset(&for_user, 0, sizeof(for_user));
+    for_user.user = userid->user;
+    for_user.auth_package.data = package;
+    for_user.auth_package.length = sizeof(package) - 1;
+
+    code = make_pa_for_user_checksum(context, &tgt->keyblock,
+                                     &for_user, &for_user.cksum);
+    if (code != 0)
+        goto cleanup;
+
+    code = encode_krb5_pa_for_user(&for_user, &for_user_data);
+    if (code != 0)
+        goto cleanup;
+
+    padata = malloc(sizeof(*padata));
+    if (padata == NULL) {
+        code = ENOMEM;
+        goto cleanup;
+    }
+
+    padata->magic = KV5M_PA_DATA;
+    padata->pa_type = KRB5_PADATA_FOR_USER;
+    padata->length = for_user_data->length;
+    padata->contents = (krb5_octet *)for_user_data->data;
+
+    free(for_user_data);
+    for_user_data = NULL;
+
+    *out_padata = padata;
+
+cleanup:
+    if (for_user.cksum.contents != NULL)
+        krb5_free_checksum_contents(context, &for_user.cksum);
+    krb5_free_data(context, for_user_data);
+
+    return code;
+}
+
+/*
+ * This function is invoked by krb5int_send_tgs() just before
+ * the request is encoded; it gives us access to the nonce and
+ * subkey without requiring them to be generated by the caller.
+ */
+static krb5_error_code
+build_pa_s4u_x509_user(krb5_context context,
+                       krb5_keyblock *subkey,
+                       krb5_kdc_req *tgsreq,
+                       void *gcvt_data)
+{
+    krb5_error_code code;
+    krb5_pa_s4u_x509_user *s4u_user = (krb5_pa_s4u_x509_user *)gcvt_data;
+    krb5_data *data = NULL;
+    krb5_pa_data **padata;
+    krb5_cksumtype cksumtype;
+    int i;
+
+    assert(s4u_user->cksum.contents == NULL);
+
+    s4u_user->user_id.nonce = tgsreq->nonce;
+
+    code = encode_krb5_s4u_userid(&s4u_user->user_id, &data);
+    if (code != 0)
+        goto cleanup;
+
+    /* [MS-SFU] 2.2.2: unusual to say the least, but enc_padata secures it */
+    if (subkey->enctype == ENCTYPE_ARCFOUR_HMAC ||
+        subkey->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
+        cksumtype = CKSUMTYPE_RSA_MD4;
+    } else {
+        code = krb5int_c_mandatory_cksumtype(context, subkey->enctype,
+                                             &cksumtype);
+    }
+    if (code != 0)
+        goto cleanup;
+
+    code = krb5_c_make_checksum(context, cksumtype, subkey,
+                                KRB5_KEYUSAGE_PA_S4U_X509_USER_REQUEST, data,
+                                &s4u_user->cksum);
+    if (code != 0)
+        goto cleanup;
+
+    krb5_free_data(context, data);
+    data = NULL;
+
+    code = encode_krb5_pa_s4u_x509_user(s4u_user, &data);
+    if (code != 0)
+        goto cleanup;
+
+    assert(tgsreq->padata != NULL);
+
+    for (i = 0; tgsreq->padata[i] != NULL; i++)
+        ;
+
+    padata = realloc(tgsreq->padata,
+                     (i + 2) * sizeof(krb5_pa_data *));
+    if (padata == NULL) {
+        code = ENOMEM;
+        goto cleanup;
+    }
+    tgsreq->padata = padata;
+
+    padata[i] = malloc(sizeof(krb5_pa_data));
+    if (padata[i] == NULL) {
+        code = ENOMEM;
+        goto cleanup;
+    }
+    padata[i]->magic = KV5M_PA_DATA;
+    padata[i]->pa_type = KRB5_PADATA_S4U_X509_USER;
+    padata[i]->length = data->length;
+    padata[i]->contents = (krb5_octet *)data->data;
+
+    padata[i + 1] = NULL;
+
+    free(data);
+    data = NULL;
+
+cleanup:
+    if (code != 0 && s4u_user->cksum.contents != NULL) {
+        krb5_free_checksum_contents(context, &s4u_user->cksum);
+        s4u_user->cksum.contents = NULL;
+    }
+    krb5_free_data(context, data);
+
+    return code;
+}
+
+static krb5_error_code
+verify_s4u2self_reply(krb5_context context,
+                      krb5_keyblock *subkey,
+                      krb5_pa_s4u_x509_user *req_s4u_user,
+                      krb5_pa_data **rep_padata,
+                      krb5_pa_data **enc_padata)
+{
+    krb5_error_code code;
+    krb5_pa_data *rep_s4u_padata, *enc_s4u_padata;
+    krb5_pa_s4u_x509_user *rep_s4u_user = NULL;
+    krb5_data data, *datap = NULL;
+    krb5_keyusage usage;
+    krb5_boolean valid;
+    krb5_boolean not_newer;
+
+    assert(req_s4u_user != NULL);
+
+    switch (subkey->enctype) {
+    case ENCTYPE_DES_CBC_CRC:
+    case ENCTYPE_DES_CBC_MD4:
+    case ENCTYPE_DES_CBC_MD5:
+    case ENCTYPE_DES3_CBC_SHA1:
+    case ENCTYPE_DES3_CBC_RAW:
+    case ENCTYPE_ARCFOUR_HMAC:
+    case ENCTYPE_ARCFOUR_HMAC_EXP :
+        not_newer = TRUE;
+        break;
+    default:
+        not_newer = FALSE;
+        break;
+    }
+
+    enc_s4u_padata = krb5int_find_pa_data(context,
+                                          enc_padata,
+                                          KRB5_PADATA_S4U_X509_USER);
+
+    /* XXX this will break newer enctypes with a MIT 1.7 KDC */
+    rep_s4u_padata = krb5int_find_pa_data(context,
+                                          rep_padata,
+                                          KRB5_PADATA_S4U_X509_USER);
+    if (rep_s4u_padata == NULL) {
+        if (not_newer == FALSE || enc_s4u_padata != NULL)
+            return KRB5_KDCREP_MODIFIED;
+        else
+            return 0;
+    }
+
+    data.length = rep_s4u_padata->length;
+    data.data = (char *)rep_s4u_padata->contents;
+
+    code = decode_krb5_pa_s4u_x509_user(&data, &rep_s4u_user);
+    if (code != 0)
+        goto cleanup;
+
+    if (rep_s4u_user->user_id.nonce != req_s4u_user->user_id.nonce) {
+        code = KRB5_KDCREP_MODIFIED;
+        goto cleanup;
+    }
+
+    code = encode_krb5_s4u_userid(&rep_s4u_user->user_id, &datap);
+    if (code != 0)
+        goto cleanup;
+
+    if (rep_s4u_user->user_id.options & KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE)
+        usage = KRB5_KEYUSAGE_PA_S4U_X509_USER_REPLY;
+    else
+        usage = KRB5_KEYUSAGE_PA_S4U_X509_USER_REQUEST;
+
+    code = krb5_c_verify_checksum(context, subkey, usage, datap,
+                                  &rep_s4u_user->cksum, &valid);
+    if (code != 0)
+        goto cleanup;
+    if (valid == FALSE) {
+        code = KRB5_KDCREP_MODIFIED;
+        goto cleanup;
+    }
+
+    /*
+     * KDCs that support KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE also return
+     * S4U enc_padata for older (pre-AES) encryption types only.
+     */
+    if (not_newer) {
+        if (enc_s4u_padata == NULL) {
+            if (rep_s4u_user->user_id.options &
+                    KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE) {
+                code = KRB5_KDCREP_MODIFIED;
+                goto cleanup;
+            }
+        } else {
+            if (enc_s4u_padata->length !=
+                req_s4u_user->cksum.length + rep_s4u_user->cksum.length) {
+                code = KRB5_KDCREP_MODIFIED;
+                goto cleanup;
+            }
+            if (memcmp(enc_s4u_padata->contents,
+                       req_s4u_user->cksum.contents,
+                       req_s4u_user->cksum.length) ||
+                memcmp(&enc_s4u_padata->contents[req_s4u_user->cksum.length],
+                       rep_s4u_user->cksum.contents,
+                       rep_s4u_user->cksum.length)) {
+                code = KRB5_KDCREP_MODIFIED;
+                goto cleanup;
+            }
+        }
+    } else if (!krb5_c_is_keyed_cksum(rep_s4u_user->cksum.checksum_type)) {
+        code = KRB5KRB_AP_ERR_INAPP_CKSUM;
+        goto cleanup;
+    }
+
+cleanup:
+    krb5_free_pa_s4u_x509_user(context, rep_s4u_user);
+    krb5_free_data(context, datap);
+
+    return code;
+}
+
+static krb5_error_code
+krb5_get_self_cred_from_kdc(krb5_context context,
+                            krb5_flags options,
+                            krb5_ccache ccache,
+                            krb5_creds *in_creds,
+                            krb5_data *subject_cert,
+                            krb5_data *user_realm,
+                            krb5_creds **out_creds)
+{
+    krb5_error_code code;
+    krb5_principal tgs = NULL;
+    krb5_creds tgtq, s4u_creds, *tgt = NULL, *tgtptr;
+    krb5_creds *referral_tgts[KRB5_REFERRAL_MAXHOPS];
+    krb5_pa_s4u_x509_user s4u_user;
+    int referral_count = 0, i;
+    krb5_flags kdcopt;
+
+    memset(&tgtq, 0, sizeof(tgtq));
+    memset(&s4u_creds, 0, sizeof(s4u_creds));
+    memset(referral_tgts, 0, sizeof(referral_tgts));
+    *out_creds = NULL;
+
+    memset(&s4u_user, 0, sizeof(s4u_user));
+
+    if (in_creds->client != NULL &&
+        krb5_princ_size(context, in_creds->client)) {
+        if (krb5_princ_type(context, in_creds->client) ==
+            KRB5_NT_ENTERPRISE_PRINCIPAL)
+        {
+            code = krb5_build_principal_ext(context,
+                                            &s4u_user.user_id.user,
+                                            user_realm->length,
+                                            user_realm->data,
+                                            in_creds->client->data[0].length,
+                                            in_creds->client->data[0].data,
+                                            0);
+            if (code != 0)
+                goto cleanup;
+            s4u_user.user_id.user->type = KRB5_NT_ENTERPRISE_PRINCIPAL;
+        } else {
+            code = krb5_copy_principal(context,
+                                       in_creds->client,
+                                       &s4u_user.user_id.user);
+            if (code != 0)
+                goto cleanup;
+        }
+    } else {
+        code = krb5_build_principal_ext(context, &s4u_user.user_id.user,
+                                        user_realm->length,
+                                        user_realm->data);
+        if (code != 0)
+            goto cleanup;
+        s4u_user.user_id.user->type = KRB5_NT_ENTERPRISE_PRINCIPAL;
+    }
+    if (subject_cert != NULL)
+        s4u_user.user_id.subject_cert = *subject_cert;
+    s4u_user.user_id.options = KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE;
+
+    /* First, acquire a TGT to the user's realm. */
+    code = krb5_tgtname(context, user_realm,
+                        krb5_princ_realm(context, in_creds->server), &tgs);
+    if (code != 0)
+        goto cleanup;
+
+    tgtq.client = in_creds->server;
+    tgtq.server = tgs;
+
+    code = krb5_get_credentials(context, options, ccache, &tgtq, &tgt);
+    if (code != 0)
+        goto cleanup;
+
+    tgtptr = tgt;
+
+    code = krb5int_copy_creds_contents(context, in_creds, &s4u_creds);
+    if (code != 0)
+        goto cleanup;
+
+    if (s4u_creds.client != NULL) {
+        krb5_free_principal(context, s4u_creds.client);
+        s4u_creds.client = NULL;
+    }
+
+    code = krb5_copy_principal(context, in_creds->server, &s4u_creds.client);
+    if (code != 0)
+        goto cleanup;
+
+    /* Then, walk back the referral path to S4U2Self for user */
+    kdcopt = 0;
+    if (options & KRB5_GC_CANONICALIZE)
+        kdcopt |= KDC_OPT_CANONICALIZE;
+    if (options & KRB5_GC_FORWARDABLE)
+        kdcopt |= KDC_OPT_FORWARDABLE;
+    if (options & KRB5_GC_NO_TRANSIT_CHECK)
+        kdcopt |= KDC_OPT_DISABLE_TRANSITED_CHECK;
+
+    for (referral_count = 0;
+         referral_count < KRB5_REFERRAL_MAXHOPS;
+         referral_count++)
+    {
+        krb5_pa_data **in_padata = NULL;
+        krb5_pa_data **out_padata = NULL;
+        krb5_pa_data **enc_padata = NULL;
+        krb5_keyblock *subkey = NULL;
+
+        if (s4u_user.user_id.user != NULL &&
+            krb5_princ_size(context, s4u_user.user_id.user)) {
+            in_padata = calloc(2, sizeof(krb5_pa_data *));
+            if (in_padata == NULL) {
+                code = ENOMEM;
+                goto cleanup;
+            }
+            code = build_pa_for_user(context,
+                                     tgtptr,
+                                     &s4u_user.user_id, &in_padata[0]);
+            if (code != 0) {
+                krb5_free_pa_data(context, in_padata);
+                goto cleanup;
+            }
+        }
+
+        /* Rewrite server realm to match TGS realm */
+        krb5_free_data_contents(context, &s4u_creds.server->realm);
+
+        code = krb5int_copy_data_contents(context,
+                                          &tgtptr->server->data[1],
+                                          &s4u_creds.server->realm);
+        if (code != 0)
+            goto cleanup;
+
+        code = krb5_get_cred_via_tkt_ext(context, tgtptr,
+                                         KDC_OPT_CANONICALIZE |
+                                         FLAGS2OPTS(tgtptr->ticket_flags) |
+                                         kdcopt,
+                                         tgtptr->addresses,
+                                         in_padata, &s4u_creds,
+                                         build_pa_s4u_x509_user, &s4u_user,
+                                         &out_padata, &enc_padata,
+                                         out_creds, &subkey);
+        if (code != 0) {
+            krb5_free_checksum_contents(context, &s4u_user.cksum);
+            krb5_free_pa_data(context, in_padata);
+            goto cleanup;
+        }
+
+        code = verify_s4u2self_reply(context, subkey, &s4u_user,
+                                     out_padata, enc_padata);
+
+        krb5_free_checksum_contents(context, &s4u_user.cksum);
+        krb5_free_pa_data(context, in_padata);
+        krb5_free_pa_data(context, out_padata);
+        krb5_free_pa_data(context, enc_padata);
+        krb5_free_keyblock(context, subkey);
+
+        if (code != 0)
+            goto cleanup;
+
+        if (krb5_principal_compare(context,
+                                   in_creds->server,
+                                   (*out_creds)->server)) {
+            code = 0;
+            goto cleanup;
+        } else if (IS_TGS_PRINC(context, (*out_creds)->server)) {
+            krb5_data *r1 = &tgtptr->server->data[1];
+            krb5_data *r2 = &(*out_creds)->server->data[1];
+
+            if (data_eq(*r1, *r2)) {
+                krb5_free_creds(context, *out_creds);
+                *out_creds = NULL;
+                code = KRB5_ERR_HOST_REALM_UNKNOWN;
+                break;
+            }
+            for (i = 0; i < referral_count; i++) {
+                if (krb5_principal_compare(context,
+                                           (*out_creds)->server,
+                                           referral_tgts[i]->server)) {
+                    code = KRB5_KDC_UNREACH;
+                    goto cleanup;
+                }
+            }
+
+            tgtptr = *out_creds;
+            referral_tgts[referral_count] = *out_creds;
+            *out_creds = NULL;
+        } else {
+            krb5_free_creds(context, *out_creds);
+            *out_creds = NULL;
+            code = KRB5KRB_AP_WRONG_PRINC; /* XXX */
+            break;
+        }
+    }
+
+cleanup:
+    for (i = 0; i < KRB5_REFERRAL_MAXHOPS; i++) {
+        if (referral_tgts[i] != NULL)
+            krb5_free_creds(context, referral_tgts[i]);
+    }
+    krb5_free_principal(context, tgs);
+    krb5_free_creds(context, tgt);
+    krb5_free_cred_contents(context, &s4u_creds);
+    krb5_free_principal(context, s4u_user.user_id.user);
+    krb5_free_checksum_contents(context, &s4u_user.cksum);
+
+    return code;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_credentials_for_user(krb5_context context, krb5_flags options,
+                              krb5_ccache ccache, krb5_creds *in_creds,
+                              krb5_data *subject_cert,
+                              krb5_creds **out_creds)
+{
+    krb5_error_code code;
+    krb5_principal realm = NULL;
+
+    *out_creds = NULL;
+
+    if (options & KRB5_GC_CONSTRAINED_DELEGATION) {
+        code = EINVAL;
+        goto cleanup;
+    }
+
+    if (in_creds->client != NULL) {
+        /* Uncanonicalised check */
+        code = krb5_get_credentials(context, options | KRB5_GC_CACHED,
+                                    ccache, in_creds, out_creds);
+        if (code != KRB5_CC_NOTFOUND && code != KRB5_CC_NOT_KTYPE)
+            goto cleanup;
+
+        if ((options & KRB5_GC_CACHED) && !(options & KRB5_GC_CANONICALIZE))
+            goto cleanup;
+    }
+
+    code = s4u_identify_user(context, in_creds, subject_cert, &realm);
+    if (code != 0)
+        goto cleanup;
+
+    code = krb5_get_credentials(context, options | KRB5_GC_CACHED,
+                                ccache, in_creds, out_creds);
+    if ((code != KRB5_CC_NOTFOUND && code != KRB5_CC_NOT_KTYPE)
+        || options & KRB5_GC_CACHED)
+        goto cleanup;
+
+    code = krb5_get_self_cred_from_kdc(context, options, ccache,
+                                       in_creds, subject_cert,
+                                       krb5_princ_realm(context, realm),
+                                       out_creds);
+    if (code != 0)
+        goto cleanup;
+
+    assert(*out_creds != NULL);
+
+    if ((options & KRB5_GC_NO_STORE) == 0) {
+        code = krb5_cc_store_cred(context, ccache, *out_creds);
+        if (code != 0)
+            goto cleanup;
+    }
+
+cleanup:
+    if (code != 0 && *out_creds != NULL) {
+        krb5_free_creds(context, *out_creds);
+        *out_creds = NULL;
+    }
+
+    krb5_free_principal(context, realm);
+
+    return code;
+}
+
+/*
+ * Exported API for constrained delegation (S4U2Proxy).
+ *
+ * This is preferable to using krb5_get_credentials directly because
+ * it can perform some additional checks.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_get_credentials_for_proxy(krb5_context context,
+                               krb5_flags options,
+                               krb5_ccache ccache,
+                               krb5_creds *in_creds,
+                               krb5_ticket *evidence_tkt,
+                               krb5_creds **out_creds)
+{
+    krb5_error_code code;
+    krb5_creds mcreds;
+    krb5_creds *ncreds = NULL;
+    krb5_flags fields;
+    krb5_data *evidence_tkt_data = NULL;
+    krb5_creds s4u_creds;
+
+    *out_creds = NULL;
+
+    if (in_creds == NULL || in_creds->client == NULL ||
+        evidence_tkt == NULL || evidence_tkt->enc_part2 == NULL) {
+        code = EINVAL;
+        goto cleanup;
+    }
+
+    /*
+     * Caller should have set in_creds->client to match evidence
+     * ticket client
+     */
+    if (!krb5_principal_compare(context, evidence_tkt->enc_part2->client,
+                                in_creds->client)) {
+        code = EINVAL;
+        goto cleanup;
+    }
+
+    if ((evidence_tkt->enc_part2->flags & TKT_FLG_FORWARDABLE) == 0) {
+        code = KRB5_TKT_NOT_FORWARDABLE;
+        goto cleanup;
+    }
+
+    code = krb5_get_credentials_core(context, options, in_creds,
+                                     &mcreds, &fields);
+    if (code != 0)
+        goto cleanup;
+
+    ncreds = calloc(1, sizeof(*ncreds));
+    if (ncreds == NULL) {
+        code = ENOMEM;
+        goto cleanup;
+    }
+    ncreds->magic = KV5M_CRED;
+
+    code = krb5_cc_retrieve_cred(context, ccache, fields, &mcreds, ncreds);
+    if (code != 0) {
+        free(ncreds);
+        ncreds = in_creds;
+    } else {
+        *out_creds = ncreds;
+    }
+
+    if ((code != KRB5_CC_NOTFOUND && code != KRB5_CC_NOT_KTYPE)
+        || options & KRB5_GC_CACHED)
+        goto cleanup;
+
+    code = encode_krb5_ticket(evidence_tkt, &evidence_tkt_data);
+    if (code != 0)
+        goto cleanup;
+
+    s4u_creds = *in_creds;
+    s4u_creds.client = evidence_tkt->server;
+    s4u_creds.second_ticket = *evidence_tkt_data;
+
+    code = krb5_get_credentials(context,
+                                options | KRB5_GC_CONSTRAINED_DELEGATION,
+                                ccache,
+                                &s4u_creds,
+                                out_creds);
+    if (code != 0)
+        goto cleanup;
+
+    /*
+     * Check client name because we couldn't compare that inside
+     * krb5_get_credentials() (enc_part2 is unavailable in clear)
+     */
+    if (!krb5_principal_compare(context,
+                                evidence_tkt->enc_part2->client,
+                                (*out_creds)->client)) {
+        code = KRB5_KDCREP_MODIFIED;
+        goto cleanup;
+    }
+
+cleanup:
+    if (*out_creds != NULL && code != 0) {
+        krb5_free_creds(context, *out_creds);
+        *out_creds = NULL;
+    }
+    if (evidence_tkt_data != NULL)
+        krb5_free_data(context, evidence_tkt_data);
+
+    return code;
+}
index 97cd02bf75e22d1dce73a3264075d9e506462d74..eee47ed570a2f3786541b769aea9b4b677ff0a9c 100644 (file)
@@ -77,7 +77,7 @@ tgs_construct_tgsreq(krb5_context context, krb5_data *in_data,
        if (retval)
            goto cleanup;
     }
-    
+
     /* Generate checksum */
     if ((retval = krb5_c_make_checksum(context, cksumtype,
                        &in_cred->keyblock,
@@ -142,6 +142,9 @@ cleanup:
 }
 /*
  * Note that this function fills in part of rep even on failure.
+ *
+ * The pacb_fct callback allows the caller access to the nonce
+ * and request subkey, for binding preauthentication data
  */
 krb5_error_code
 krb5int_send_tgs(krb5_context context, krb5_flags kdcoptions,
@@ -149,7 +152,13 @@ krb5int_send_tgs(krb5_context context, krb5_flags kdcoptions,
           krb5_const_principal sname, krb5_address *const *addrs,
           krb5_authdata *const *authorization_data,
           krb5_pa_data *const *padata, const krb5_data *second_ticket,
-          krb5_creds *in_cred, krb5_response *rep, krb5_keyblock **subkey)
+          krb5_creds *in_cred,
+          krb5_error_code (*pacb_fct)(krb5_context,
+                                      krb5_keyblock *,
+                                      krb5_kdc_req *,
+                                      void *),
+          void *pacb_data,
+          krb5_response *rep, krb5_keyblock **subkey)
 {
     krb5_error_code retval;
     krb5_kdc_req tgsreq;
@@ -157,13 +166,14 @@ krb5int_send_tgs(krb5_context context, krb5_flags kdcoptions,
     krb5_ticket *sec_ticket = 0;
     krb5_ticket *sec_ticket_arr[2];
     krb5_timestamp time_now;
-    krb5_pa_data **combined_padata;
+    krb5_pa_data **combined_padata = NULL;
     krb5_pa_data ap_req_padata;
     int tcp_only = 0, use_master;
     krb5_keyblock *local_subkey = NULL;
 
     assert (subkey != NULL);
     *subkey  = NULL;
+
     /* 
      * in_creds MUST be a valid credential NOT just a partially filled in
      * place holder for us to get credentials for the caller.
@@ -215,8 +225,8 @@ krb5int_send_tgs(krb5_context context, krb5_flags kdcoptions,
 
     /* Get the encryption types list */
     if (ktypes) {
-    /* Check passed ktypes and make sure they're valid. */
-       for (tgsreq.nktypes = 0; ktypes[tgsreq.nktypes]; tgsreq.nktypes++) {
+        /* Check passed ktypes and make sure they're valid. */
+        for (tgsreq.nktypes = 0; ktypes[tgsreq.nktypes]; tgsreq.nktypes++) {
             if (!krb5_c_valid_enctype(ktypes[tgsreq.nktypes]))
                 return KRB5_PROG_ETYPE_NOSUPP;
         }
@@ -236,6 +246,8 @@ krb5int_send_tgs(krb5_context context, krb5_flags kdcoptions,
     } else
         tgsreq.second_ticket = 0;
 
+    ap_req_padata.contents = NULL;
+
     /* encode the body; then checksum it */
     if ((retval = encode_krb5_kdc_req_body(&tgsreq, &scratch)))
         goto send_tgs_error_2;
@@ -250,47 +262,74 @@ krb5int_send_tgs(krb5_context context, krb5_flags kdcoptions,
     }
     krb5_free_data(context, scratch);
 
-    ap_req_padata.pa_type = KRB5_PADATA_AP_REQ;
-    ap_req_padata.length = scratch2.length;
-    ap_req_padata.contents = (krb5_octet *)scratch2.data;
-
-    /* combine in any other supplied padata */
+    tgsreq.padata = (krb5_pa_data **)calloc(2, sizeof(krb5_pa_data *));
+    if (tgsreq.padata == NULL) {
+        free(scratch2.data);
+        goto send_tgs_error_2;
+    }
+    tgsreq.padata[0] = (krb5_pa_data *)malloc(sizeof(krb5_pa_data));
+    if (tgsreq.padata[0] == NULL) {
+        free(scratch2.data);
+        goto send_tgs_error_2;
+    }
+    tgsreq.padata[0]->pa_type = KRB5_PADATA_AP_REQ;
+    tgsreq.padata[0]->length = scratch2.length;
+    tgsreq.padata[0]->contents = (krb5_octet *)scratch2.data;
+    tgsreq.padata[1] = NULL;
+
+    /* combine in any other supplied padata, unfortunately now it is
+     * necessary to copy it as the callback function might modify the
+     * padata, and having a separate path for the non-callback case,
+     * or attempting to determine which elements were changed by the
+     * callback, would have complicated the code significantly.
+     */
     if (padata) {
-        krb5_pa_data * const * counter;
-        register unsigned int i = 0;
-        for (counter = padata; *counter; counter++, i++);
-        combined_padata = malloc((i+2) * sizeof(*combined_padata));
-        if (!combined_padata) {
-            free(ap_req_padata.contents);
-            retval = ENOMEM;
-            goto send_tgs_error_2;
-        }
-        combined_padata[0] = &ap_req_padata;
-        for (i = 1, counter = padata; *counter; counter++, i++)
-            combined_padata[i] = (krb5_pa_data *) *counter;
-        combined_padata[i] = 0;
-    } else {
-        combined_padata = (krb5_pa_data **)malloc(2*sizeof(*combined_padata));
-        if (!combined_padata) {
-            free(ap_req_padata.contents);
-            retval = ENOMEM;
+        krb5_pa_data **tmp;
+        int i;
+
+        for (i = 0; padata[i]; i++)
+            ;
+
+        tmp = (krb5_pa_data **)realloc(tgsreq.padata,
+                                       (i + 2) * sizeof(*combined_padata));
+        if (tmp == NULL)
             goto send_tgs_error_2;
+
+        tgsreq.padata = tmp;
+
+        for (i = 0; padata[i]; i++) {
+            krb5_pa_data *pa;
+
+            pa = tgsreq.padata[1 + i] = (krb5_pa_data *)malloc(sizeof(krb5_pa_data));
+            if (tgsreq.padata == NULL) {
+                retval = ENOMEM;
+                goto send_tgs_error_2;
+            }
+
+            pa->pa_type = padata[i]->pa_type;
+            pa->length = padata[i]->length;
+            pa->contents = (krb5_octet *)malloc(padata[i]->length);
+            if (pa->contents == NULL) {
+                retval = ENOMEM;
+                goto send_tgs_error_2;
+            }
+            memcpy(pa->contents, padata[i]->contents, padata[i]->length);
         }
-        combined_padata[0] = &ap_req_padata;
-        combined_padata[1] = 0;
+        tgsreq.padata[1 + i] = NULL;
     }
-    tgsreq.padata = combined_padata;
 
+    if (pacb_fct != NULL) {
+        if ((retval = (*pacb_fct)(context, local_subkey, &tgsreq, pacb_data)))
+            goto send_tgs_error_2;
+    }
     /* the TGS_REQ is assembled in tgsreq, so encode it */
-    if ((retval = encode_krb5_tgs_req(&tgsreq, &scratch))) {
-        free(ap_req_padata.contents);
-        free(combined_padata);
+    if ((retval = encode_krb5_tgs_req(&tgsreq, &scratch)))
         goto send_tgs_error_2;
-    }
-    free(ap_req_padata.contents);
-    free(combined_padata);
 
     /* now send request & get response from KDC */
+    krb5_free_pa_data(context, tgsreq.padata);
+    tgsreq.padata = NULL;
+
 send_again:
     use_master = 0;
     retval = krb5_sendto_kdc(context, scratch, 
@@ -325,6 +364,8 @@ send_again:
     krb5_free_data(context, scratch);
     
 send_tgs_error_2:;
+    if (tgsreq.padata)
+        krb5_free_pa_data(context, tgsreq.padata);
     if (sec_ticket) 
         krb5_free_ticket(context, sec_ticket);
 
index b5cf260f2c0a203bafb004682ee695c06ba6da0a..0934e27e104e6ef65efef933beefc443809f06eb 100644 (file)
@@ -70,27 +70,70 @@ krb5int_server_decrypt_ticket_keyblock(krb5_context context,
 }
 
 
-krb5_error_code        KRB5_CALLCONV
+krb5_error_code KRB5_CALLCONV
 krb5_server_decrypt_ticket_keytab(krb5_context context,
-                                 const krb5_keytab kt,
+                                 const krb5_keytab keytab,
                                  krb5_ticket *ticket)
 {
-    krb5_error_code       retval;
-    krb5_enctype          enctype;
-    krb5_keytab_entry     ktent;
+    krb5_error_code      retval;
+    krb5_keytab_entry    ktent;
+
+    retval = KRB5_KT_NOTFOUND;
+
+    if (keytab->ops->start_seq_get == NULL) {
+       retval = krb5_kt_get_entry(context, keytab,
+                                  ticket->server,
+                                  ticket->enc_part.kvno,
+                                  ticket->enc_part.enctype, &ktent);
+       if (retval == 0) {
+           retval = krb5int_server_decrypt_ticket_keyblock(context, &ktent.key, ticket);
+
+           (void) krb5_free_keytab_entry_contents(context, &ktent);
+       }
+    } else {
+       krb5_error_code code;
+       krb5_kt_cursor cursor;
+
+       retval = krb5_kt_start_seq_get(context, keytab, &cursor);
+       if (retval != 0)
+           goto map_error;
 
-    enctype = ticket->enc_part.enctype;
+       while ((code = krb5_kt_next_entry(context, keytab,
+                                         &ktent, &cursor)) == 0) {
+           if (ktent.key.enctype != ticket->enc_part.enctype)
+               continue;
 
-    if ((retval = krb5_kt_get_entry(context, kt, ticket->server,
-                                    ticket->enc_part.kvno,
-                                    enctype, &ktent)))
-        return retval;
+           retval = krb5int_server_decrypt_ticket_keyblock(context, &ktent.key, ticket);
+           if (retval == 0) {
+               krb5_principal tmp;
 
-    retval = krb5int_server_decrypt_ticket_keyblock(context,
-                                                   &ktent.key, ticket);
-    /* Upon error, Free keytab entry first, then return */
+               retval = krb5_copy_principal(context, ktent.principal, &tmp);
+               if (retval == 0) {
+                   krb5_free_principal(context, ticket->server);
+                   ticket->server = tmp;
+               }
+               (void) krb5_free_keytab_entry_contents(context, &ktent);
+               break;
+           }
+           (void) krb5_free_keytab_entry_contents(context, &ktent);
+       }
+
+       code = krb5_kt_end_seq_get(context, keytab, &cursor);
+       if (code != 0)
+           retval = code;
+    }
+
+map_error:
+    switch (retval) {
+    case KRB5_KT_KVNONOTFOUND:
+    case KRB5_KT_NOTFOUND:
+    case KRB5KRB_AP_ERR_BAD_INTEGRITY:
+       retval = KRB5KRB_AP_WRONG_PRINC;
+       break;
+    default:
+       break;
+    }
 
-    (void) krb5_kt_free_entry(context, &ktent);
     return retval;
 }
 #endif /* LEAN_CLIENT */
index bbefc942f388728736dfa8890e16ebd5574fe455..cf4dc21ec7e12350e71d4c8cb430166fbe25092f 100644 (file)
@@ -21,11 +21,12 @@ decode_krb5_error
 decode_krb5_etype_info
 decode_krb5_etype_info2
 decode_krb5_fast_req
-decode_krb5_pa_fx_fast_request
 decode_krb5_kdc_req_body
 decode_krb5_pa_enc_ts
 decode_krb5_pa_for_user
+decode_krb5_pa_fx_fast_request
 decode_krb5_pa_pac_req
+decode_krb5_pa_s4u_x509_user
 decode_krb5_padata_sequence
 decode_krb5_predicted_sam_response
 decode_krb5_priv
@@ -62,10 +63,11 @@ encode_krb5_error
 encode_krb5_etype_info
 encode_krb5_etype_info2
 encode_krb5_fast_response
-encode_krb5_pa_fx_fast_reply
 encode_krb5_kdc_req_body
 encode_krb5_pa_enc_ts
 encode_krb5_pa_for_user
+encode_krb5_pa_fx_fast_reply
+encode_krb5_pa_s4u_x509_user
 encode_krb5_pa_server_referral_data
 encode_krb5_pa_svr_referral_data
 encode_krb5_padata_sequence
@@ -73,6 +75,7 @@ encode_krb5_predicted_sam_response
 encode_krb5_priv
 encode_krb5_pwd_data
 encode_krb5_pwd_sequence
+encode_krb5_s4u_userid
 encode_krb5_safe
 encode_krb5_sam_challenge
 encode_krb5_sam_key
@@ -149,9 +152,9 @@ krb5_authdata_export_internal
 krb5_authdata_free_internal
 krb5_authdata_import_attributes
 krb5_build_principal
+krb5_build_principal_alloc_va
 krb5_build_principal_ext
 krb5_build_principal_va
-krb5_build_principal_alloc_va
 krb5_cc_close
 krb5_cc_copy_creds
 krb5_cc_default
@@ -259,8 +262,9 @@ krb5_free_ktypes
 krb5_free_last_req
 krb5_free_pa_data
 krb5_free_pa_enc_ts
-krb5_free_pa_pac_req
 krb5_free_pa_for_user
+krb5_free_pa_pac_req
+krb5_free_pa_s4u_x509_user
 krb5_free_pa_server_referral_data
 krb5_free_pa_svr_referral_data
 krb5_free_passwd_phrase_element
@@ -300,6 +304,8 @@ krb5_get_cred_from_kdc_renew
 krb5_get_cred_from_kdc_validate
 krb5_get_cred_via_tkt
 krb5_get_credentials
+krb5_get_credentials_for_proxy
+krb5_get_credentials_for_user
 krb5_get_credentials_renew
 krb5_get_credentials_validate
 krb5_get_default_config_files
@@ -397,7 +403,6 @@ krb5_os_free_context
 krb5_os_hostaddr
 krb5_os_init_context
 krb5_os_localaddr
-krb5int_get_domain_realm_mapping
 krb5_overridekeyname
 krb5_pac_add_buffer
 krb5_pac_free
@@ -548,6 +553,7 @@ krb5int_find_pa_data
 krb5int_foreach_localaddr
 krb5int_free_addrlist
 krb5int_free_data_list
+krb5int_get_domain_realm_mapping
 krb5int_init_context_kdc
 krb5int_initialize_library
 krb5int_pac_sign
index dcf08d996be45d9c907542659976118b9b409c1b..3e5f9e2341d3442a339e02e595502f4844b77f5c 100644 (file)
@@ -57,7 +57,7 @@
 #define DEFAULT_UDP_PREF_LIMIT  1465
 #define HARD_UDP_LIMIT         32700 /* could probably do 64K-epsilon ? */
 
-#undef DEBUG
+#define DEBUG 1
 
 #ifdef DEBUG
 int krb5int_debug_sendto_kdc = 0;
index 8b3c7a14a3dc3db1497b6d2dce599eb9477abb4e..1cf67629bc40b6753e0848f54972855c0a615b2d 100644 (file)
@@ -188,7 +188,10 @@ krb5_ldap_iterate(context, match_expr, func, func_arg)
 
        LDAP_SEARCH(subtree[tree], ldap_context->lrparams->search_scope, filter, principal_attributes);
        for (ent=ldap_first_entry(ld, result); ent != NULL; ent=ldap_next_entry(ld, ent)) {
-           if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) {
+           values=ldap_get_values(ld, ent, "krbcanonicalname");
+           if (values == NULL)
+               values=ldap_get_values(ld, ent, "krbprincipalname");
+           if (values != NULL) {
                for (i=0; values[i] != NULL; ++i) {
                    if (krb5_ldap_parse_principal_name(values[i], &princ_name) != 0)
                        continue;
@@ -201,13 +204,11 @@ krb5_ldap_iterate(context, match_expr, func, func_arg)
                        (*func)(func_arg, &entry);
                        krb5_dbe_free_contents(context, &entry);
                        (void) krb5_free_principal(context, principal);
-                       if (princ_name)
-                           free(princ_name);
+                       free(princ_name);
                        break;
                    }
                    (void) krb5_free_principal(context, principal);
-                   if (princ_name)
-                       free(princ_name);
+                   free(princ_name);
                }
                ldap_value_free(values);
            }
index 14d029c452b5ba3f567306fdda65fd72273987e6..03c3da48d78b78ec23872394f38b29aae781d91a 100644 (file)
@@ -69,6 +69,30 @@ berval2tl_data(struct berval *in, krb5_tl_data **out)
     return 0;
 }
 
+/* Return true if it's okay to return aliases according to flags. */
+static krb5_boolean
+aliases_ok(unsigned int flags)
+{
+    /*
+     * The current DAL does not have a flag to indicate whether
+     * aliases are okay.  For service name lookups (AS or TGT path),
+     * we can always return aliases.  For client name lookups, we can
+     * only return aliases if the client passed the canonicalize flag.
+     * We abuse the CLIENT_REFERRALS_ONLY flag to detect client name
+     * lookups.
+     *
+     * This method has the side effect of permitting aliases for
+     * lookups by administrative interfaces (e.g. kadmin).  Since we
+     * don't have explicit admin support for aliases yet, this is
+     * okay.
+     */
+    if (!(flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY))
+       return TRUE;
+    if (flags & KRB5_KDB_FLAG_CANONICALIZE)
+       return TRUE;
+    return FALSE;
+}
+
 /*
  * look up a principal in the directory.
  */
@@ -160,7 +184,7 @@ krb5_ldap_get_principal(context, searchfor, flags, entries, nentries, more)
            if ((values=ldap_get_values(ld, ent, "krbcanonicalname")) != NULL) {
                if (values[0] && strcmp(values[0], user) != 0) {
                    /* We matched an alias, not the canonical name. */
-                   if (flags & KRB5_KDB_FLAG_CANONICALIZE) {
+                   if (aliases_ok(flags)) {
                        st = krb5_ldap_parse_principal_name(values[0], &cname);
                        if (st != 0)
                            goto cleanup;
index 43a7738d4129d350c356df9ebd1b1a5a428f7fd2..6fb2e2288f57496264efdad68ef691c784abd90a 100644 (file)
@@ -40,23 +40,31 @@ static void
 print_flags(unsigned int flags)
 {
     unsigned int i;
-    static char *prflags[] = { 
-       "DISALLOW_POSTDATED",   /* 0x00000001 */ 
-       "DISALLOW_FORWARDABLE", /* 0x00000002 */ 
-       "DISALLOW_TGT_BASED",   /* 0x00000004 */ 
-       "DISALLOW_RENEWABLE",   /* 0x00000008 */ 
-       "DISALLOW_PROXIABLE",   /* 0x00000010 */ 
-       "DISALLOW_DUP_SKEY",    /* 0x00000020 */ 
-       "DISALLOW_ALL_TIX",     /* 0x00000040 */ 
-       "REQUIRES_PRE_AUTH",    /* 0x00000080 */ 
-       "REQUIRES_HW_AUTH",     /* 0x00000100 */ 
-       "REQUIRES_PWCHANGE",    /* 0x00000200 */ 
-       "UNKNOWN_0x00000400",   /* 0x00000400 */ 
-       "UNKNOWN_0x00000800",   /* 0x00000800 */ 
-       "DISALLOW_SVR",         /* 0x00001000 */ 
-       "PWCHANGE_SERVICE",     /* 0x00002000 */ 
-       "SUPPORT_DESMD5",       /* 0x00004000 */ 
-       "NEW_PRINC",            /* 0x00008000 */ 
+    static char *prflags[] = {
+       "DISALLOW_POSTDATED",     /* 0x00000001 */
+       "DISALLOW_FORWARDABLE",   /* 0x00000002 */
+       "DISALLOW_TGT_BASED",     /* 0x00000004 */
+       "DISALLOW_RENEWABLE",     /* 0x00000008 */
+       "DISALLOW_PROXIABLE",     /* 0x00000010 */
+       "DISALLOW_DUP_SKEY",      /* 0x00000020 */
+       "DISALLOW_ALL_TIX",       /* 0x00000040 */
+       "REQUIRES_PRE_AUTH",      /* 0x00000080 */
+       "REQUIRES_HW_AUTH",       /* 0x00000100 */
+       "REQUIRES_PWCHANGE",      /* 0x00000200 */
+       "UNKNOWN_0x00000400",     /* 0x00000400 */
+       "UNKNOWN_0x00000800",     /* 0x00000800 */
+       "DISALLOW_SVR",           /* 0x00001000 */
+       "PWCHANGE_SERVICE",       /* 0x00002000 */
+       "SUPPORT_DESMD5",         /* 0x00004000 */
+       "NEW_PRINC",              /* 0x00008000 */
+       "UNKNOWN_0x00010000",     /* 0x00010000 */
+       "UNKNOWN_0x00020000",     /* 0x00020000 */
+       "UNKNOWN_0x00040000",     /* 0x00040000 */
+       "UNKNOWN_0x00080000",     /* 0x00080000 */
+       "OK_AS_DELEGATE",         /* 0x00100000 */
+       "OK_TO_AUTH_AS_DELEGATE", /* 0x00200000 */
+       "NO_AUTH_DATA_REQUIRED",  /* 0x00400000 */
+
     };
 
     for (i = 0; i < sizeof (prflags) / sizeof (char *); i++) {
@@ -169,7 +177,7 @@ print_key(kdbe_key_t *k)
 
     for (i = 0; i < k->k_enctype.k_enctype_len; i++) {
        printf("\t\t\tenc type: 0x%x\n",
-              k->k_enctype.k_enctype_val[i]); 
+              k->k_enctype.k_enctype_val[i]);
     }
 
     str = k->k_contents.k_contents_val;
index 3f8b929ac716d4e3389a31861d81c47e2c67ec0a..3eb6f3c66ed1bd4fa168aa58518c9ec9c34d1306 100644 (file)
@@ -659,10 +659,20 @@ main(int argc, char **argv)
         ktest_empty_enc_sam_response_enc_2(&sam_ch2);
     }
     /****************************************************************/
+    /* encode_krb5_pa_s4u_x509_user */
+    {
+        krb5_pa_s4u_x509_user s4u, *tmp;
+        setup(s4u, "pa_s4u_x509_user",
+              ktest_make_sample_pa_s4u_x509_user);
+        leak_test(s4u, encode_krb5_pa_s4u_x509_user,
+                  decode_krb5_pa_s4u_x509_user,
+                  krb5_free_pa_s4u_x509_user);
+        ktest_empty_pa_s4u_x509_user(&s4u);
+    }
+    /****************************************************************/
     /* encode_krb5_ad_kdcissued */
     {
         krb5_ad_kdcissued kdci, *tmp;
-
         setup(kdci, "ad_kdcissued",
               ktest_make_sample_ad_kdcissued);
         leak_test(kdci, encode_krb5_ad_kdcissued,
index 90cf747e5656579df64bca91d1ed7a13076602b9..401b26240e277d60346e08fb1ef32ece253e0e91 100644 (file)
@@ -890,11 +890,23 @@ int main(argc, argv)
 
        ktest_empty_sam_response(&ref);
     }
+
+    /****************************************************************/
+    /* decode_pa_s4u_x509_user */
+    {
+       setup(krb5_pa_s4u_x509_user,"krb5_pa_s4u_x509_user",ktest_make_sample_pa_s4u_x509_user);
+       decode_run("pa_s4u_x509_user","","30 68 A0 55 30 53 A0 06 02 04 00 CA 14 9A A1 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 12 04 10 70 61 5F 73 34 75 5F 78 35 30 39 5F 75 73 65 72 A4 07 03 05 00 80 00 00 00 A1 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34",decode_krb5_pa_s4u_x509_user,ktest_equal_pa_s4u_x509_user,krb5_free_pa_s4u_x509_user);
+       ktest_empty_pa_s4u_x509_user(&ref);
+    }
+
+    /****************************************************************/
+    /* decode_ad_kdcissued */
     {
        setup(krb5_ad_kdcissued,"krb5_ad_kdcissued",ktest_make_sample_ad_kdcissued);
        decode_run("ad_kdcissued","","30 65 A0 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 24 30 22 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72",decode_krb5_ad_kdcissued,ktest_equal_ad_kdcissued,krb5_free_ad_kdcissued);
        ktest_empty_ad_kdcissued(&ref);
     }
+
 #ifdef ENABLE_LDAP
     /* ldap sequence_of_keys */
     {
index a4896d96a77152fe68ec56c6ebbf466e1f952c5d..c010af9ab63ea2a4bdcda3fe1545e4c494617e27 100644 (file)
@@ -696,6 +696,17 @@ main(argc, argv)
        ktest_empty_enc_sam_response_enc_2(&sam_ch2);
     }
     /****************************************************************/
+    /* encode_krb5_pa_s4u_x509_user */
+    {
+       krb5_pa_s4u_x509_user s4u;
+       setup(s4u,krb5_pa_s4u_x509_user,"pa_s4u_x509_user",
+             ktest_make_sample_pa_s4u_x509_user);
+       encode_run(s4u,krb5_pa_s4u_x509_user,
+                  "pa_s4u_x509_user","",
+                  encode_krb5_pa_s4u_x509_user);
+       ktest_empty_pa_s4u_x509_user(&s4u);
+    }
+    /****************************************************************/
     /* encode_krb5_ad_kdcissued */
     {
        krb5_ad_kdcissued kdci;
index f7814f8d9abbf897e9c3f7ad999ca8521c823371..f41347c0f8bfb5a783c75a5d5eabfb1dff379c76 100644 (file)
@@ -825,6 +825,23 @@ krb5_error_code ktest_make_sample_enc_sam_response_enc_2(p)
     return 0;
 }
 
+krb5_error_code ktest_make_sample_pa_s4u_x509_user(p)
+    krb5_pa_s4u_x509_user *p;
+{
+    krb5_error_code retval;
+    krb5_s4u_userid *u = &p->user_id;
+    u->nonce = 13243546;
+    retval = ktest_make_sample_principal(&u->user);
+    if (retval) return retval;
+    u->subject_cert.data = strdup("pa_s4u_x509_user");
+    if (u->subject_cert.data == NULL) return ENOMEM;
+    u->subject_cert.length = strlen(u->subject_cert.data);
+    u->options = 0x80000000;
+    retval = ktest_make_sample_checksum(&p->cksum);
+    if (retval) return retval;
+    return 0;
+}
+
 krb5_error_code ktest_make_sample_ad_kdcissued(p)
     krb5_ad_kdcissued *p;
 {
@@ -1433,6 +1450,14 @@ void ktest_empty_enc_sam_response_enc_2(p)
   ktest_empty_data(&p->sam_sad);
 }
 
+void ktest_empty_pa_s4u_x509_user(p)
+    krb5_pa_s4u_x509_user *p;
+{
+    ktest_destroy_principal(&p->user_id.user);
+    ktest_empty_data(&p->user_id.subject_cert);
+    if (p->cksum.contents) free(p->cksum.contents);
+}
+
 void ktest_empty_ad_kdcissued(p)
     krb5_ad_kdcissued *p;
 {
index d02b567a007a5c57ec2e5f89f485c6a29c7be3e2..fa33ceffd40ea48970b0290a439d591496727cdc 100644 (file)
@@ -105,6 +105,7 @@ krb5_error_code ktest_make_sample_enc_sam_response_enc
        (krb5_enc_sam_response_enc *p);
 krb5_error_code ktest_make_sample_predicted_sam_response(krb5_predicted_sam_response *p);
 krb5_error_code ktest_make_sample_enc_sam_response_enc_2(krb5_enc_sam_response_enc_2 *p);
+krb5_error_code ktest_make_sample_pa_s4u_x509_user(krb5_pa_s4u_x509_user *p);
 krb5_error_code ktest_make_sample_ad_kdcissued(krb5_ad_kdcissued *p);
 
 #ifdef ENABLE_LDAP
@@ -214,6 +215,7 @@ void ktest_empty_enc_sam_response_enc(krb5_enc_sam_response_enc *p);
 void ktest_empty_predicted_sam_response(krb5_predicted_sam_response *p);
 void ktest_empty_sam_response_2(krb5_sam_response_2 *p);
 void ktest_empty_enc_sam_response_enc_2(krb5_enc_sam_response_enc_2 *p);
+void ktest_empty_pa_s4u_x509_user(krb5_pa_s4u_x509_user *p);
 void ktest_empty_ad_kdcissued(krb5_ad_kdcissued *p);
 
 #ifdef ENABLE_LDAP
index a23e82bc7d3fca23edb6df65e4e391e72c915ad2..5479f8047a1b808f7c73352d69c1d0b5032a9914 100644 (file)
@@ -542,6 +542,21 @@ int ktest_equal_sam_response(ref, var)
     return p;
 }
 
+int ktest_equal_pa_s4u_x509_user(ref, var)
+    krb5_pa_s4u_x509_user *ref;
+    krb5_pa_s4u_x509_user *var;
+{
+    int p = TRUE;
+    if (ref == var) return TRUE;
+    else if (ref == NULL || var == NULL) return FALSE;
+    p=p&&scalar_equal(user_id.nonce);
+    p=p&&ptr_equal(user_id.user,ktest_equal_principal_data);
+    p=p&&struct_equal(user_id.subject_cert,ktest_equal_data);
+    p=p&&scalar_equal(user_id.options);
+    p=p&&struct_equal(cksum,ktest_equal_checksum);
+    return p;
+}
+
 int ktest_equal_ad_kdcissued(ref, var)
     krb5_ad_kdcissued *ref;
     krb5_ad_kdcissued *var;
index cd9245347829c781c2429b6297737f7b8e5453c6..1464ebb50948bc82a8718f89dbc024e4bad195c4 100644 (file)
@@ -91,6 +91,10 @@ int ktest_equal_krb5_etype_info_entry
     (krb5_etype_info_entry * ref,
                    krb5_etype_info_entry * var);
 
+int ktest_equal_pa_s4u_x509_user
+    (krb5_pa_s4u_x509_user *ref,
+                   krb5_pa_s4u_x509_user *var);
+
 int ktest_equal_ad_kdcissued
     (krb5_ad_kdcissued *ref,
                    krb5_ad_kdcissued *var);
index 8360eba3de8757f5383a9dd92062b834b1e64063..952e69c771ed5a92d51211bae713779383d2e2e3 100644 (file)
@@ -56,4 +56,5 @@ encode_krb5_enc_sam_response_enc: 30 38 A0 05 02 03 01 33 2A A1 11 18 0F 31 39 3
 encode_krb5_predicted_sam_response: 30 6D A0 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A1 07 03 05 00 00 00 00 09 A2 11 18 0F 31 39 37 30 30 31 30 31 30 30 30 30 31 37 5A A3 03 02 01 12 A4 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A5 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A6 07 04 05 68 65 6C 6C 6F
 encode_krb5_sam_response_2: 30 42 A0 03 02 01 2B A1 07 03 05 00 80 00 00 00 A2 0C 04 0A 74 72 61 63 6B 20 64 61 74 61 A3 1D 30 1B A0 03 02 01 01 A1 04 02 02 0D 36 A2 0E 04 0C 6E 6F 6E 63 65 20 6F 72 20 73 61 64 A4 05 02 03 54 32 10
 encode_krb5_enc_sam_response_enc_2: 30 1F A0 03 02 01 58 A1 18 04 16 65 6E 63 5F 73 61 6D 5F 72 65 73 70 6F 6E 73 65 5F 65 6E 63 5F 32
+encode_krb5_pa_s4u_x509_user: 30 68 A0 55 30 53 A0 06 02 04 00 CA 14 9A A1 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 12 04 10 70 61 5F 73 34 75 5F 78 35 30 39 5F 75 73 65 72 A4 07 03 05 00 80 00 00 00 A1 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34
 encode_krb5_ad_kdcissued: 30 65 A0 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 24 30 22 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72
index 09ffb0f66564e033d1ed3789ac213ac784b384d0..b19ca747e7552d71ad2becfb7ae1f185a2b088b4 100644 (file)
@@ -1246,6 +1246,23 @@ encode_krb5_enc_sam_response_enc_2:
 .  [0] [Integer] 88
 .  [1] [Octet String] "enc_sam_response_enc_2"
 
+encode_krb5_pa_s4u_x509_user:
+
+[Sequence/Sequence Of] 
+.  [0] [Sequence/Sequence Of] 
+.  .  [0] [Integer] 13243546
+.  .  [1] [Sequence/Sequence Of] 
+.  .  .  [0] [Integer] 1
+.  .  .  [1] [Sequence/Sequence Of] 
+.  .  .  .  [General string] "hftsai"
+.  .  .  .  [General string] "extra"
+.  .  [2] [General string] "ATHENA.MIT.EDU"
+.  .  [3] [Octet String] "pa_s4u_x509_user"
+.  .  [4] [Bit String] 0x80000000
+.  [1] [Sequence/Sequence Of] 
+.  .  [0] [Integer] 1
+.  .  [1] [Octet String] "1234"
+
 encode_krb5_ad_kdcissued:
 
 [Sequence/Sequence Of] 
index 455fbc0935b9454df85bb073d4d4213c5e40b87b..fd7b7db5b6ce2bce36baef5c8b9344898b6b7440 100644 (file)
@@ -6,17 +6,19 @@ DEFINES = -DUSE_AUTOCONF_H
 PROG_LIBPATH=-L$(TOPLIBD)
 PROG_RPATH=$(KRB5_LIBDIR)
 
-SRCS= $(srcdir)/t_imp_name.c $(srcdir)/t_namingexts.c
+SRCS= $(srcdir)/t_imp_name.c $(srcdir)/t_s4u.c $(srcdir)/t_namingexts.c
 
-OBJS= t_imp_name.o t_namingexts.o
+OBJS= t_imp_name.o t_s4u.o t_namingexts.o
 
-all:: t_imp_name t_namingexts
+all:: t_imp_name t_s4u t_namingexts
 
 t_imp_name: t_imp_name.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
        $(CC_LINK) -o t_imp_name t_imp_name.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
 t_namingexts: t_namingexts.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
        $(CC_LINK) -o t_namingexts t_namingexts.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
+t_s4u: t_s4u.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+       $(CC_LINK) -o t_s4u t_s4u.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
 
 clean::
-       $(RM) t_imp_name
+       $(RM) t_imp_name t_s4u t_namingexts
 
diff --git a/src/tests/gssapi/t_s4u.c b/src/tests/gssapi/t_s4u.c
new file mode 100644 (file)
index 0000000..264e60a
--- /dev/null
@@ -0,0 +1,418 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2009  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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gssapi/gssapi_krb5.h>
+
+/*
+ * Test program for protocol transition (S4U2Self) and constrained delegation
+ * (S4U2Proxy)
+ *
+ * Note: because of name canonicalization, the following tips may help
+ * when configuring with Active Directory:
+ *
+ * - Create a computer account FOO$
+ * - Set the UPN to host/foo.domain (no suffix); this is necessary to
+ *   be able to send an AS-REQ as this principal, otherwise you would
+ *   need to use the canonical name (FOO$), which will cause principal
+ *   comparison errors in gss_accept_sec_context().
+ * - Add a SPN of host/foo.domain
+ * - Configure the computer account to support constrained delegation with
+ *   protocol transition (Trust this computer for delegation to specified
+ *   services only / Use any authentication protocol)
+ * - Add host/foo.domain to the keytab (possibly easiest to do this
+ *   with ktadd)
+ *
+ * For S4U2Proxy to work the TGT must be forwardable too.
+ *
+ * Usage eg:
+ *
+ * kinit -k -t test.keytab -f 'host/test.win.mit.edu@WIN.MIT.EDU'
+ * ./t_s4u delegtest@WIN.MIT.EDU HOST/WIN-EQ7E4AA2WR8.win.mit.edu@WIN.MIT.EDU test.keytab
+ */
+
+static gss_OID_desc spnego_mech = { 6, "\053\006\001\005\005\002" };
+
+int use_spnego = 0;
+
+static void displayStatus_1(m, code, type)
+     char *m;
+     OM_uint32 code;
+     int type;
+{
+     OM_uint32 maj_stat, min_stat;
+     gss_buffer_desc msg;
+     OM_uint32 msg_ctx;
+
+     msg_ctx = 0;
+     while (1) {
+          maj_stat = gss_display_status(&min_stat, code,
+                                       type, GSS_C_NULL_OID,
+                                       &msg_ctx, &msg);
+          fprintf(stderr, "%s: %s\n", m, (char *)msg.value);
+          (void) gss_release_buffer(&min_stat, &msg);
+
+          if (!msg_ctx)
+               break;
+     }
+}
+
+static void displayStatus(msg, maj_stat, min_stat)
+     char *msg;
+     OM_uint32 maj_stat;
+     OM_uint32 min_stat;
+{
+     displayStatus_1(msg, maj_stat, GSS_C_GSS_CODE);
+     displayStatus_1(msg, min_stat, GSS_C_MECH_CODE);
+}
+
+static OM_uint32
+displayCanonName(OM_uint32 *minor, gss_name_t name, char *tag)
+{
+    gss_name_t canon;
+    OM_uint32 major, tmp_minor;
+    gss_buffer_desc buf;
+
+    major = gss_canonicalize_name(minor, name,
+                                  (gss_OID)gss_mech_krb5, &canon);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_canonicalize_name", major, *minor);
+        return major;
+    }
+
+    major = gss_display_name(minor, canon, &buf, NULL);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_display_name", major, *minor);
+        gss_release_name(&tmp_minor, &canon);
+        return major;
+    }
+
+    printf("%s:\t%s\n", tag, (char *)buf.value);
+
+    gss_release_buffer(&tmp_minor, &buf);
+    gss_release_name(&tmp_minor, &canon);
+
+    return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+displayOID(OM_uint32 *minor, gss_OID oid, char *tag)
+{
+    OM_uint32 major, tmp_minor;
+    gss_buffer_desc buf;
+
+    major = gss_oid_to_str(minor, oid, &buf);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_oid_to_str", major, *minor);
+        return major;
+    }
+
+    printf("%s:\t%s\n", tag, (char *)buf.value);
+
+    gss_release_buffer(&tmp_minor, &buf);
+
+    return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+initAcceptSecContext(OM_uint32 *minor,
+                     gss_cred_id_t claimant_cred_handle,
+                     gss_cred_id_t verifier_cred_handle,
+                     gss_cred_id_t *deleg_cred_handle)
+{
+    OM_uint32 major, tmp_minor;
+    gss_buffer_desc token, tmp;
+    gss_ctx_id_t initiator_context = GSS_C_NO_CONTEXT;
+    gss_ctx_id_t acceptor_context = GSS_C_NO_CONTEXT;
+    gss_name_t source_name = GSS_C_NO_NAME;
+    gss_name_t target_name = GSS_C_NO_NAME;
+    OM_uint32 time_rec;
+    gss_OID mech = GSS_C_NO_OID;
+
+    token.value = NULL;
+    token.length = 0;
+
+    tmp.value = NULL;
+    tmp.length = 0;
+
+    *deleg_cred_handle = GSS_C_NO_CREDENTIAL;
+
+    major = gss_inquire_cred(minor, verifier_cred_handle,
+                             &target_name, NULL, NULL, NULL);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_inquire_cred", major, *minor);
+        return major;
+    }
+
+    displayCanonName(minor, target_name, "Target name");
+
+    mech = use_spnego ? (gss_OID)&spnego_mech : (gss_OID)gss_mech_krb5;
+    displayOID(minor, mech, "Target mech");
+
+    major = gss_init_sec_context(minor,
+                                 claimant_cred_handle,
+                                 &initiator_context,
+                                 target_name,
+                                 mech,
+                                 GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG,
+                                 GSS_C_INDEFINITE,
+                                 GSS_C_NO_CHANNEL_BINDINGS,
+                                 GSS_C_NO_BUFFER,
+                                 NULL,
+                                 &token,
+                                 NULL,
+                                 &time_rec);
+
+    if (target_name != GSS_C_NO_NAME)
+        (void) gss_release_name(&tmp_minor, &target_name);
+
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_init_sec_context", major, *minor);
+        return major;
+    }
+
+    (void) gss_delete_sec_context(minor, &initiator_context, NULL);
+    mech = GSS_C_NO_OID;
+
+    major = gss_accept_sec_context(minor,
+                                   &acceptor_context,
+                                   verifier_cred_handle,
+                                   &token,
+                                   GSS_C_NO_CHANNEL_BINDINGS,
+                                   &source_name,
+                                   &mech,
+                                   &tmp,
+                                   NULL,
+                                   &time_rec,
+                                   deleg_cred_handle);
+
+    if (GSS_ERROR(major))
+        displayStatus("gss_accept_sec_context", major, *minor);
+    else {
+        displayCanonName(minor, source_name, "Source name");
+        displayOID(minor, mech, "Source mech");
+    }
+
+    (void) gss_release_name(&tmp_minor, &source_name);
+    (void) gss_delete_sec_context(&tmp_minor, &acceptor_context, NULL);
+    (void) gss_release_buffer(&tmp_minor, &token);
+    (void) gss_release_buffer(&tmp_minor, &tmp);
+    (void) gss_release_oid(&tmp_minor, &mech);
+
+    return major;
+}
+
+static OM_uint32
+constrainedDelegate(OM_uint32 *minor,
+                    gss_OID_set desired_mechs,
+                    gss_name_t target,
+                    gss_cred_id_t delegated_cred_handle,
+                    gss_cred_id_t verifier_cred_handle)
+{
+    OM_uint32 major, tmp_minor;
+    gss_ctx_id_t initiator_context = GSS_C_NO_CONTEXT;
+    gss_name_t cred_name = GSS_C_NO_NAME;
+    OM_uint32 time_rec, lifetime;
+    gss_cred_usage_t usage;
+    gss_buffer_desc token;
+    gss_OID_set mechs;
+
+    printf("Constrained delegation tests follow\n");
+    printf("-----------------------------------\n\n");
+
+    if (gss_inquire_cred(minor, verifier_cred_handle, &cred_name,
+                         &lifetime, &usage, NULL) == GSS_S_COMPLETE) {
+        displayCanonName(minor, cred_name, "Proxy name");
+        gss_release_name(&tmp_minor, &cred_name);
+    }
+    displayCanonName(minor, target, "Target name");
+    if (gss_inquire_cred(minor, delegated_cred_handle, &cred_name,
+                         &lifetime, &usage, &mechs) == GSS_S_COMPLETE) {
+        displayCanonName(minor, cred_name, "Delegated name");
+        displayOID(minor, &mechs->elements[0], "Delegated mech");
+        gss_release_name(&tmp_minor, &cred_name);
+    }
+
+    printf("\n");
+
+    major = gss_init_sec_context(minor,
+                                 delegated_cred_handle,
+                                 &initiator_context,
+                                 target,
+                                 mechs ? &mechs->elements[0] :
+                                         (gss_OID)gss_mech_krb5,
+                                 GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG,
+                                 GSS_C_INDEFINITE,
+                                 GSS_C_NO_CHANNEL_BINDINGS,
+                                 GSS_C_NO_BUFFER,
+                                 NULL,
+                                 &token,
+                                 NULL,
+                                 &time_rec);
+    if (GSS_ERROR(major))
+        displayStatus("gss_init_sec_context", major, *minor);
+
+    (void) gss_release_buffer(&tmp_minor, &token);
+    (void) gss_delete_sec_context(&tmp_minor, &initiator_context, NULL);
+    (void) gss_release_oid_set(&tmp_minor, &mechs);
+
+    return major;
+}
+
+int main(int argc, char *argv[])
+{
+    OM_uint32 minor, major;
+    gss_cred_id_t impersonator_cred_handle = GSS_C_NO_CREDENTIAL;
+    gss_cred_id_t user_cred_handle = GSS_C_NO_CREDENTIAL;
+    gss_cred_id_t delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+    gss_name_t user = GSS_C_NO_NAME, target = GSS_C_NO_NAME;
+    gss_OID_set_desc mechs;
+    gss_OID_set actual_mechs = GSS_C_NO_OID_SET;
+    gss_buffer_desc buf;
+
+    if (argc < 2 || argc > 5) {
+        fprintf(stderr, "Usage: %s [--spnego] [user] "
+                        "[proxy-target] [keytab]\n", argv[0]);
+        fprintf(stderr, "       proxy-target and keytab are optional\n");
+        exit(1);
+    }
+
+    if (strcmp(argv[1], "--spnego") == 0) {
+        use_spnego++;
+        argc--;
+        argv++;
+    }
+
+    buf.value = argv[1];
+    buf.length = strlen((char *)buf.value);
+
+    major = gss_import_name(&minor, &buf,
+                            (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME,
+                            &user);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_import_name(user)", major, minor);
+        goto out;
+    }
+
+    if (argc > 2 && strcmp(argv[2], "-")) {
+        buf.value = argv[2];
+        buf.length = strlen((char *)buf.value);
+
+        major = gss_import_name(&minor, &buf,
+                                (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME,
+                                &target);
+        if (GSS_ERROR(major)) {
+            displayStatus("gss_import_name(target)", major, minor);
+            goto out;
+        }
+    } else {
+        target = GSS_C_NO_NAME;
+    }
+
+    if (argc > 3) {
+        major = krb5_gss_register_acceptor_identity(argv[3]);
+        if (GSS_ERROR(major)) {
+            displayStatus("krb5_gss_register_acceptor_identity",
+                          major, minor);
+            goto out;
+        }
+    }
+
+    mechs.elements = use_spnego ? (gss_OID)&spnego_mech :
+                                  (gss_OID)gss_mech_krb5;
+    mechs.count = 1;
+
+    /* get default cred */
+    major = gss_acquire_cred(&minor,
+                             GSS_C_NO_NAME,
+                             GSS_C_INDEFINITE,
+                             &mechs,
+                             GSS_C_BOTH,
+                             &impersonator_cred_handle,
+                             &actual_mechs,
+                             NULL);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_acquire_cred", major, minor);
+        goto out;
+    }
+
+    (void) gss_release_oid_set(&minor, &actual_mechs);
+
+    printf("Protocol transition tests follow\n");
+    printf("-----------------------------------\n\n");
+
+    /* get S4U2Self cred */
+    major = gss_acquire_cred_impersonate_name(&minor,
+                                              impersonator_cred_handle,
+                                              user,
+                                              GSS_C_INDEFINITE,
+                                              &mechs,
+                                              GSS_C_INITIATE,
+                                              &user_cred_handle,
+                                              &actual_mechs,
+                                              NULL);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_acquire_cred_impersonate_name", major, minor);
+        goto out;
+    }
+
+    major = initAcceptSecContext(&minor,
+                                 user_cred_handle,
+                                 impersonator_cred_handle,
+                                 &delegated_cred_handle);
+    if (GSS_ERROR(major))
+        goto out;
+
+    printf("\n");
+
+    if (target != GSS_C_NO_NAME &&
+        delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
+        major = constrainedDelegate(&minor, &mechs, target,
+                                    delegated_cred_handle,
+                                    impersonator_cred_handle);
+    } else if (target != GSS_C_NO_NAME) {
+        fprintf(stderr, "Warning: no delegated credentials handle returned\n\n");
+        fprintf(stderr, "Verify:\n\n");
+        fprintf(stderr, " - The TGT for the impersonating service is forwardable\n");
+        fprintf(stderr, " - The T2A4D flag set on the impersonating service's UAC\n");
+        fprintf(stderr, " - The user is not marked sensitive and cannot be delegated\n");
+        fprintf(stderr, "\n");
+    }
+
+out:
+    (void) gss_release_name(&minor, &user);
+    (void) gss_release_name(&minor, &target);
+    (void) gss_release_cred(&minor, &delegated_cred_handle);
+    (void) gss_release_cred(&minor, &impersonator_cred_handle);
+    (void) gss_release_cred(&minor, &user_cred_handle);
+    (void) gss_release_oid_set(&minor, &actual_mechs);
+
+    return GSS_ERROR(major) ? 1 : 0;
+}
+
diff --git a/src/tests/mk_migr/db2_backend/README_for_mkmdb2 b/src/tests/mk_migr/db2_backend/README_for_mkmdb2
new file mode 100644 (file)
index 0000000..1a5cf30
--- /dev/null
@@ -0,0 +1,37 @@
+ABOUT:
+A translation of Will Fiveash's "mit_db2_mkey_migrate_testB" ksh code into Python with the default db2 backend.  With minor fixes and changes.  Written by HaoQi Li.
+
+DEFAULT SETTINGS:
+Options     Name              Default Setting
+  -h      Help
+  -v      Verbose:        True
+  -p      Testing pw:     test123
+  -s      Sandbox loc:    src/tests/mk_migr/db2_backend/sandbox
+  -c      Krb5kdc:        src/kdc/krb5kdc
+  -d      Kadmind:        src/kadmin/server/kadmind
+  -b      Kdb5_util:      src/kadmin/dbutil/kdb5_util
+  -l      Kadmin.local:   src/kadmin/cli/kadmin.local
+  -n      Kadmin:         src/kadmin/cli/kadmin
+  -t      Client paths:   src/clients
+
+INPUTS:
+* src/tests/mk_migr/db2_backend/input_conf/kdc_template_db2.conf
+* src/tests/mk_migr/db2_backend/input_conf/krb5_template_db2.conf 
+* src/tests/mk_migr/db2_backend/input_conf/kadm5_template_db2.acl
+
+OUTPUTS:
+* sandbox that contains customized outfile with all commands and their outputs, kdc.conf, krb5.conf, kadm6.acl, and others.
+* Statistics on screen of number of commands passed and failed.
+
+EXAMPLES:
+- MUST RUN from trunk/src. 
+* python tests/mk_migr/db2_backend/mkmdb2.py
+    Using all Default Settings.
+* python tests/mk_migr/db2_backend/mkmdb2.py -s /tmp/mySandbox
+    Sandbox now can be found in /tmp/mySandbox.  
+
+
+# Notes:
+# Exists only at the end, unless fatal errors are encountered.  Otherwise, skips errors and continue!!
+# "haoqili" is a name that can be changed.
+# 2019 and 2029 are future dates that should best be written not as fixed. Such as now+10years.
diff --git a/src/tests/mk_migr/db2_backend/input_conf/kadm5_template_db2.acl b/src/tests/mk_migr/db2_backend/input_conf/kadm5_template_db2.acl
new file mode 100644 (file)
index 0000000..719677a
--- /dev/null
@@ -0,0 +1 @@
+*/admin *
diff --git a/src/tests/mk_migr/db2_backend/input_conf/kdc_template_db2.conf b/src/tests/mk_migr/db2_backend/input_conf/kdc_template_db2.conf
new file mode 100644 (file)
index 0000000..31ff522
--- /dev/null
@@ -0,0 +1,14 @@
+[kdcdefaults]
+       kdc_ports = 8888
+
+[realms]
+       K.MIT.EDU = {
+               database_name = %(sandboxdir)s/principal
+               acl_file = %(sandboxdir)s/kadm5.acl
+               key_stash_file = %(sandboxdir)s/keyStashFile
+               kdc_ports = 8888
+               kpasswd_port = 8887
+               kadmind_port = 8886
+               max_life = 10h 0m 0s
+               max_renewable_life = 7d 0h 0m 0s
+       }
diff --git a/src/tests/mk_migr/db2_backend/input_conf/krb5_template_db2.conf b/src/tests/mk_migr/db2_backend/input_conf/krb5_template_db2.conf
new file mode 100644 (file)
index 0000000..e89aa87
--- /dev/null
@@ -0,0 +1,21 @@
+[libdefaults]
+       default_realm = K.MIT.EDU
+
+[realms]
+# use "kdc = ..." if realm admins haven't put SRV records into DNS
+       K.MIT.EDU = {
+               admin_server = %(localFQDN)s:8886
+               kpasswd_server = %(localFQDN)s:8887
+               default_domain = MIT.EDU
+               kdc = %(localFQDN)s:8888
+               v4_instance_convert = {
+                       mit = mit.edu
+                       lithium = lithium.lcs.mit.edu
+               }
+       }
+       ANDREW.CMU.EDU = {
+               admin_server = vice28.fs.andrew.cmu.edu
+       }
+
+[logging]
+#      kdc = CONSOLE
diff --git a/src/tests/mk_migr/db2_backend/mkmdb2.py b/src/tests/mk_migr/db2_backend/mkmdb2.py
new file mode 100644 (file)
index 0000000..00ae4cb
--- /dev/null
@@ -0,0 +1,808 @@
+# Master Key Migration for db2
+
+import os, sys, shutil, socket, time, string
+from subprocess import Popen, PIPE
+from optparse import OptionParser
+from time import strftime
+
+class MasterKeyMigrationTest:
+    def __init__(self, verbose_in, pw_in,  kdcPath_in, kdmdPath_in, kdbPath_in, kdmlPath_in, kdmPath_in, cltPath_in, sandir_in):
+        self.npass = 0
+        self.nfail = 0
+
+        self.verbose = verbose_in
+        self.pw = pw_in
+
+        self.krb5kdc = kdcPath_in #1 krb5kdc
+        self.kadmind = kdmdPath_in #2 kadmind
+        self.kdb5_util = kdbPath_in #3 kdb5_util
+        self.kadminlocal = kdmlPath_in #4 kadmin.local
+        self.kadmin = kdmPath_in #5 kadmin
+        self.clients = cltPath_in+"/" #6 clients
+
+        self.sandir = sandir_in
+
+        ########## SET UP Write Output File #####
+        self.outfile = open(self.sandir+"/outfile", 'w')
+
+        '''print os.environ'''
+
+    def _writeLine(self, astr, prt=False):
+        self.outfile.write(astr.strip()+"\n")
+        if prt:
+            print astr.strip()
+
+    def _writeHeader(self, astr, prt=True):
+        self.outfile.write("\n========== "+astr.strip()+" ==========\n")
+        if prt:
+            print "========== "+astr.strip()+" =========="
+    
+    def _sysexit(self, fatal=False, finished=False):
+        self._writeLine("++++++++++++++++++++++++++++++", True)
+        if fatal:
+            self._writeLine("++++ Test did NOT finish +++++", True)
+            self._writeLine("++++ FATAL FAILURE! Stopped ++", True)
+            self._writeLine("++++ See sandbox/outfile +++++", True)
+            self._writeLine("++++++++++++++++++++++++++++++", True)
+            sys.exit()
+        elif not finished:
+            self._writeLine("++++ Test did NOT finish +++++", True)
+            self._writeLine("++++ FAIL Detected! keep going", True)
+            self._writeLine("++++++++++++++++++++++++++++++", True)
+        else: #finished
+            self._writeLine("++++ MKM Test Finished +++++++", True)
+            self._writeLine("++++++++++++++++++++++++++++++", True)
+            self._writeLine("++++ Commands Passed: %s +++++" % self.npass, True)
+            self._writeLine("++++ Commands Failed: %s +++++" % self.nfail, True)
+            sys.exit()
+        
+    def _printig(self):
+        self._writeLine("~.~.~Error should be ignored~.~.~.~")
+
+    def _printerr(self, errm, stderr):
+        self._writeLine("#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#")
+        self._writeLine("-XX-FAILED: "+errm+". See stderr below:")
+        [self._writeLine(line) for line in stderr.readlines() ]
+
+    def _printout(self, cmd, pstdout):
+        if self.verbose:
+            self._writeLine("---------------------------------------")
+            self._writeLine("-command: "+cmd)
+            self._writeLine("-----out: ")
+            [self._writeLine(line) for line in pstdout.readlines()]
+
+    def _eval(self, succeed, pwait, errm, pstderr, fatal=False, msg2="", finished=False):
+        if int(pwait) != 0: # is bad
+            self._printerr(errm, pstderr)
+            if succeed==True: ## want good
+                self.nfail += 1
+                self._sysexit(fatal, finished)
+            else: ## want bad
+                self.npass += 1
+                self._printig()
+        else: # is good
+            if not succeed: ## want bad
+                if msg2 != "":
+                    self._writeLine(msg2, True)
+                self.nfail += 1
+                self._sysexit(fatal, finished)
+            else: ## want good
+                self.npass += 1 
+
+    def _metafunc(self, command,  errmsg, moreinfo="", isLocal=False, succeed=True, fatal=False):
+        l = command
+        if isLocal:
+            pl = Popen(l.split(None,2), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+        else:
+            pl = Popen(l.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+        self._printout(l+moreinfo, pl.stdout)
+        
+        self._eval(succeed, pl.wait(), errmsg, pl.stderr, fatal)
+    
+    ###########################################
+
+    # Start the KDC daemons
+    def _startkdc(self):
+        self._writeLine("\nstarting kdc daemons ...")
+        l0 = self.krb5kdc
+        errm = "error at starting krb5kdc"
+        self._metafunc(l0, errm)
+        # below has been changed
+        l0b = self.kadmind + ' -W -nofork' #the W is for during off strong random numbers
+        errm = "error at starting kadmind, maybe it's already started"
+        pl0b = Popen(l0b.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+        self._writeLine( "kadmind -nofork")
+        started = False
+        while time.clock() < 3:
+            l = pl0b.stderr.readline()
+            if l.find("starting") > -1:
+                self._writeLine( l.strip())          
+                self.npass += 1
+                started = True
+                break  
+        else:
+            self.nfail += 1
+            self._printerr("kadmind not starting, check to see if there are any previous kadmind running with cmd: 'ps -ef | grep kadmind' and then do 'sudo kill -9 [# on the left]'", pl0b.stderr)
+            self._sysexit(fatal=True)
+        if not started:
+            self.nfail += 1
+            self._sysexit()
+        self._writeLine("end starting kdc daemons")
+
+    # Kill the KDC daemons in case they are running
+    def _killkdc(self, suc=True):
+        l1 = 'pkill -9 -x krb5kdc'
+        errm = "no krb5kdc killed"
+        self._metafunc(l1, errm, succeed=suc)
+        
+        l2 = 'pkill -9 -x kadmind'
+        errm = "no kadmind killed"
+        self._metafunc(l2, errm, succeed=suc)
+
+    # Destroys current database
+    def _destroykdc(self, suc=True):
+        l3 = self.kdb5_util+' destroy -f' #forced
+        errm = "no kdb database destroyed"
+        self._metafunc(l3, errm, succeed=suc)
+
+    # Create a new database with a new master key
+    def _createdb(self, pw):
+        l4 = self.kdb5_util+' -P '+pw+' create -s -W' #added W for svn version 22435 to avoid reading strong random numbers
+        errm = "error when creating new database, _createdb()"
+        self._metafunc(l4, errm, fatal=True)
+
+    # Addprinc
+    def _locAddprinc(self, passw, usern):
+        l5 = self.kadminlocal+' -q addprinc -pw '+passw+' '+usern
+        errm = "error when adding princ, _locAddprinc"
+        self._metafunc(l5, errm, isLocal=True)
+
+    # List princs
+    def _locListprincs(self):
+        l6 = self.kadminlocal+' -q listprincs'
+        errm = "error when listing princs, _locListprincs"        
+        self._metafunc(l6, errm, isLocal=True)
+
+    #  Get princs
+    def _locGetprinc(self, usern, extra=False, succeed=True):
+        l7 = self.kadminlocal+' -q getprinc '+usern
+        errm="error when getting princ, _locGetprinc"
+
+        pl7 = Popen(l7.split(None,2), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+        if not extra:
+            self._printout(l7, pl7.stdout)
+        else:
+            if self.verbose:
+                self._writeLine("-command: "+l7)
+                self._writeLine("-----out: ")
+                for line in pl7.stdout.readlines():
+                    if line.startswith("Princ") or line.startswith("MKey"):
+                        self._writeLine(line)
+        self._eval(succeed, pl7.wait(), errm, pl7.stderr)
+
+    # Get princs and finds something in the output
+    def _locGetprincFind(self, usern, findstr, succeed=True):
+        l7b = self.kadminlocal+' -q getprinc ' +usern
+        errm="error when getting princs, _locGetprinc, (regular output of getprincs is not printed here), will NOT continue to find string="+findstr
+        pl7b = Popen(l7b.split(None, 2), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+        if self.verbose:
+            self._writeLine("-command: "+l7b)
+        if int(pl7b.wait()) != 0: # is bad
+            self._printerr(errm, pl7b.stderr)
+            if succeed: ## want good
+                self.nfail += 1
+                self._sysexit()
+            else: ## want bad
+                self.npass += 1
+                self._printig()
+        else: # is good
+            if self.verbose:            
+                self._writeLine( "-----out: ")
+            boofound = False
+            for outl in pl7b.stdout.readlines():
+                self._writeLine(outl)
+                if string.find(outl, findstr) > -1:
+                    boofound = True
+            if boofound:
+                self._writeLine("----FOUND: "+findstr)
+            else:
+                self._writeLine("----NOT FOUND: "+findstr)
+            if not succeed: ## want bad
+                self.nfail += 1
+                self._sysexit()
+            else: ## want good
+                self.npass += 1
+
+    # Add policy
+    def _locAddpol(self, maxtime, minlength, minclasses, history, policyname):
+        rest = ""
+        if maxtime != None:
+            rest += '-maxlife '+maxtime+' '
+        if minlength != None:
+            rest += '-minlength '+minlength+' '
+        if minclasses != None:
+            rest += '-minclasses '+minclasses+' '
+        if history != None:
+            rest += '-history '+history+' '
+        l8 = self.kadminlocal+' -q add_policy '+rest+policyname
+        errm = "error when adding policy, _locAddpol"
+        self._metafunc(l8, errm, isLocal=True)  
+
+    #  Get pol
+    def _locGetpol(self, poln):
+        l8b = self.kadminlocal+' -q getpol '+poln
+        errm="error when getting pol, _locGetpol"
+        self._metafunc(l8b, errm, isLocal=True)
+
+    # Modify Principal
+    def _locModprinc(self, rest):
+        l9 = self.kadminlocal+' -q modprinc '+rest
+        errm = "error when modifing principal, _locModprinc"
+        self._metafunc(l9, errm, isLocal=True)
+
+    # List mkeys
+    def _listmkeys(self):
+        l10 = self.kdb5_util+' list_mkeys'
+        errm = "error when listing mkeys, _listmkeys"
+        self._metafunc(l10, errm)
+
+    # Use mkeys
+    def _usemkey(self, kvno, time, succeed=True):
+        l11 = self.kdb5_util+' use_mkey '+kvno+' '+time
+        pl11 = Popen(l11.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+        self._printout(l11, pl11.stdout)
+        self._eval(succeed, pl11.wait(), "error when using mkeys, _usemkey", pl11.stderr, msg2="-XX-ERROR: "+l11+" should have failed.")        
+
+        
+    # Change password (cpw)
+    def _locCpw(self, passw, usern):
+        l12 = self.kadminlocal+' -q cpw -pw '+passw+' '+usern
+        errm = "error when changing password, _locCpw"
+        self._metafunc(l12, errm, moreinfo="\n--------: newpw='"+passw+"'", isLocal=True)
+
+    # Purge mkeys
+    def _purgemkeys(self):
+        l13 = self.kdb5_util+' purge_mkeys -f -v' #-f is forced, -v is verbose
+        errm = "error when purging mkeys, _purgemkeys"
+        self._metafunc(l13, errm)
+
+    # Add mkey
+    def _addmkey(self, passw, extra="", succeed=True):
+        l14 = self.kdb5_util+' add_mkey '+extra
+        pl14 = Popen(l14.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE) 
+        pl14.stdin.write(passw+'\n') #enter 1st time
+        pl14.stdin.write(passw+'\n') #re-enter    
+        self._printout(l14+' [with password='+passw+']', pl14.stdout)
+        self._eval(succeed, pl14.wait(), "error when adding mkey, _addmkey", pl14.stderr)
+        self._writeLine( "----end of adding mkey")
+
+    # kinit user
+    def _kinit(self, passw_in, usern, succeed=True):
+        l15 = self.clients+'kinit/kinit '+usern
+        pl15 = Popen(l15.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+        pl15.stdin.write(passw_in+'\n')
+        pl15.stdin.close()
+        self._printout(l15, pl15.stdout)
+        self._eval(succeed, pl15.wait(), "error when kinit user, _kinit", pl15.stderr)
+        self._writeLine( "----end of kiniting user")
+
+    # change password on client's side
+    def _kpasswd(self, oldpw, newpw, usern, succeed=True):
+        l16 = self.clients+'kpasswd/kpasswd '+usern
+        pl16 = Popen(l16.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+        pl16.stdin.write(oldpw+'\n')
+        pl16.stdin.write(newpw+'\n')
+        pl16.stdin.write(newpw+'\n')
+        self._printout(l16+"\n--------: oldpw='"+oldpw+"' -> newpw='"+newpw+"'", pl16.stdout)
+        self._eval(succeed, pl16.wait(), "error when changing password on client's side, _kpasswd", pl16.stderr)
+        self._writeLine("----end of changing kpasswd")
+
+    # klist on client's side
+    def _klist(self):
+        l17 = self.clients+'klist/klist'
+        errm = "error when klist, _klist"
+        self._metafunc(l17, errm)
+
+    # Update principal encryption
+    def _updatePrincEnc(self):
+        l18 = self.kdb5_util+' update_princ_encryption -f -v'
+        errm = "error when updating principal encryption, _updatePrincEnc"
+        self._metafunc(l18, errm)
+
+    # kdestroy
+    def _kdestroy(self):
+        l19 = self.clients+'kdestroy/kdestroy'
+        errm = "error when kdestroy, _kdestroy"
+        self._metafunc(l19, errm)
+
+    # stash
+    def _stash(self):
+        l20 = self.kdb5_util+' stash'
+        errm="error at stash, _stash"
+        self._metafunc(l20, errm)
+
+    # any shell command
+    def _shell(self, command, succeed=True):
+        l21 = command
+        errm="error at executing this command in _shell(): "+l21
+        pl21 = Popen(l21, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
+        self._printout(l21, pl21.stdout)
+        self._eval(succeed, pl21.wait(), errm, pl21.stderr)
+        '''self._printerr(errm, pl21.stderr)  Pointed out that kadmin had problems!'''
+
+    # get_princ_records()
+    def _get_princ_records(self, succeed=True):
+        l22 = self.kadminlocal+" -q listprincs 2>/dev/null|grep -v '^Authenticating as'|fgrep '@'|sort"
+        errm="error at listprincs in _get_princ_records() with this command: "+l22
+        pl22 = Popen(l22, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
+        if int(pl22.wait()) != 0: # is bad
+            self.printerr(errm, pl22.stderr)
+            if succeed: ## want good
+                self.nfail += 1
+                self._sysexit()
+            else: ## want badd
+                self.npass += 1
+                self._printig()
+        else: # is good
+            if not succeed: ## want bad
+                self.nfail += 1
+                self._sysexit()
+            else: ## want good
+                self.npass += 1
+                self._writeLine( "\nget_princ_records() executing all listprincs command: "+l22+"\n------its results:")
+                for princ in pl22.stdout.readlines():
+                    self._locGetprinc(princ.strip(), extra=True)
+                self._writeLine("END executing command: "+l22+"\n~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~")
+        
+######################################################
+    def run(self):
+        #############RUN###################
+        passw=self.pw        
+    
+        self._writeHeader("START MASTER KEY MIGRATION TEST")        
+
+        # Set up database
+        self._writeHeader("SET UP: database")
+        self._killkdc("Either") #74 =1,2
+        self._destroykdc("Either") #77 =3
+        self._createdb(passw) #81 =4
+        #line 83-86 involves ktadd kadm5.keytab, which are out dated
+        
+        # add, get, and list princs
+        self._writeHeader("SET UP: add/get/list princs")        
+        self._locAddprinc(passw, 'kdc/admin') #87 =5
+        self._locListprincs() #89 =6
+        self._locGetprinc('K/M') #90 =7
+        self._locAddprinc('test123', 'haoqili') #91 =8
+        self._locGetprinc('haoqili') #92 =9
+        self._locAddprinc(passw, 'haoqili/admin') #93 =10
+        self._locAddprinc('foobar', 'test') #94 =11
+        self._locGetprinc('test') #95 =12
+        self._locListprincs() # I added =13
+        myfqdn = socket.getfqdn()
+        #self._shell(self.parentpath+"kadmin.local -q 'addprinc -randkey host/"+myfqdn+"'") #96
+        self._shell(self.kadminlocal+" -q 'addprinc -randkey host/"+myfqdn+"'") #96 =14
+        
+        # create policies
+        self._writeHeader("SET UP: create policies")
+        #print "\n~~~~~~~~~ create policies ~~~~~~~~~~~"
+        self._locAddpol('8days', None, None, None, 'testpolicy')#100 =15
+        self._locAddpol('20days', '8', '3', None,  'testpolicy2')#101 
+        self._locAddpol('90days', '2', '2', None,  'testpolicy3')#102
+        self._locAddpol('90days', '2', '2', '3', 'testpolicy4')#103
+            
+        self._locModprinc('-policy testpolicy haoqili')#105
+        self._locAddprinc(passw, 'foo')#106
+        self._locModprinc('-policy testpolicy3 foo')#107 =21
+        
+        # create all princ with all fields
+        self._writeHeader("SET UP: create all princ with all fields")
+        #print "\n~~~~~~~~~ create all princ with all fields ~~~~~"
+        self._locAddprinc(passw, 'all') #110 =22
+        self._locModprinc('-expire "2029-12-30 7pm" all') #112
+        self._locModprinc('-pwexpire 12/30/2029 all') #114
+        self._locGetprinc('all') #115
+        self._locModprinc('-maxlife 100days all') #116
+        self._locGetprinc('all') #117
+        self._locModprinc('-maxrenewlife 100days all') #118
+        self._locGetprinc('all') #119
+        self._locModprinc('+allow_postdated +allow_forwardable all') #120 =30
+        self._locModprinc('+allow_proxiable +allow_dup_skey all') #121
+        self._locModprinc('+requires_preauth +allow_svr +needchange all') #122
+        self._locModprinc('-policy testpolicy4 all') #123
+        self._locGetprinc('all') #124 =34
+        
+        # Testing stuff
+        self._writeHeader("TEST: initial mkey list") #126
+        self._writeLine("===== Listing mkeys at start of test") #I add
+        self._listmkeys() #127 =35
+        
+        self._writeLine( "Testing krb5kdc list_mkeys Done ==============================================") #128
+
+        self._writeLine("---------------\n xxxxxxxxxx \/\/\/ ERRORS (multiple) EXPECTED below xxxxxxxxxx")
+        self._writeLine("\nERRORS (multiple) EXPECTED below") 
+        self._writeLine("Testing bogus use_mkey (setting only mkey to future date, using non-existent kvno, so should return error) =======") #129, 130
+        self._writeLine( "-> must have a mkey currently active (setting mkey to 2 days from now), should fail and return error") #132     
+        self._usemkey('1', 'now+2days', False) #133-138 =36
+        
+        self._writeLine("-> must have a mkey currently active (setting mkey to 2019 the future), should fail and return error") #140
+        self._usemkey('1', '5/30/2019', False) #141 =37
+        self._writeLine("-> bogus kvno and setting mkey to 2 days from now, should fail and return error") #147
+        self._usemkey('2', 'now+2days', False) #148 =38
+        self._writeLine("-> bogus kvno, should fail and return error") #I add
+        self._usemkey('2', 'now-2days', False) #I add =39
+        self._writeLine( "^^^ABOVE^^ SHOULD HAVE *ALL* FAILED\n-----------------")
+
+        self._writeLine( "Listing mkeys at end of test") #I add
+        self._listmkeys() #155 =40
+        self._writeLine("Testing bogus use_mkey (setting only mkey to future date) Done ===========================") #156
+        
+        
+        self._writeLine("\nmake sure cpw [change password] works") #158
+        # this changes the password of 'test' from 'foobar' in "add, get, and list princs" above
+        self._locCpw('test1', 'test') #159 =41
+
+        self._writeHeader("TEST: bogus purge_mkeys (should be no keys purged, no error returned")
+        #print "\nTesting bogus purge_mkeys (should be no keys purged, no error returned) ===========================" #161
+        self._purgemkeys() #162 =42
+        self._writeLine("Testing bogus purge_mkeys (no error) Done ===========================") #163
+        
+        self._writeLine( "\nadd kvno 2") #164
+        self._addmkey('abcde', '-s') #165-167 =43
+        self._writeLine("\nlist mkeys")
+        self._listmkeys() #169 =44
+        
+        #start daemons
+        self._startkdc() #172 =45 46
+        self._writeLine("make sure kdc is up, by kinit test") #176
+        self._kinit('test1', 'test') #177 =47
+        
+        self._writeLine("---------------\n\/\/\/ ERROR EXPECTED below.  Test passwd policy.:") #180
+        self._kinit(passw, 'all', succeed=False) #181 =48
+        self._writeLine("^^ABOVE^^ SHOULD HAVE FAILED\n-----------------")
+        
+        #change passwd on client's side
+        self._kpasswd(passw, 'Test123.', 'all')#184-188 =49
+
+        self._kinit('Test123.', 'all') #189 =50
+        self._klist() #190 =51
+        
+        self._writeHeader("TEST: password history for principal 'all', new passwords must not be a previous password") #191
+        self._kpasswd('Test123.', 'Foobar2!', 'all') #192-195 =52
+        self._writeLine("--------------\n\/\/\/ ERROR EXPECTED below") #197
+        self._kpasswd('Foobar2!', passw, 'all', succeed=False) #199-202 =53
+        self._writeLine("^^^ABOVE^^ SHOULD HAVE FAILED\n----------")
+        
+        # this shouldn't change the mkvno for any princs (should be 1) #206
+        #self._updatePrincEnc() #207
+        # princs should still be protected by mkvno 1 #208
+        self._writeLine("@@@@@@@@ Wait for other people to fix bug in code 6507 update_princ_encryption to use mkey instead of latest mkey @@@@@@@@@@@@@\n")
+        self._locGetprincFind('test', 'MKey: vno 1') #209 =54
+               
+        self._purgemkeys() #210 =55   
+        self._listmkeys() #211 =56
+        self._usemkey('2', 'now-1day') #213 =57
+        self._listmkeys() #214 =58
+        
+        self._writeLine("-----------\n\/\/\/ ERROR EXPECTED below") #216
+        self._kpasswd('Foobar2!', passw, 'all', succeed=False) #217-221 =59
+        self._writeLine("^^^ABOVE^^ SHOULD HAVE FAILED\n--------") 
+        
+        self._kpasswd('Foobar2!', 'Barfoo3.', 'all') #224-228 =60
+        self._kinit('Barfoo3.', 'all') #229
+        self._klist() #230 =62
+        
+        self._writeLine("-------------\n\/\/\/ ERROR EXPECTED below") #231
+        self._kpasswd('Barfoo3.', 'Foobar2!', 'all',succeed=False) #233-235 =63
+        self._writeLine("^^^ABOVE^^ SHOULD HAVE FAILED\n---------")
+        
+        self._writeLine("\nTest's key should be protected by mkvno 2" ) #239
+        self._locCpw('foo', 'test') #240 =64
+        self._locGetprincFind('test', 'MKey: vno 2') #241 =65
+        self._kdestroy() #242 =66
+        
+        self._writeHeader("TEST: krb5kdc refetch of mkey")#243
+        self._kinit('foo', 'test') #244 =67
+        self._klist() #245 =68
+        self._writeLine("END. Testing krb5kdc refetch of mkey list Done ==============================================\n")     #246
+        
+        self._updatePrincEnc() #247 =69
+        self._get_princ_records() #248 =70 -83
+        self._kdestroy() #249 =84
+        self._kinit('foo', 'test') #250 =85
+        self._purgemkeys() #252 =86
+        
+        self._stash() #254 =87
+        self._shell(self.clients+'klist/klist' +" -ekt "+self.sandir+"/keyStashFile") #255 =88
+        
+        self._locGetprinc('K/M') #256 =89
+        self._purgemkeys() #257 =90
+        self._locGetprinc('K/M') #258
+        self._listmkeys() #259 =92
+        self._kdestroy() #260
+        self._kinit('foo', 'test') #261
+        self._klist() #262 =95
+   
+        self._writeLine("\n Adding in Master Key Number 3")
+        self._listmkeys() #265 =96
+        self._addmkey('abcde') #266-268
+        self._listmkeys() #270 =98
+        self._locCpw('foo', 'all') #271
+        self._locGetprinc('all') #272 =100
+        self._usemkey('3', 'now') #273
+        self._listmkeys() #274 =102
+        self._locCpw('99acefghI0!', 'all') #275
+        self._locGetprinc('all') #276 =104
+        self._kdestroy() #277
+        self._kinit('foo', 'test') #279 =106
+        self._klist() #280
+        self._shell(self.kadmin+" -p haoqili/admin -w "+passw+" -q 'listprincs'") #281 =108
+        self._shell(self.kadmin+" -p haoqili/admin -w "+passw+" -q 'getprinc test'") #282 =109
+        
+        self._writeHeader("TEST: add_mkey with aes128 enctype") #283      
+        self._addmkey('abcde', '-e aes128-cts-hmac-sha1-96') #284-287 =110
+        self._listmkeys() #288 =111
+        
+        self._writeLine( "END. Testing add_mkey with aes128 enctype done ==============================================")#289     
+
+        self._writeHeader("TEST: krb5kdc refetch of mkey list")
+        self._usemkey('4', 'now') #290 =112
+        self._listmkeys() #291 =113
+        self._shell(self.kadmin+" -p haoqili/admin -w "+passw+" -q 'cpw -pw abcde test'") #292 =114
+        self._shell(self.kadmin +" -p haoqili/admin -w "+passw+" -q 'getprinc test'") #293
+        self._kdestroy() #294 =116
+
+        self._writeLine("\nTesting krb5kdc refetch of mkey list =================================================") #295
+        self._kinit('abcde', 'test') #296 =117
+        #'self._klist() #297 =118
+        self._writeLine("Testing krb5kdc refetch of mkey list Done :) =================================================\n") #298
+
+        self._killkdc() #300 =119, 120
+        self._startkdc() #301 =121 122
+        self._shell("kadmin -p haoqili/admin -w "+passw+" -q 'cpw -pw foo test'") #304 =123
+        self._shell("kadmin -p haoqili/admin -w "+passw+" -q 'getprinc test'") #305 =124
+        self._kdestroy() #307 =125
+
+        self._writeLine("\nTesting krb5kdc refetch of mkey list =================================================") #308
+        self._kinit('foo', 'test') #309 =126
+        self._klist() #310 =127
+        self._writeLine("Testing krb5kdc refetch of mkey list Done =================================================\n") #311
+        
+        self._updatePrincEnc() #313 =128
+        self._locGetprinc('K/M') #314
+        self._locGetprinc('all') #315 =130
+        self._locGetprinc('haoqili') #316
+        self._kdestroy() #317 =132
+        self._kinit('foo', 'test') #318
+        self._stash() #319 =134
+        self._shell(self.clients+'klist/klist' + " -ekt "+self.sandir+"/keyStashFile") #320
+        self._locGetprinc('K/M') #321 =136
+        self._purgemkeys() #322
+        self._locGetprinc('K/M') #323 =138
+        self._locGetprinc('all') #324
+        self._shell("kadmin -p haoqili/admin -w "+passw+" -q 'getprinc test'") #325 =140
+        self._listmkeys() #326
+        self._kdestroy() #327 =142
+        self._kinit('foo', 'test') #328
+        self._klist() #329 =144
+        
+        self._get_princ_records() #330 =145-158
+        
+        self._writeHeader("TEST: add_meky with DES-crc enctype")
+        #print "\nTesting add_mkey with DES-crc enctype ==============================================" #331
+        self._addmkey('abcde', '-e des-cbc-crc') #332-335 =159
+        self._listmkeys() #336 =160
+        self._writeLine( "END. Testing add_mkey with DES-crc enctype Done ==============================================") #337
+        self._addmkey('abcde') #338-341 =161
+        self._listmkeys() #342 =162
+        self._writeLine( "current time: "+strftime("%Y-%m-%d %H:%M:%S") ) #343
+        
+        self._usemkey('5', 'now-1day') #344 =163
+        self._writeLine("current time: "+strftime("%Y-%m-%d %H:%M:%S") )#345
+        self._listmkeys() #346 =164
+        self._usemkey('5', 'now') #347 =165
+        self._writeLine("current time: "+strftime("%Y-%m-%d %H:%M:%S") )#348
+        self._listmkeys() #349 =166
+        self._usemkey('5', 'now+3days') #350 =167
+        self._writeLine("current time: "+strftime("%Y-%m-%d %H:%M:%S") )#351
+        self._listmkeys() #352 =168
+        self._writeLine("current time: "+strftime("%Y-%m-%d %H:%M:%S") )#353
+        self._usemkey('5', 'now+5sec') #354 =169
+        self._listmkeys() #355 =170
+        time.sleep(5) #356
+        self._listmkeys() #357 =171
+        self._writeLine("current time: "+strftime("%Y-%m-%d %H:%M:%S") )#358
+        self._usemkey('4', 'now+5sec') #359 =172
+        self._listmkeys() #360 =173
+        time.sleep(5) #361
+        self._listmkeys() #362 =174
+        self._usemkey('5', 'now+3days') #363 =175
+
+        self._writeLine("------------\n\/\/\/ ERROR EXPECTED below" )#364
+        self._writeLine("should fail, because there must be one mkey currently active") #365
+        self._usemkey('4', 'now+2days', False) #366 =176
+        self._writeLine("^^^ABOVE^^ SHOULD HAVE FAILED\n---------------")
+
+        self._listmkeys() #373 =177
+        self._usemkey('4', '1/30/2009') #375 =178
+        
+        self._writeHeader("TEST: purge_mkeys (removing mkey 5)")
+        #print "\nTesting purge_mkeys (removing mkey 5) ==============================================" #378
+        self._purgemkeys() #379 =179
+        self._stash() #380 =180
+        self._shell(self.clients+'klist/klist' +" -ekt "+self.sandir+"/keyStashFile") #381 =181
+        self._listmkeys() #382 =182
+        self._shell("kadmin -p haoqili/admin -w "+passw+" -q 'getprinc K/M'") #383 =183
+        self._writeLine("Testing purge_mkeys Done ==============================================") #384
+        self._writeHeader("MASTER KEY MIGRATION TEST DONE. please consult 'outfile' in your sandbox for more info.  The sandbox is at: %s" % self.sandir) 
+ # I added
+        self._sysexit(finished=True)
+        
+####################################################
+####################################################
+
+class Launcher:
+    def __init__(self, path, sandP):
+        # srcdir, self._buildDir = InPath
+        self._buildDir = path
+        # self._confDir = InPath/tests/mk_migr/input_conf
+        self._confDir = '%s/tests/mk_migr/db2_backend/input_conf' % self._buildDir
+    
+        # setting up sand box
+        if sandP != "":
+            self._sandboxDir = sandP
+        else:
+            self._sandboxDir = '%s/tests/mk_migr/db2_backend/sandbox' % self._buildDir
+
+        self._vars = {'srcdir': self._buildDir,
+                      'sandboxdir': self._sandboxDir,
+                      'localFQDN':socket.getfqdn()}     
+
+    def _prepSandbox(self):
+        sandir = self._sandboxDir
+        if os.path.exists(sandir):
+            shutil.rmtree(sandir)
+        print "------about to make sandbox, with the path of:"
+        print sandir
+        os.makedirs(sandir, 0777)
+        print "------sandbox made"
+        return sandir
+
+    def _createFileFromTemplate(self, outpath, template, vars):
+        fin = open(template, 'r')
+        result = fin.read() % vars
+        fin.close()
+        fout = open(outpath, 'w')
+        fout.write(result)
+        fout.close()
+
+    ####### Launcher RUN ################
+    def runLauncher(self):
+        # create sandbox file directory if it does not exit
+        sandir = self._prepSandbox()
+        '''print os.environ
+        '''
+        #save the initial 3 things setup
+        orig_libpath = os.getenv('LD_LIBRARY_PATH')
+        orig_krbconf = os.getenv('KRB5_CONFIG')
+        orig_kdcprof = os.getenv('KRB5_KDC_PROFILE')
+
+        # change the 3 things
+        os.environ["LD_LIBRARY_PATH"] = '%s/lib' % self._buildDir
+        #os.environ["SRCDIR"] = '%s' % self._buildDir
+
+        str1 = '%s/krb5.conf' % self._sandboxDir
+        os.environ["KRB5_CONFIG"] = str1
+
+        str2 = '%s/kdc.conf' % self._sandboxDir
+        os.environ["KRB5_KDC_PROFILE"] = str2
+
+        str3 = '%s/kadm5.acl' % self._sandboxDir    
+
+        # Create adequate to the environment config files
+        self._createFileFromTemplate('%s' % str1, '%s/%s' % (self._confDir, 'krb5_template_db2.conf'), self._vars)
+        self._createFileFromTemplate('%s' % str2, '%s/%s' % (self._confDir, 'kdc_template_db2.conf'), self._vars)
+        self._createFileFromTemplate('%s' % str3, '%s/%s' % (self._confDir, 'kadm5_template_db2.acl'), self._vars)
+
+        return sandir
+
+####################################################
+####################################################
+def makeBool(aStr):
+    if aStr == "True" or aStr == "T":
+        return True
+    if aStr == "False" or aStr == "F":
+        return False
+    else:
+        print "did NOT execute due to invalid True False argument.  Please enter either 'True', 'T', 'False', or 'F'"
+        sys.exit()
+
+# # # # # # # # # # # # # # # # # # # # # # # # #
+
+def processInputs(parser):
+    # get inputs
+    (options, args) = parser.parse_args()
+
+    verbose = makeBool(options.opVerbose)
+    pw = options.opPassword
+
+    kdcPath = options.opKdcPath #1
+    kdmdPath = options.opKdmdPath #2
+    kdbPath = options.opKdbPath #3
+    kdmlPath = options.opKdmlPath #4
+    kdmPath = options.opKdmPath #5
+    cltPath = options.opCltPath #6
+
+    sandPath = options.opSandbox
+
+    ########### Launch ###############
+
+    print "\n############ Start Launcher #############"    
+    src_path=os.environ["PWD"]
+    print "SOURCE PATH ==>" , src_path
+
+    myLaunch = Launcher(src_path, sandPath)
+    sandir = myLaunch.runLauncher()
+
+    test = MasterKeyMigrationTest(verbose, pw,  kdcPath, kdmdPath, kdbPath, kdmlPath, kdmPath, cltPath, sandir)
+    print "########## Finished Launcher ############\n"
+
+    return test
+# # # # # # # # # # # # # # # # # # # # # # # # #
+
+def makeParser():
+    usage = "\n\t%prog [-v][-p][-c][-d][-b][-l][-t][-s]"
+    description = "Description:\n\tTests for the master key migration commands."
+    parser = OptionParser(usage=usage, description=description)
+
+    parser.add_option("-v", "--verbose",  type="string", dest="opVerbose", 
+default="True", help="'True' or 'False'.  Switch on for details of command lines and outputs.  Default is 'True'")
+
+    parser.add_option("-p", "--password",  type="string", dest="opPassword",  default="test123", help="master password for many of the passwords in the test. Default is 'test123'")
+
+    ## Default Paths
+    dSrcPath = src_path=os.environ["PWD"]
+    dKdcPath = '%s/kdc/krb5kdc' % dSrcPath #1    
+    dKdmdPath = '%s/kadmin/server/kadmind' % dSrcPath #2   
+    dKdbPath = '%s/kadmin/dbutil/kdb5_util' % dSrcPath #3
+    dKdmlPath = '%s/kadmin/cli/kadmin.local' % dSrcPath #4
+    dKdmPath = '%s/kadmin/cli/kadmin' % dSrcPath #5
+    dCltPath = '%s/clients' % dSrcPath #6
+
+    parser.add_option("-c", "--krb5kdcpath",
+type="string", dest="opKdcPath", 
+default=dKdcPath, help="set krb5kdc path, default="+dKdcPath) #1
+
+    parser.add_option("-d", "--kadmindpath", 
+type="string", dest="opKdmdPath", 
+default=dKdmdPath, help="set kadmind path, default="+dKdmdPath) #2
+
+    parser.add_option("-b", "--kdb5_utilpath", 
+type="string", dest="opKdbPath", 
+default=dKdbPath, help="set kdb5_util path, default="+dKdbPath) #3
+
+    parser.add_option("-l", "--kadminlocalpath", 
+type="string", dest="opKdmlPath", 
+default=dKdmlPath, help="set kadmin.local path, default="+dKdmlPath) #4
+
+    parser.add_option("-n", "--kadminpath", 
+type="string", dest="opKdmPath", 
+default=dKdmPath, help="set kadmin path, default="+dKdmPath) #5 
+
+    parser.add_option("-t", "--clientspath", 
+type="string", dest="opCltPath", 
+default=dCltPath, help="set clients path, default="+dCltPath) #6
+
+    # set up / initializing stuff for the sandbox
+    parser.add_option("-s", "--sandbox",
+type="string", dest="opSandbox",
+default="",
+help="path for the sandbox. Default is '%s/tests/mk_migr/db2_backend/sandbox' % "+dSrcPath)
+
+    return parser
+
+####################################################
+if __name__ == '__main__':
+    parser = makeParser()    
+    test = processInputs(parser)
+    result = test.run()
diff --git a/src/tests/mk_migr/ldap_backend/README_for_mkmldap b/src/tests/mk_migr/ldap_backend/README_for_mkmldap
new file mode 100644 (file)
index 0000000..1ab3cde
--- /dev/null
@@ -0,0 +1,77 @@
+##############################################################################
+###################### WARNING: DOES NOT WORK YET ############################
+##############################################################################
+
+ABOUT:
+A translation of Will Fiveash's "mit_db2_mkey_migrate_testB" ksh code into Python with ldap backend.  With minor fixes and changes.  Written by HaoQi Li.
+
+DEFAULT SETTINGS:
+Options     Name              Default Setting
+  -h      Help
+  -v      Verbose:        True
+  -p      Testing pw:     test123
+  -s      Sandbox loc:    src/tests/kdc_realm2/sandbox
+  -c      Krb5kdc:        src/kdc/krb5kdc
+  -d      Kadmind:        src/kadmin/server/kadmind
+  -b      Kdb5_util:      src/kadmin/dbutil/kdb5_util
+  -a      Kdb5_ldap_util: src/plugins/kdb/ldap/ldap_util/kdb5_ldap_util
+  -l      Kadmin.local:   src/kadmin/cli/kadmin.local
+  -n      Kadmin:         src/kadmin/cli/kadmin
+  -t      Client paths:   src/clients
+
+INPUTS:
+* src/tests/mk_migr/ldap_backend/input_conf/kdc_template_ldap.conf
+* src/tests/mk_migr/ldap_backend/input_conf/krb5_template_ldap.conf
+* src/tests/mk_migr/ldap_backend/input_conf/kadm5_template_ldap.acl
+* src/tests/mk_migr/ldap_backend/input_conf/debconfile
+
+OUTPUTS:
+* sandbox that contains customized outfile with all commands and their outputs, kdc.conf, krb5.conf, kadm6.acl, and others.
+* Statistics on screen of number of commands passed and failed (if not interrupted by fatal failures).
+
+EXAMPLES:
+- MUST RUN from trunk/src. 
+* python tests/mk_migr/ldap_backend/ldap7.py 
+    Using all Default Settings.
+* python tests/mk_migr/ldap_backend/ldap7.py  -s /tmp/mySandbox
+    Sandbox now can be found in /tmp/mySandbox. 
+
+REFERENCE:
+http://k5wiki.kerberos.org/wiki/LDAP_on_Kerberos
+and http://k5wiki.kerberos.org/wiki/User_talk:Haoqili
+
+NOTES:
+* "haoqili" is a name that can be changed.
+* "kdb5_util stash" is equivalent to "-s" in "kdb5_ldap_util create -s"
+* 2019 and 2029 are future dates that should best be written not as fixed. Such as now+10years.
+
+FAILURES:
+
+* failure in kpasswd all, ERROR:"password history principal key version mismatch while trying to change password."  This is caused by "-history 3" in testpolicy4
+
+* The beginning of a series of failures starts from: the "kdb5_util list_mkeys" fails after "kdb5_util add_mkey -e aes128-cts-hmac-sha1-96 [with password=abcde]"
+ERROR:-------------------------------------
+kdb5_util: Unable to decrypt latest master key with the provided master key
+while getting master key list
+kdb5_util: Warning: proceeding without master key list
+kdb5_util: master keylist not initialized
+can't decrypt the latest master key 
+--------------------------------------------
+Convo with Tom:
+T: so you didn't activate the new mkey?
+H: correct i just added it
+T: the message looks familiar. does list_mkeys work before you do that add_mkey?
+H: yes it does
+T: Will might have mentioned some problems with the LDAP backend and the master key migration stuff.
+T: how up-to-date is your source tree? Will says he remembers fixing this.
+H: i'm at revision 22523
+T: hm, i think that should be recent enough.
+T: do you have any enctype settings in your config files?
+H: in krb5.conf
+[libdefaults]
+default_realm = EXAMPLE.ORG
+default_tkt_enctypes = des3-hmac-sha1 aes128-cts
+default_tgs_enctypes = des3-hmac-sha1 aes128-cts
+T: anything for supported_enctypes or master_key_type?
+H: no
+
diff --git a/src/tests/mk_migr/ldap_backend/input_conf/debconfile b/src/tests/mk_migr/ldap_backend/input_conf/debconfile
new file mode 100644 (file)
index 0000000..6866e93
--- /dev/null
@@ -0,0 +1,9 @@
+slapd  slapd/no_configuration  boolean false
+slapd  slapd/domain    string  example.org
+slapd  shared/organization     string  My Organization
+slapd  slapd/backend   select  HDB
+slapd  slapd/purge_database    boolean true
+slapd  slapd/move_old_database boolean true
+slapd  slapd/password1 password a
+slapd  slapd/password2 password a
+slapd  slapd/allow_ldap_v2     boolean false
diff --git a/src/tests/mk_migr/ldap_backend/input_conf/kadm5_template_ldap.acl b/src/tests/mk_migr/ldap_backend/input_conf/kadm5_template_ldap.acl
new file mode 100644 (file)
index 0000000..719677a
--- /dev/null
@@ -0,0 +1 @@
+*/admin *
diff --git a/src/tests/mk_migr/ldap_backend/input_conf/kdc_template_ldap.conf b/src/tests/mk_migr/ldap_backend/input_conf/kdc_template_ldap.conf
new file mode 100644 (file)
index 0000000..94a82a7
--- /dev/null
@@ -0,0 +1,17 @@
+[kdcdefaults]
+        kdc_ports = 8888
+
+[realms]
+        EXAMPLE.ORG = {
+                database_name = %(sandir)s/krb5kdc/principal
+                acl_file = %(sandir)s/kadm5.acl
+                key_stash_file = %(sandir)s/krb5kdc/.k5.EXAMPLE.ORG
+                admin_keytab = FILE:%(sandir)s/krb5kdc/kadm5.keytab
+                kdc_ports = 8888
+                kpasswd_port = 8887
+                kadmind_port = 8886
+                max_life = 10h 0m 0s
+                max_renewable_life = 7d 0h 0m 0s
+        }
+[logging]
+        kdc = FILE:/tmp/myrealKDC.log
diff --git a/src/tests/mk_migr/ldap_backend/input_conf/krb5_template_ldap.conf b/src/tests/mk_migr/ldap_backend/input_conf/krb5_template_ldap.conf
new file mode 100644 (file)
index 0000000..5805f60
--- /dev/null
@@ -0,0 +1,33 @@
+[libdefaults]
+        default_realm = EXAMPLE.ORG
+        default_tkt_enctypes = des3-hmac-sha1 aes128-cts
+        default_tgs_enctypes = des3-hmac-sha1 aes128-cts
+
+[realms]
+        EXAMPLE.ORG = {
+                admin_server = %(localFQDN)s:8886
+                kpasswd_server = %(localFQDN)s:8887
+                #default_domain = EXAMPLE.ORG
+                kdc = %(localFQDN)s:8888
+                database_module = LDAP
+        }
+
+[dbdefaults]
+        ldap_kerberos_container_dn = "cn=krbContainer,dc=example,dc=org"
+
+[dbmodules]
+        LDAP = {
+        db_library = kldap
+        ldap_kerberos_container_dn = "cn=krbContainer,dc=example,dc=org"
+        ldap_kdc_dn = cn=admin,dc=example,dc=org
+        ldap_kadmind_dn = cn=admin,dc=example,dc=org
+        ldap_service_password_file = %(sandir)s/krb5kdc/admin.stash
+        ldap_servers = ldapi:///
+        }
+[domain_realm]
+
+[logging]
+        kdc = FILE:/tmp/kdc_fromkrb.log
+        default = FILE:/tmp/krb5.log
+        admin_server = FILE:/tmp/admin.log
+
diff --git a/src/tests/mk_migr/ldap_backend/mkmldap.py b/src/tests/mk_migr/ldap_backend/mkmldap.py
new file mode 100644 (file)
index 0000000..ae2b83a
--- /dev/null
@@ -0,0 +1,897 @@
+##############################################################################
+###################### WARNING: DOES NOT WORK YET ############################
+##############################################################################
+
+import os, sys, shutil, socket, time, string
+from subprocess import Popen, PIPE
+from optparse import OptionParser
+from time import strftime
+
+class LDAPbackendSetup:
+    def __init__(self, verbose_in, pw_in,  kdcPath_in, kdmdPath_in, kdbPath_in, ldapPath_in, kdmlPath_in, kdmPath_in, cltPath_in, sandir_in, confdir_in):
+        self.npass = 0
+
+        self.nfail = 0
+
+        self.verbose = verbose_in
+        self.pw = pw_in
+
+        self.krb5kdc = kdcPath_in #1 krb5kdc
+        self.kadmind = kdmdPath_in #2 kadmind
+        self.kdb5_util = kdbPath_in #3a kdb5_util
+        self.kdb5_ldap_util = ldapPath_in #3b kdb5_ldap_util
+        self.kadminlocal = kdmlPath_in #4 kadmin.local
+        self.kadmin = kdmPath_in #5 kadmin
+        self.clients = cltPath_in+"/" #6 clients
+
+        self.sandir = sandir_in
+        self.confdir = confdir_in
+
+        ########## SET UP Write Output File #####
+        print "outfile path"
+        print self.sandir
+        print self.sandir+"/outfile"
+        
+        self.outfile = open(self.sandir+"/outfile", 'w')
+
+        #''print os.environ'
+
+    def _writeLine(self, astr, prt=False):
+        self.outfile.write(astr.strip()+"\n")
+        if prt:
+            print astr.strip()
+
+    def _writeHeader(self, astr, prt=True):
+        self.outfile.write("\n========== "+astr.strip()+" ==========\n")
+        if prt:
+            print "========== "+astr.strip()+" =========="
+    
+    def _sysexit(self, fatal=False, finished=False):
+        self._writeLine("++++++++++++++++++++++++++++++", True)
+        if fatal:
+            self._writeLine("++++ Test did NOT finish +++++", True)
+            self._writeLine("++++ FATAL FAILURE! Stopped ++", True)
+            self._writeLine("++++ See sandbox/outfile +++++", True)
+            self._writeLine("++++++++++++++++++++++++++++++", True)
+            sys.exit()
+        elif not finished:
+            self._writeLine("++++ Test did NOT finish +++++", True)
+            self._writeLine("++++ FAIL Detected! keep going", True)
+            self._writeLine("++++++++++++++++++++++++++++++", True)
+        else: #finished
+            self._writeLine("++++ MKM Test Finished +++++++", True)
+            self._writeLine("++++++++++++++++++++++++++++++", True)
+            self._writeLine("++++ Commands Passed: %s +++++" % self.npass, True)
+            self._writeLine("++++ Commands Failed: %s +++++" % self.nfail, True)
+            sys.exit()
+        
+    def _printig(self):
+        self._writeLine("~.~.~Error should be ignored~.~.~.~")
+
+    def _printerr(self, errm, stderr):
+        self._writeLine("#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#")
+        self._writeLine("-XX-FAILED: "+errm+". See stderr below:")
+        [self._writeLine(line) for line in stderr.readlines() ]
+
+    def _printout(self, cmd, pstdout):
+        if self.verbose:
+            self._writeLine("#######################################")
+            #self._writeLine("---------------------------------------")
+            self._writeLine("-command: "+cmd)
+            self._writeLine("-----out: ")
+            [self._writeLine(line) for line in pstdout.readlines()]
+
+    def _eval(self, succeed, pwait, errm, pstderr, fatal=False, msg2="", finished=False):
+        if int(pwait) != 0: # is bad
+            self._printerr(errm, pstderr)
+            if succeed==True: ## want good
+                self.nfail += 1
+                self._sysexit(fatal, finished)
+            else: ## want bad
+                self.npass += 1
+                self._printig()
+        else: # is good
+            if not succeed: ## want bad
+                if msg2 != "":
+                    self._writeLine(msg2, True)
+                self.nfail += 1
+                self._sysexit(fatal, finished)
+            else: ## want good
+                self.npass += 1 
+
+    def _metafunc(self, command,  errmsg, moreinfo="", isLocal=False, succeed=True, fatal=False):
+        l = command
+        if isLocal:
+            pl = Popen(l.split(None,2), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+        else:
+            pl = Popen(l.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+        self._printout(l+moreinfo, pl.stdout)
+        
+        self._eval(succeed, pl.wait(), errmsg, pl.stderr, fatal)
+    
+    ###########################################
+
+    # Start the KDC daemons
+    def _startkdc(self):
+        self._writeLine("\nstarting kdc daemons ...")
+        l0 = self.krb5kdc
+        errm = "error at starting krb5kdc"
+        self._metafunc(l0, errm)
+        # below has been changed
+        
+        #starting kadmind
+        l0b = self.kadmind + ' -W -nofork' #the W is for during off strong random numbers
+        errm = "error at starting kadmind, maybe it's already started"
+        pl0b = Popen(l0b.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+        self._writeLine( "kadmind -nofork")
+        started = False
+        while time.clock() < 3:
+            l = pl0b.stderr.readline()
+            if l.find("starting") > -1:
+                self._writeLine( l.strip())          
+                self.npass += 1
+                started = True
+                break  
+        else:
+            self.nfail += 1
+            self._printerr("kadmind not starting, check to see if there are any previous kadmind running with cmd: 'ps -ef | grep kadmind' and then do 'sudo kill -9 [# on the left]'", pl0b.stderr)
+            self._sysexit(fatal=True)
+        if not started:
+            self.nfail += 1
+            self._sysexit()
+        self._writeLine("end starting kdc daemons")
+        
+    # Kill the KDC daemons in case they are running
+    def _killkdc(self, suc=True):
+        l1 = 'pkill -9 -x krb5kdc'
+        errm = "no krb5kdc killed"
+        self._metafunc(l1, errm, succeed=suc)
+        l2 = 'pkill -9 -x kadmind'
+        errm = "no kadmind killed"
+        self._metafunc(l2, errm, succeed=suc)
+
+    # Destroys current database
+    def _destroykdc(self, suc=True):
+        l3 = self.kdb5_util+' destroy -f' #forced
+        errm = "no kdb database destroyed"
+        self._metafunc(l3, errm, succeed=suc)
+
+    ''' Destroys current database
+    I don't use this because 1. I don't know the specific kdc's to destroy, 2. the debconf setting up of slapd has destroyed old databases already
+    def _destroykdc_ldap(self, suc=True):
+        l3 = self.kdb5_ldap_util+' destroy -f' #forced
+        errm = "no kdb database destroyed"
+        self._metafunc(l3, errm, succeed=suc)
+    '''
+
+    # Create a new database with a new master key
+    def _createdb(self, pw):
+        l4 = self.kdb5_util+' -P '+pw+' create -s -W' #added W for svn version 22435 to avoid reading strong random numbers
+        errm = "error when creating new database, _createdb()"
+        self._metafunc(l4, errm, fatal=True)
+
+    # Addprinc
+    def _locAddprinc(self, passw, usern):
+        l5 = self.kadminlocal+' -q addprinc -pw '+passw+' '+usern
+        errm = "error when adding princ, _locAddprinc"
+        self._metafunc(l5, errm, isLocal=True)
+
+    # List princs
+    def _locListprincs(self):
+        l6 = self.kadminlocal+' -q listprincs'
+        errm = "error when listing princs, _locListprincs"        
+        self._metafunc(l6, errm, isLocal=True)
+
+    #  Get princs
+    def _locGetprinc(self, usern, extra=False, succeed=True):
+        l7 = self.kadminlocal+' -q getprinc '+usern
+        errm="error when getting princ, _locGetprinc"
+
+        pl7 = Popen(l7.split(None,2), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+        if not extra:
+            self._printout(l7, pl7.stdout)
+        else:
+            if self.verbose:
+                self._writeLine("-command: "+l7)
+                self._writeLine("-----out: ")
+                for line in pl7.stdout.readlines():
+                    if line.startswith("Princ") or line.startswith("MKey"):
+                        self._writeLine(line)
+        self._eval(succeed, pl7.wait(), errm, pl7.stderr)
+
+    # Get princs and finds something in the output
+    def _locGetprincFind(self, usern, findstr, succeed=True):
+        l7b = self.kadminlocal+' -q getprinc ' +usern
+        errm="error when getting princs, _locGetprinc, (regular output of getprincs is not printed here), will NOT continue to find string="+findstr
+        pl7b = Popen(l7b.split(None, 2), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+        if self.verbose:
+            self._writeLine("-command: "+l7b)
+        if int(pl7b.wait()) != 0: # is bad
+            self._printerr(errm, pl7b.stderr)
+            if succeed: ## want good
+                self.nfail += 1
+                self._sysexit()
+            else: ## want bad
+                self.npass += 1
+                self._printig()
+        else: # is good
+            if self.verbose:            
+                self._writeLine( "-----out: ")
+            boofound = False
+            for outl in pl7b.stdout.readlines():
+                self._writeLine(outl)
+                if string.find(outl, findstr) > -1:
+                    boofound = True
+            if boofound:
+                self._writeLine("----FOUND: "+findstr)
+            else:
+                self._writeLine("----NOT FOUND: "+findstr)
+            if not succeed: ## want bad
+                self.nfail += 1
+                self._sysexit()
+            else: ## want good
+                self.npass += 1
+
+    # Add policy
+    def _locAddpol(self, maxtime, minlength, minclasses, history, policyname):
+        rest = ""
+        if maxtime != None:
+            rest += '-maxlife '+maxtime+' '
+        if minlength != None:
+            rest += '-minlength '+minlength+' '
+        if minclasses != None:
+            rest += '-minclasses '+minclasses+' '
+        if history != None:
+            rest += '-history '+history+' '
+        l8 = self.kadminlocal+' -q add_policy '+rest+policyname
+        errm = "error when adding policy, _locAddpol"
+        self._metafunc(l8, errm, isLocal=True)  
+
+    #  Get pol
+    def _locGetpol(self, poln):
+        l8b = self.kadminlocal+' -q getpol '+poln
+        errm="error when getting pol, _locGetpol"
+        self._metafunc(l8b, errm, isLocal=True)
+
+    # Modify Principal
+    def _locModprinc(self, rest):
+        l9 = self.kadminlocal+' -q modprinc '+rest
+        errm = "error when modifing principal, _locModprinc"
+        self._metafunc(l9, errm, isLocal=True)
+
+    # List mkeys
+    def _listmkeys(self):
+        l10 = self.kdb5_util+' list_mkeys'
+        errm = "error when listing mkeys, _listmkeys"
+        self._metafunc(l10, errm)
+
+    # Use mkeys
+    def _usemkey(self, kvno, time, succeed=True):
+        l11 = self.kdb5_util+' use_mkey '+kvno+' '+time
+        pl11 = Popen(l11.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+        self._printout(l11, pl11.stdout)
+        self._eval(succeed, pl11.wait(), "error when using mkeys, _usemkey", pl11.stderr, msg2="-XX-ERROR: "+l11+" should have failed.")        
+
+        
+    # Change password (cpw)
+    def _locCpw(self, passw, usern):
+        l12 = self.kadminlocal+' -q cpw -pw '+passw+' '+usern
+        errm = "error when changing password, _locCpw"
+        self._metafunc(l12, errm, moreinfo="\n--------: newpw='"+passw+"'", isLocal=True)
+
+    # Purge mkeys
+    def _purgemkeys(self):
+        l13 = self.kdb5_util+' purge_mkeys -f -v' #-f is forced, -v is verbose
+        errm = "error when purging mkeys, _purgemkeys"
+        self._metafunc(l13, errm)
+
+    # Add mkey
+    def _addmkey(self, passw, extra="", succeed=True):
+        l14 = self.kdb5_util+' add_mkey '+extra
+        pl14 = Popen(l14.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE) 
+        pl14.stdin.write(passw+'\n') #enter 1st time
+        pl14.stdin.write(passw+'\n') #re-enter    
+        self._printout(l14+' [with password='+passw+']', pl14.stdout)
+        self._eval(succeed, pl14.wait(), "error when adding mkey, _addmkey", pl14.stderr)
+        self._writeLine( "----end of adding mkey")
+
+    # kinit user
+    def _kinit(self, passw_in, usern, succeed=True):
+        l15 = self.clients+'kinit/kinit '+usern
+        pl15 = Popen(l15.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+        pl15.stdin.write(passw_in+'\n')
+        pl15.stdin.close()
+        self._printout(l15, pl15.stdout)
+        self._eval(succeed, pl15.wait(), "error when kinit user, _kinit", pl15.stderr)
+        self._writeLine( "----end of kiniting user")
+
+    # change password on client's side
+    def _kpasswd(self, oldpw, newpw, usern, succeed=True):
+        l16 = self.clients+'kpasswd/kpasswd '+usern
+        pl16 = Popen(l16.split(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
+        pl16.stdin.write(oldpw+'\n')
+        pl16.stdin.write(newpw+'\n')
+        pl16.stdin.write(newpw+'\n')
+        self._printout(l16+"\n--------: oldpw='"+oldpw+"' -> newpw='"+newpw+"'", pl16.stdout)
+        self._eval(succeed, pl16.wait(), "error when changing password on client's side, _kpasswd", pl16.stderr)
+        self._writeLine("----end of changing kpasswd")
+
+    # klist on client's side
+    def _klist(self):
+        l17 = self.clients+'klist/klist'
+        errm = "error when klist, _klist"
+        self._metafunc(l17, errm)
+
+    # Update principal encryption
+    def _updatePrincEnc(self):
+        l18 = self.kdb5_util+' update_princ_encryption -f -v'
+        errm = "error when updating principal encryption, _updatePrincEnc"
+        self._metafunc(l18, errm)
+
+    # kdestroy
+    def _kdestroy(self):
+        l19 = self.clients+'kdestroy/kdestroy'
+        errm = "error when kdestroy, _kdestroy"
+        self._metafunc(l19, errm)
+
+    # stash
+    def _stash(self):
+        l20 = self.kdb5_util+' stash'
+        errm="error at stash, _stash"
+        self._metafunc(l20, errm)
+
+    # any shell command
+    def _shell(self, command, succeed=True):
+        l21 = command
+        errm="error at executing this command in _shell(): "+l21
+        pl21 = Popen(l21, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
+        self._printout(l21, pl21.stdout)
+        self._eval(succeed, pl21.wait(), errm, pl21.stderr)
+        #'self._printerr(errm, pl21.stderr)  Pointed out that kadmin had problems!'
+
+
+    def _shelltest(self, command, succeed=True):
+        l21 = command
+        errm="error at executing this command in _shell(): "+l21
+        pl21 = Popen(l21, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
+        first = pl21.communicate('a\na')[0]
+        print "first:"
+        print first
+        print "end first"
+              
+        #self._printout(l21, pl21.stdout) self._printout(l21, first)        
+        self._eval(succeed, pl21.wait(), errm, pl21.stderr)
+        #self._printerr(errm, pl21.stderr)  #Pointed out that kadmin had problems!'
+
+
+    # get_princ_records()
+    def _get_princ_records(self, succeed=True):
+        l22 = self.kadminlocal+" -q listprincs 2>/dev/null|grep -v '^Authenticating as'|fgrep '@'|sort"
+        errm="error at listprincs in _get_princ_records() with this command: "+l22
+        pl22 = Popen(l22, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
+        if int(pl22.wait()) != 0: # is bad
+            self.printerr(errm, pl22.stderr)
+            if succeed: ## want good
+                self.nfail += 1
+                self._sysexit()
+            else: ## want badd
+                self.npass += 1
+                self._printig()
+        else: # is good
+            if not succeed: ## want bad
+                self.nfail += 1
+                self._sysexit()
+            else: ## want good
+                self.npass += 1
+                self._writeLine( "\nget_princ_records() executing all listprincs command: "+l22+"\n------its results:")
+                for princ in pl22.stdout.readlines():
+                    self._locGetprinc(princ.strip(), extra=True)
+                self._writeLine("END executing command: "+l22+"\n~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~")
+        
+######################################################
+    def run(self):
+        #############RUN###################
+        passw=self.pw     
+       
+        self._writeHeader("START MASTER KEY MIGRATION TEST")        
+
+        # Set up database
+        self._writeHeader("SET UP: database")
+        self._killkdc("Either") #74 =1,2
+        #self._destroykdc("Either") #77 =3
+        #self._destroykdc_ldap("Either") #77 =3
+
+        self._shell('sudo cat '+self.confdir+'/debconfile')
+       self._shell('sudo debconf-set-selections '+self.confdir+'/debconfile')
+        self._shell('sudo dpkg-reconfigure --frontend=noninteractive slapd')
+        self._shell('sudo ldapadd -x -D cn=admin,cn=config -w a -f /tmp/ldif_output/cn\=config/cn\=schema/cn\=\{6\}kerberos.ldif -H ldapi:///')
+        self._shell('kdb5_ldap_util -D cn=admin,dc=example,dc=org -w a -H ldapi:/// create -P a -s') #self._createdb(passw) #81 =4
+        self._shelltest('kdb5_ldap_util -D cn=admin,dc=example,dc=org -w a -H ldapi:/// stashsrvpw cn=admin,dc=example,dc=org')              
+        #self._shell('krb5kdc') ## MUST KILL krb5kdc before first!
+        self._writeHeader("+++++ START +++++")        
+        
+        #line 83-86 involves ktadd kadm5.keytab, which are out dated
+        
+        # add, get, and list princs
+        self._writeHeader("SET UP: add/get/list princs")               
+        self._locAddprinc(passw, 'kdc/admin') #87 =5
+        self._locListprincs() #89 =6
+        self._locGetprinc('K/M') #90 =7
+        self._locAddprinc('test123', 'haoqili') #91 =8
+        self._locGetprinc('haoqili') #92 =9
+        self._locAddprinc(passw, 'haoqili/admin') #93 =10
+        self._locAddprinc('foobar', 'test') #94 =11
+        self._locGetprinc('test') #95 =12
+        self._locListprincs() # I added =13
+        myfqdn = socket.getfqdn()
+        #self._shell(self.parentpath+"kadmin.local -q 'addprinc -randkey host/"+myfqdn+"'") #96
+        self._shell(self.kadminlocal+" -q 'addprinc -randkey host/"+myfqdn+"'") #96 =14
+        
+        # create policies
+        self._writeHeader("SET UP: create policies")
+        
+        #print "\n~~~~~~~~~ create policies ~~~~~~~~~~~"
+        self._locAddpol('8days', None, None, None, 'testpolicy')#100 =15
+        self._locAddpol('20days', '8', '3', None,  'testpolicy2')#101 
+        self._locAddpol('90days', '2', '2', None,  'testpolicy3')#102
+        #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+        #!!!!!!!!!Changed to avoid problem in 'kpasswd all'!!!!!!!!!!!!!!!!!!!!
+        #self._locAddpol('90days', '2', '2', '3', 'testpolicy4')#103
+        self._locAddpol('90days', '2', '2', None, 'testpolicy4')#103
+        #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+            
+        self._locModprinc('-policy testpolicy haoqili')#105
+        self._locAddprinc(passw, 'foo')#106
+        self._locModprinc('-policy testpolicy3 foo')#107 =21
+        
+        # create all princ with all fields
+        self._writeHeader("SET UP: create all princ with all fields")
+        #print "\n~~~~~~~~~ create all princ with all fields ~~~~~"
+        self._locAddprinc(passw, 'all') #110 =22
+        self._locModprinc('-expire "2029-12-30 7pm" all') #112
+        self._locModprinc('-pwexpire 12/30/2029 all') #114
+        #self._locModprinc('-expire "now+10years" all') #112
+        #self._locModprinc('-pwexpire now+10years all') #114        
+        self._locGetprinc('all') #115
+        self._locModprinc('-maxlife 100days all') #116
+        self._locGetprinc('all') #117
+        self._locModprinc('-maxrenewlife 100days all') #118
+        self._locGetprinc('all') #119
+        self._locModprinc('+allow_postdated +allow_forwardable all') #120 =30
+        self._locModprinc('+allow_proxiable +allow_dup_skey all') #121
+        self._locModprinc('+requires_preauth +allow_svr +needchange all') #122
+        self._locModprinc('-policy testpolicy4 all') #123 ###########
+        self._locGetprinc('all') #124 =34
+        
+        # Testing stuff
+        self._writeHeader("TEST: initial mkey list") #126
+        self._writeLine("===== Listing mkeys at start of test") #I add
+        self._listmkeys() #127 =35
+        
+        self._writeLine( "Testing krb5kdc list_mkeys Done ==============================================") #128
+
+        self._writeLine("---------------\n xxxxxxxxxx \/\/\/ ERRORS (multiple) EXPECTED below xxxxxxxxxx")
+        self._writeLine("\nERRORS (multiple) EXPECTED below") 
+        self._writeLine("Testing bogus use_mkey (setting only mkey to future date, using non-existent kvno, so should return error) =======") #129, 130
+        self._writeLine( "-> must have a mkey currently active (setting mkey to 2 days from now), should fail and return error") #132     
+        self._usemkey('1', 'now+2days', False) #133-138 =36
+        
+        self._writeLine("-> must have a mkey currently active (setting mkey to 2019 the future), should fail and return error") #140
+        self._usemkey('1', '5/30/2019', False) #141 =37
+        self._writeLine("-> bogus kvno and setting mkey to 2 days from now, should fail and return error") #147
+        self._usemkey('2', 'now+2days', False) #148 =38
+        self._writeLine("-> bogus kvno, should fail and return error") #I add
+        self._usemkey('2', 'now-2days', False) #I add =39
+        self._writeLine( "^^^ABOVE^^ SHOULD HAVE *ALL* FAILED\n-----------------")
+
+        self._writeLine( "Listing mkeys at end of test") #I add
+        self._listmkeys() #155 =40
+        self._writeLine("Testing bogus use_mkey (setting only mkey to future date) Done ===========================") #156
+        
+        
+        self._writeLine("\nmake sure cpw [change password] works") #158
+        # this changes the password of 'test' from 'foobar' in "add, get, and list princs" above
+        self._locCpw('test1', 'test') #159 =41
+
+        self._writeHeader("TEST: bogus purge_mkeys (should be no keys purged, no error returned")
+        #print "\nTesting bogus purge_mkeys (should be no keys purged, no error returned) ===========================" #161
+        self._purgemkeys() #162 =42
+        self._writeLine("Testing bogus purge_mkeys (no error) Done ===========================") #163
+        
+        self._writeHeader( "add kvno 2") #164
+        
+        self._addmkey('abcde', '-s') #165-167 =43
+        self._writeLine(".\nlist mkeys")
+        self._listmkeys() #169 =44
+        
+        #start daemons
+        #@@@@@@@@@@@@@@@@@@@@@@@@@@@############@@@@@@@@@@@@@@@@@@############
+        self._startkdc() #172 =45 46
+        self._writeLine("make sure kdc is up, by kinit test") #176
+        self._kinit('test1', 'test') #177 =47
+        
+        self._writeLine("---------------\n\/\/\/ ERROR EXPECTED below.  Test passwd policy.:") #180
+        self._kinit(passw, 'all', succeed=False) #181 =48
+        self._writeLine("^^ABOVE^^ SHOULD HAVE FAILED\n-----------------")
+        
+        #change passwd on client's side
+        
+        #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+        self._kpasswd(passw, 'Test123.', 'all')#184-188 =49 !!!!!!!!!!!!!!!!
+        #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+        self._kinit('Test123.', 'all') #189 =50
+        self._klist() #190 =51
+        
+        self._writeHeader("TEST: password history for principal 'all', new passwords must not be a previous password") #191
+        self._kpasswd('Test123.', 'Foobar2!', 'all') #192-195 =52
+        #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+        '''
+        self._writeLine("--------------\n\/\/\/ ERROR EXPECTED below") #197
+        self._kpasswd('Foobar2!', passw, 'all', succeed=False) #199-202 =53
+        self._writeLine("^^^ABOVE^^ SHOULD HAVE FAILED\n----------")
+        '''
+        #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+        
+        # this shouldn't change the mkvno for any princs (should be 1) #206
+        #self._updatePrincEnc() #207
+        # princs should still be protected by mkvno 1 #208
+        self._writeLine("@@@@@@@@ Wait for other people to fix bug in code 6507 update_princ_encryption to use mkey instead of latest mkey @@@@@@@@@@@@@\n")
+        self._locGetprincFind('test', 'MKey: vno 1') #209 =54
+               
+        self._purgemkeys() #210 =55   
+        self._listmkeys() #211 =56
+        self._usemkey('2', 'now-1day') #213 =57
+        self._listmkeys() #214 =58
+        #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+        '''
+        self._writeLine("-----------\n\/\/\/ ERROR EXPECTED below") #216
+        self._kpasswd('Foobar2!', passw, 'all', succeed=False) #217-221 =59
+        self._writeLine("^^^ABOVE^^ SHOULD HAVE FAILED\n--------") 
+        '''
+        #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+        
+        self._kpasswd('Foobar2!', 'Barfoo3.', 'all') #224-228 =60
+        self._kinit('Barfoo3.', 'all') #229
+        self._klist() #230 =62
+        #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+        '''    
+        self._writeLine("-------------\n\/\/\/ ERROR EXPECTED below") #231
+        self._kpasswd('Barfoo3.', 'Foobar2!', 'all',succeed=False) #233-235 =63
+        self._writeLine("^^^ABOVE^^ SHOULD HAVE FAILED\n---------")
+        '''
+        #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+        self._writeLine("\nTest's key should be protected by mkvno 2" ) #239
+        self._locCpw('foo', 'test') #240 =64
+        self._locGetprincFind('test', 'MKey: vno 2') #241 =65
+        self._kdestroy() #242 =66
+        
+        self._writeHeader("TEST: krb5kdc refetch of mkey")#243
+        self._kinit('foo', 'test') #244 =67
+        self._klist() #245 =68
+        self._writeLine("END. Testing krb5kdc refetch of mkey list Done ==============================================\n")     #246
+        
+        self._updatePrincEnc() #247 =69
+        self._get_princ_records() #248 =70 -83
+        self._kdestroy() #249 =84
+        self._kinit('foo', 'test') #250 =85
+        self._purgemkeys() #252 =86
+        
+        #self._stash() #254 =87 #!!! Not necessary in ldap, done by 'create -s'
+        self._shell(self.clients+'klist/klist' +" -ekt "+self.sandir+"/krb5kdc/.k5.EXAMPLE.ORG") #255=88
+
+        self._locGetprinc('K/M') #256 =89
+        self._purgemkeys() #257 =90
+        self._locGetprinc('K/M') #258
+        self._listmkeys() #259 =92
+        self._kdestroy() #260
+        self._kinit('foo', 'test') #261
+        self._klist() #262 =95
+        
+        self._writeLine("\n Adding in Master Key Number 3")
+        self._listmkeys() #265 =96
+        self._addmkey('abcde') #266-268
+        self._listmkeys() #270 =98
+        self._locCpw('foo', 'all') #271
+        self._locGetprinc('all') #272 =100
+        self._usemkey('3', 'now') #273
+        self._listmkeys() #274 =102
+        self._locCpw('99acefghI0!', 'all') #275
+        self._locGetprinc('all') #276 =104
+        self._kdestroy() #277
+        self._kinit('foo', 'test') #279 =106
+        self._klist() #280
+        self._shell(self.kadmin+" -p haoqili/admin -w "+passw+" -q 'listprincs'") #281 =108
+        self._shell(self.kadmin+" -p haoqili/admin -w "+passw+" -q 'getprinc test'") #282 =109
+        
+        self._writeHeader("TEST: add_mkey with aes128 enctype") #283      
+        self._addmkey('abcde', '-e aes128-cts-hmac-sha1-96') #284-287 =110
+        #!!!!!!!!!!!!!!!!Start to have problems !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+        self._listmkeys() #288 =111
+        '''$ kdb5_util list_mkeys
+kdb5_util: Unable to decrypt latest master key with the provided master key
+ while getting master key list
+kdb5_util: Warning: proceeding without master key list
+kdb5_util: master keylist not initialized'''#!!!!!!!!!!!!!!!!!!!!!!!
+        #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+        
+        self._writeLine( "END. Testing add_mkey with aes128 enctype done ==============================================")#289     
+        self._writeHeader("TEST: krb5kdc refetch of mkey list")
+        #!!!!!!!!!!!!!!\/ errors \/ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+        self._usemkey('4', 'now') #290 =112
+        self._listmkeys() #291 =113
+        #!!!!!!!!!!!!!!/\ errors /\ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+        self._shell(self.kadmin+" -p haoqili/admin -w "+passw+" -q 'cpw -pw abcde test'") #292 =114
+        self._shell(self.kadmin +" -p haoqili/admin -w "+passw+" -q 'getprinc test'") #293
+        
+        self._kdestroy() #294 =116
+        
+        self._writeLine("\nTesting krb5kdc refetch of mkey list =================================================") #295
+        self._kinit('abcde', 'test') #296 =117
+        self._klist() #297 =118
+        self._writeLine("Testing krb5kdc refetch of mkey list Done :) =================================================\n") #298
+        
+        self._killkdc() #300 =119, 120
+        self._startkdc() #301 =121 122
+        
+        # The lines below are commented out because krb5kdc could not be restarted.  For their error messages, see the outfile
+        '''
+        kdc.log:
+        Aug 31 12:21:23 reach-my-dream krb5kdc[24273](info): AS_REQ (2 etypes {16 17}) 127.0.1.1: ISSUE: authtime 1251746483, etypes {rep=16 tkt=18 ses=16}, test@EXAMPLE.ORG for krbtgt/EXAMPLE.ORG@EXAMPLE.ORG
+krb5kdc: Unable to decrypt latest master key with the provided master key
+ - while fetching master keys list for realm EXAMPLE.ORG
+        '''
+        '''
+        self._shell("kadmin -p haoqili/admin -w "+passw+" -q 'cpw -pw foo test'") #304 =123
+        self._shell("kadmin -p haoqili/admin -w "+passw+" -q 'getprinc test'") #305 =124
+        self._kdestroy() #307 =125
+
+        self._writeLine("\nTesting krb5kdc refetch of mkey list =================================================") #308
+        self._kinit('foo', 'test') #309 =126
+        self._klist() #310 =127
+        self._writeLine("Testing krb5kdc refetch of mkey list Done =================================================\n") #311
+        
+        self._updatePrincEnc() #313 =128
+        self._locGetprinc('K/M') #314
+        self._locGetprinc('all') #315 =130
+        self._locGetprinc('haoqili') #316
+        self._kdestroy() #317 =132
+        self._kinit('foo', 'test') #318
+        self._stash() #319 =134
+        self._shell(self.clients+'klist/klist' +" -ekt "+self.sandir+"/krb5kdc/.k5.EXAMPLE.ORG") #320
+        self._locGetprinc('K/M') #321 =136
+        self._purgemkeys() #322
+        self._locGetprinc('K/M') #323 =138
+        self._locGetprinc('all') #324
+        self._shell("kadmin -p haoqili/admin -w "+passw+" -q 'getprinc test'") #325 =140
+        self._listmkeys() #326
+        self._kdestroy() #327 =142
+        self._kinit('foo', 'test') #328
+        self._klist() #329 =144
+        
+        self._get_princ_records() #330 =145-158
+        
+        self._writeHeader("TEST: add_meky with DES-crc enctype")
+        #print "\nTesting add_mkey with DES-crc enctype ==============================================" #331
+        self._addmkey('abcde', '-e des-cbc-crc') #332-335 =159
+        self._listmkeys() #336 =160
+        self._writeLine( "END. Testing add_mkey with DES-crc enctype Done ==============================================") #337
+        self._addmkey('abcde') #338-341 =161
+        self._listmkeys() #342 =162
+        self._writeLine( "current time: "+strftime("%Y-%m-%d %H:%M:%S") ) #343
+        
+        self._usemkey('5', 'now-1day') #344 =163
+        self._writeLine("current time: "+strftime("%Y-%m-%d %H:%M:%S") )#345
+        self._listmkeys() #346 =164
+        self._usemkey('5', 'now') #347 =165
+        self._writeLine("current time: "+strftime("%Y-%m-%d %H:%M:%S") )#348
+        self._listmkeys() #349 =166
+        self._usemkey('5', 'now+3days') #350 =167
+        self._writeLine("current time: "+strftime("%Y-%m-%d %H:%M:%S") )#351
+        self._listmkeys() #352 =168
+        self._writeLine("current time: "+strftime("%Y-%m-%d %H:%M:%S") )#353
+        self._usemkey('5', 'now+5sec') #354 =169
+        self._listmkeys() #355 =170
+        time.sleep(5) #356
+        self._listmkeys() #357 =171
+        self._writeLine("current time: "+strftime("%Y-%m-%d %H:%M:%S") )#358
+        self._usemkey('4', 'now+5sec') #359 =172
+        self._listmkeys() #360 =173
+        time.sleep(5) #361
+        self._listmkeys() #362 =174
+        self._usemkey('5', 'now+3days') #363 =175
+
+        self._writeLine("------------\n\/\/\/ ERROR EXPECTED below" )#364
+        self._writeLine("should fail, because there must be one mkey currently active") #365
+        self._usemkey('4', 'now+2days', False) #366 =176
+        self._writeLine("^^^ABOVE^^ SHOULD HAVE FAILED\n---------------")
+
+        self._listmkeys() #373 =177
+        self._usemkey('4', '1/30/2009') #375 =178
+        
+        self._writeHeader("TEST: purge_mkeys (removing mkey 5)")
+        #print "\nTesting purge_mkeys (removing mkey 5) ==============================================" #378
+        self._purgemkeys() #379 =179
+        #self._stash() #380 =180
+        self._shell(self.clients+'klist/klist' +" -ekt "+self.sandir+"/krb5kdc/.k5.EXAMPLE.ORG") #381=181
+        self._listmkeys() #382 =182
+        self._shell("kadmin -p haoqili/admin -w "+passw+" -q 'getprinc K/M'") #383 =183
+        self._writeLine("Testing purge_mkeys Done ==============================================") #384
+        self._writeHeader("MASTER KEY MIGRATION TEST DONE. please consult 'outfile' in your sandbox for more info.  The sandbox is at: %s" % self.sandir) 
+ # I added
+        self._sysexit(finished=True)
+        '''
+####################################################
+####################################################
+
+class Launcher:
+    #def __init__(self, path, sandP):
+    #def __init__(self):
+    def __init__(self, sandP):
+        self._buildDir = os.environ["PWD"]
+        self._confDir = '%s/tests/mk_migr/ldap_backend/input_conf' % self._buildDir
+        
+        #setting up sandbox
+        if sandP != "":
+            self._sandP = sandP        
+        else: #default
+            self._sandP = '%s/tests/mk_migr/ldap_backend/sandbox' %self._buildDir
+
+        print self._sandP
+        print "sandP"
+       self._vars = {'sandir': self._sandP, 
+                     'localFQDN': socket.getfqdn()}
+
+    def _prepSandbox(self, sandir):
+        if os.path.exists(sandir):
+            shutil.rmtree(sandir)
+        print "------about to make sandbox, with the path of:"
+        print sandir
+        os.makedirs(sandir, 0777)
+       os.mkdir(sandir+'/krb5kdc', 0777)
+        print "------sandbox made"
+
+    def _createFileFromTemplate(self, outpath, template, vars):
+        fin = open(template, 'r')
+        result = fin.read() % vars
+        fin.close()
+        fout = open(outpath, 'w')
+        fout.write(result)
+        fout.close()
+
+    ####### Launcher RUN ################
+    def runLauncher(self):
+        # create sandbox file directory (and sandbox/krb5kdc) if it does not exit
+        self._prepSandbox(self._sandP)
+
+        # Export the 3 env lines
+       src_path=os.environ["PWD"]
+        os.environ["LD_LIBRARY_PATH"] = '%s/lib' % src_path
+
+        str1 = '%s/krb5.conf' % self._sandP
+        os.environ["KRB5_CONFIG"] = str1
+
+        str2 = '%s/kdc.conf' % self._sandP
+        os.environ["KRB5_KDC_PROFILE"] = str2
+
+        str3 = '%s/kadm5.acl' % self._sandP   
+
+        # Create adequate to the environment config files
+        self._createFileFromTemplate(str1, '%s/%s' % (self._confDir, 'krb5_template_ldap.conf'), self._vars)
+        self._createFileFromTemplate(str2, '%s/%s' % (self._confDir, 'kdc_template_ldap.conf'), self._vars)
+        self._createFileFromTemplate(str3, '%s/%s' % (self._confDir, 'kadm5_template_ldap.acl'), self._vars)
+        
+        return (self._confDir, self._sandP)
+
+####################################################
+####################################################
+
+def makeBool(aStr):
+    if aStr == "True" or aStr == "T":
+        return True
+    if aStr == "False" or aStr == "F":
+        return False
+    else:
+        print "did NOT execute due to invalid True False argument.  Please enter either 'True', 'T', 'False', or 'F'"
+        sys.exit()
+
+# # # # # # # # # # # # # # # # # # # # # # # # #
+
+def processInputs(parser):
+#def processInputs():
+    
+    # get inputs
+    (options, args) = parser.parse_args()
+
+    verbose = makeBool(options.opVerbose)
+    pw = options.opPassword
+
+    kdcPath = options.opKdcPath #1
+    kdmdPath = options.opKdmdPath #2
+    kdbPath = options.opKdbPath #3a
+    ldapPath = options.opLdapPath #3b
+    kdmlPath = options.opKdmlPath #4
+    kdmPath = options.opKdmPath #5
+    cltPath = options.opCltPath #6
+
+    sandPath = options.opSandbox
+
+    ########### Launch ###############
+    
+    print "\n############ Start Launcher #############"    
+    myLaunch = Launcher(sandPath)
+    (confDir, sandPath) = myLaunch.runLauncher()
+    
+    print ":D"
+    print sandPath
+    
+    test = LDAPbackendSetup(verbose, pw,  kdcPath, kdmdPath, kdbPath, ldapPath, kdmlPath, kdmPath, cltPath, sandPath, confDir)
+    print "########## Finished Launcher ############\n"
+
+    return test
+# # # # # # # # # # # # # # # # # # # # # # # # #
+
+def makeParser():
+    usage = "\n\t%prog [-v][-p][-c][-d][-b][-l][-t][-s]"
+    description = "Description:\n\tTests for the master key migration commands."
+    parser = OptionParser(usage=usage, description=description)
+
+    parser.add_option("-v", "--verbose",  type="string", dest="opVerbose", 
+default="True", help="'True' or 'False'.  Switch on for details of command lines and outputs.  Default is 'True'")
+
+    parser.add_option("-p", "--password",  type="string", dest="opPassword",  default="test123", help="master password for many of the passwords in the test. Default is 'test123'")
+
+    ## Default Paths
+    dSrcPath = src_path=os.environ["PWD"]
+    dKdcPath = '%s/kdc/krb5kdc' % dSrcPath #1    
+    dKdmdPath = '%s/kadmin/server/kadmind' % dSrcPath #2   
+    dKdbPath = '%s/kadmin/dbutil/kdb5_util' % dSrcPath #3a
+    dLdapPath = '%s/plugins/kdb/ldap/ldap_util/kdb5_ldap_util' % dSrcPath #3b
+    dKdmlPath = '%s/kadmin/cli/kadmin.local' % dSrcPath #4
+    dKdmPath = '%s/kadmin/cli/kadmin' % dSrcPath #5
+    dCltPath = '%s/clients' % dSrcPath #6
+
+    parser.add_option("-c", "--krb5kdcpath",
+type="string", dest="opKdcPath", 
+default=dKdcPath, help="set krb5kdc path, default="+dKdcPath) #1
+
+    parser.add_option("-d", "--kadmindpath", 
+type="string", dest="opKdmdPath", 
+default=dKdmdPath, help="set kadmind path, default="+dKdmdPath) #2
+
+    parser.add_option("-b", "--kdb5_utilpath", 
+type="string", dest="opKdbPath", 
+default=dKdbPath, help="set kdb5_util path, default="+dKdbPath) #3a
+
+    parser.add_option("-a", "--kdb5_ldap_utilpath", 
+type="string", dest="opLdapPath", 
+default=dKdbPath, help="set kdb5_ldap_util path, default="+dLdapPath) #3b
+
+    parser.add_option("-l", "--kadminlocalpath", 
+type="string", dest="opKdmlPath", 
+default=dKdmlPath, help="set kadmin.local path, default="+dKdmlPath) #4
+
+    parser.add_option("-n", "--kadminpath", 
+type="string", dest="opKdmPath", 
+default=dKdmPath, help="set kadmin path, default="+dKdmPath) #5 
+
+    parser.add_option("-t", "--clientspath", 
+type="string", dest="opCltPath", 
+default=dCltPath, help="set clients path, default="+dCltPath) #6
+
+    # set up / initializing stuff for the sandbox
+    parser.add_option("-s", "--sandbox",
+type="string", dest="opSandbox",
+default="",
+help="path for the sandbox. Default is 'src/tests/mk_migr/ldap_backend/sandbox'")
+
+    return parser
+
+####################################################
+if __name__ == '__main__':
+    #processInputs()
+    
+    parser = makeParser()    
+    test = processInputs(parser)
+    result = test.run()
index bd8b5d3aba7d3d88951eb1d162bb6e167be21917..68ede98494945d7646154f408aa597ea8544d7ad 100644 (file)
@@ -43,7 +43,7 @@ STOBJLISTS= \
        ../../lib/crypto/krb/crc32/OBJS.ST \
        ../../lib/crypto/builtin/des/OBJS.ST \
        ../../lib/crypto/krb/dk/OBJS.ST \
-       ../../lib/crypto/krb/enc_provider/OBJS.ST \
+       ../../lib/crypto/builtin/enc_provider/OBJS.ST \
        ../../lib/crypto/krb/hash_provider/OBJS.ST \
        ../../lib/crypto/krb/keyhash_provider/OBJS.ST \
        ../../lib/crypto/builtin/md4/OBJS.ST \
index 4b628bb67b8517f77301caeaf70d2b817b8aa484..34ce7701bdfa7c662a355abe7d0273ff50f621df 100644 (file)
@@ -140,7 +140,15 @@ extern /*@dependent@*/ char *gai_strerror (int code) /*@*/;
 #endif
 
 #if defined (__linux__) && defined(HAVE_GETADDRINFO)
-# define COPY_FIRST_CANONNAME
+/* Define COPY_FIRST_CANONNAME for glibc 2.3 and prior. */
+#include <features.h>
+# ifdef __GLIBC_PREREQ
+#  if ! __GLIBC_PREREQ(2, 4)
+#   define COPY_FIRST_CANONNAME
+#  endif
+# else
+#   define COPY_FIRST_CANONNAME
+# endif
 #endif
 
 #ifdef _AIX
@@ -1157,7 +1165,7 @@ getaddrinfo (const char *name, const char *serv, const struct addrinfo *hint,
        return aierr;
     }
 
-    /* Linux libc version 6 (libc-2.2.4.so on Debian) is broken.
+    /* Linux libc version 6 prior to 2.3.4 is broken.
 
        RFC 2553 says that when AI_CANONNAME is set, the ai_canonname
        flag of the first returned structure has the canonical name of
@@ -1188,9 +1196,12 @@ getaddrinfo (const char *name, const char *serv, const struct addrinfo *hint,
        Ref: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=133668 .
 
        Since it's dependent on the target hostname, it's hard to check
-       for at configure time.  Always do it on Linux for now.  When
-       they get around to fixing it, add a compile-time or run-time
-       check for the glibc version in use.
+       for at configure time.  The bug was fixed in glibc 2.3.4.
+       After the fix, the ai_canonname field is allocated, so our
+       workaround leaks memory.  We disable the workaround for glibc
+       >= 2.4, but there is no easy way to test for glibc patch
+       versions, so we still leak memory under glibc 2.3.4 through
+       2.3.6.
 
        Some Windows documentation says that even when AI_CANONNAME is
        set, the returned ai_canonname field can be null.  The NetBSD