build the trunk on Windows (again)
[krb5.git] / src / lib / krb5 / krb / init_ctx.c
index 2d875924179086b1fb2104d48acb03a6c242d27d..b80fd50fa170409ef0b116da5709b0dab9165a3d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * lib/krb5/krb/init_ctx.c
  *
- * Copyright 1994 by the Massachusetts Institute of Technology.
+ * Copyright 1994,1999,2000, 2002, 2003  by the Massachusetts Institute of Technology.
  * All Rights Reserved.
  *
  * Export of this software from the United States of America may
  * 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.  M.I.T. makes no representations about the suitability of
+ * 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 <ctype.h>
 #include "brand.c"
+/* There has to be a better way for windows... */
+#if defined(unix) || TARGET_OS_MAC
+#include "../krb5_libinit.h"
+#endif
+
+/* The des-mdX entries are last for now, because it's easy to
+   configure KDCs to issue TGTs with des-mdX keys and then not accept
+   them.  This'll be fixed, but for better compatibility, let's prefer
+   des-crc for now.  */
+#define DEFAULT_ETYPE_LIST     \
+       "aes256-cts-hmac-sha1-96 " \
+       "aes128-cts-hmac-sha1-96 " \
+       "des3-cbc-sha1 arcfour-hmac-md5 " \
+       "des-cbc-crc des-cbc-md5 des-cbc-md4 "
+
+/* Not included:
+       "aes128-cts-hmac-sha1-96 " \
+ */
 
-#if (defined(_MSDOS) || defined(_WIN32))
+#if (defined(_WIN32))
 extern krb5_error_code krb5_vercheck();
 extern void krb5_win_ccdll_load(krb5_context context);
 #endif
 
-KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
-krb5_init_context(context)
-       krb5_context *context;
+static krb5_error_code init_common (krb5_context *, krb5_boolean, krb5_boolean);
+
+krb5_error_code KRB5_CALLCONV
+krb5_init_context(krb5_context *context)
+{
+
+       return init_common (context, FALSE, FALSE);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_init_secure_context(krb5_context *context)
+{
+
+        /* This is to make gcc -Wall happy */
+        if(0) krb5_brand[0] = krb5_brand[0];
+       return init_common (context, TRUE, FALSE);
+}
+
+krb5_error_code
+krb5int_init_context_kdc(krb5_context *context)
+{
+    return init_common (context, FALSE, TRUE);
+}
+
+static krb5_error_code
+init_common (krb5_context *context, krb5_boolean secure, krb5_boolean kdc)
 {
        krb5_context ctx = 0;
        krb5_error_code retval;
-       krb5_timestamp now;
+       struct {
+           krb5_int32 now, now_usec;
+           long pid;
+       } seed_data;
        krb5_data seed;
        int tmp;
 
-       /* Initialize error tables */
-       krb5_init_ets(ctx);
+       /* Verify some assumptions.  If the assumptions hold and the
+          compiler is optimizing, this should result in no code being
+          executed.  If we're guessing "unsigned long long" instead
+          of using uint64_t, the possibility does exist that we're
+          wrong.  */
+       {
+           krb5_ui_8 i64;
+           assert(sizeof(i64) == 8);
+           i64 = 0, i64--, i64 >>= 62;
+           assert(i64 == 3);
+           i64 = 1, i64 <<= 31, i64 <<= 31, i64 <<= 1;
+           assert(i64 != 0);
+           i64 <<= 1;
+           assert(i64 == 0);
+       }
+
+       retval = krb5int_initialize_library();
+       if (retval)
+           return retval;
+
+#if (defined(_WIN32))
+       /* 
+        * Load the krbcc32.dll if necessary.  We do this here so that
+        * we know to use API: later on during initialization.
+        * The context being NULL is ok.
+        */
+       krb5_win_ccdll_load(ctx);
 
-#if (defined(_MSDOS) || defined(_WIN32))
-       krb5_win_ccdll_load(context);   /* Load the krbcc32.dll if necessary */
        /*
         * krb5_vercheck() is defined in win_glue.c, and this is
         * where we handle the timebomb and version server checks.
@@ -90,6 +160,8 @@ krb5_init_context(context)
        memset(ctx, 0, sizeof(struct _krb5_context));
        ctx->magic = KV5M_CONTEXT;
 
+       ctx->profile_secure = secure;
+
        /* Set the default encryption types, possible defined in krb5/conf */
        if ((retval = krb5_set_default_in_tkt_ktypes(ctx, NULL)))
                goto cleanup;
@@ -97,15 +169,18 @@ krb5_init_context(context)
        if ((retval = krb5_set_default_tgs_ktypes(ctx, NULL)))
                goto cleanup;
 
-       if ((retval = krb5_os_init_context(ctx)))
+       if ((retval = krb5_os_init_context(ctx, kdc)))
                goto cleanup;
 
        /* initialize the prng (not well, but passable) */
-       if ((retval = krb5_timeofday(ctx, &now)))
+       if ((retval = krb5_c_random_os_entropy( ctx, 0, NULL)) !=0)
+         goto cleanup;
+       if ((retval = krb5_crypto_us_timeofday(&seed_data.now, &seed_data.now_usec)))
                goto cleanup;
-       seed.length = sizeof(now);
-       seed.data = (char *) &now;
-       if ((retval = krb5_c_random_seed(ctx, &seed)))
+       seed_data.pid = getpid ();
+       seed.length = sizeof(seed_data);
+       seed.data = (char *) &seed_data;
+       if ((retval = krb5_c_random_add_entropy(ctx, KRB5_C_RANDSOURCE_TIMING, &seed)))
                goto cleanup;
 
        ctx->default_realm = 0;
@@ -140,12 +215,8 @@ krb5_init_context(context)
        profile_get_integer(ctx->profile, "libdefaults",
                            "kdc_default_options", 0,
                            KDC_OPT_RENEWABLE_OK, &tmp);
-       ctx->kdc_default_options = KDC_OPT_RENEWABLE_OK;
-#ifdef macintosh
+       ctx->kdc_default_options = tmp;
 #define DEFAULT_KDC_TIMESYNC 1
-#else
-#define DEFAULT_KDC_TIMESYNC 0
-#endif
        profile_get_integer(ctx->profile, "libdefaults",
                            "kdc_timesync", 0, DEFAULT_KDC_TIMESYNC,
                            &tmp);
@@ -159,16 +230,15 @@ krb5_init_context(context)
         * Note: DCE 1.0.3a only supports a cache type of 1
         *      DCE 1.1 supports a cache type of 2.
         */
-#ifdef macintosh
 #define DEFAULT_CCACHE_TYPE 4
-#else
-#define DEFAULT_CCACHE_TYPE 3
-#endif
        profile_get_integer(ctx->profile, "libdefaults", "ccache_type",
                            0, DEFAULT_CCACHE_TYPE, &tmp);
        ctx->fcc_default_format = tmp + 0x0500;
        ctx->scc_default_format = tmp + 0x0500;
+       ctx->prompt_types = 0;
+       ctx->use_conf_ktypes = 0;
 
+       ctx->udp_pref_limit = -1;
        *context = ctx;
        return 0;
 
@@ -177,11 +247,9 @@ cleanup:
        return retval;
 }
 
-KRB5_DLLIMP void KRB5_CALLCONV
-krb5_free_context(ctx)
-       krb5_context    ctx;
+void KRB5_CALLCONV
+krb5_free_context(krb5_context ctx)
 {
-     krb5_free_ets(ctx);
      krb5_os_free_context(ctx);
 
      if (ctx->in_tkt_ktypes) {
@@ -204,6 +272,8 @@ krb5_free_context(ctx)
          ctx->ser_ctx = 0;
      }
 
+     krb5_clear_error_message(ctx);
+
      ctx->magic = 0;
      free(ctx);
 }
@@ -212,16 +282,14 @@ krb5_free_context(ctx)
  * Set the desired default ktypes, making sure they are valid.
  */
 krb5_error_code
-krb5_set_default_in_tkt_ktypes(context, ktypes)
-       krb5_context context;
-       const krb5_enctype *ktypes;
+krb5_set_default_in_tkt_ktypes(krb5_context context, const krb5_enctype *ktypes)
 {
     krb5_enctype * new_ktypes;
     int i;
 
     if (ktypes) {
        for (i = 0; ktypes[i]; i++) {
-           if (!valid_enctype(ktypes[i])) 
+           if (!krb5_c_valid_enctype(ktypes[i])) 
                return KRB5_PROG_ETYPE_NOSUPP;
        }
 
@@ -244,16 +312,12 @@ krb5_set_default_in_tkt_ktypes(context, ktypes)
 }
 
 static krb5_error_code
-get_profile_etype_list(context, ktypes, profstr, ctx_count, ctx_list)
-     krb5_context context;
-     krb5_enctype **ktypes;
-     char *profstr;
-     int ctx_count;
-     krb5_enctype FAR *ctx_list;
+get_profile_etype_list(krb5_context context, krb5_enctype **ktypes, char *profstr,
+                      unsigned int ctx_count, krb5_enctype *ctx_list)
 {
     krb5_enctype *old_ktypes;
 
-    if (context->in_tkt_ktype_count) {
+    if (ctx_count) {
        /* application-set defaults */
        if ((old_ktypes = 
             (krb5_enctype *)malloc(sizeof(krb5_enctype) *
@@ -276,24 +340,20 @@ get_profile_etype_list(context, ktypes, profstr, ctx_count, ctx_list)
        krb5_error_code code;
 
        code = profile_get_string(context->profile, "libdefaults", profstr,
-                                 NULL,
-                                 "des3-hmac-sha1 des-cbc-md5 des-cbc-crc",
-                                 &retval);
+                                 NULL, DEFAULT_ETYPE_LIST, &retval);
        if (code)
            return code;
 
        count = 0;
        sp = retval;
-       while (sp) {
-           for (ep = sp; *ep && (*ep != ',') && !isspace(*ep); ep++)
+       while (*sp) {
+           for (ep = sp; *ep && (*ep != ',') && !isspace((int) (*ep)); ep++)
                ;
            if (*ep) {
                *ep++ = '\0';
-               while (isspace(*ep))
-                   ep++;
-           } else
-               ep = (char *) NULL;
-
+               while (isspace((int) (*ep)) || *ep == ',')
+                   *ep++ = '\0';
+           }
            count++;
            sp = ep;
        }
@@ -319,7 +379,13 @@ get_profile_etype_list(context, ktypes, profstr, ctx_count, ctx_list)
        }
 
        old_ktypes[j] = (krb5_enctype) 0;
-       free(retval);
+       profile_release_string(retval);
+    }
+
+    if (old_ktypes[0] == 0) {
+       free (old_ktypes);
+       *ktypes = 0;
+       return KRB5_CONFIG_ETYPE_NOSUPP;
     }
 
     *ktypes = old_ktypes;
@@ -327,26 +393,22 @@ get_profile_etype_list(context, ktypes, profstr, ctx_count, ctx_list)
 }
 
 krb5_error_code
-krb5_get_default_in_tkt_ktypes(context, ktypes)
-    krb5_context context;
-    krb5_enctype **ktypes;
+krb5_get_default_in_tkt_ktypes(krb5_context context, krb5_enctype **ktypes)
 {
     return(get_profile_etype_list(context, ktypes, "default_tkt_enctypes",
                                  context->in_tkt_ktype_count,
                                  context->in_tkt_ktypes));
 }
 
-krb5_error_code
-krb5_set_default_tgs_ktypes(context, ktypes)
-       krb5_context context;
-       const krb5_enctype *ktypes;
+krb5_error_code KRB5_CALLCONV
+krb5_set_default_tgs_enctypes (krb5_context context, const krb5_enctype *ktypes)
 {
     krb5_enctype * new_ktypes;
     int i;
 
     if (ktypes) {
        for (i = 0; ktypes[i]; i++) {
-           if (!valid_enctype(ktypes[i])) 
+           if (!krb5_c_valid_enctype(ktypes[i])) 
                return KRB5_PROG_ETYPE_NOSUPP;
        }
 
@@ -362,27 +424,43 @@ krb5_set_default_tgs_ktypes(context, ktypes)
     }
 
     if (context->tgs_ktypes) 
-        free(context->tgs_ktypes);
+        krb5_free_ktypes(context, context->tgs_ktypes);
     context->tgs_ktypes = new_ktypes;
     context->tgs_ktype_count = i;
     return 0;
 }
 
-krb5_error_code
-krb5_get_tgs_ktypes(context, princ, ktypes)
-    krb5_context context;
-    krb5_const_principal princ;
-    krb5_enctype **ktypes;
+krb5_error_code krb5_set_default_tgs_ktypes
+(krb5_context context, const krb5_enctype *etypes)
 {
-    return(get_profile_etype_list(context, ktypes, "default_tgs_enctypes",
-                                 context->tgs_ktype_count,
-                                 context->tgs_ktypes));
+  return (krb5_set_default_tgs_enctypes (context, etypes));
+}
+
+
+void
+KRB5_CALLCONV
+krb5_free_ktypes (krb5_context context, krb5_enctype *val)
+{
+    free (val);
 }
 
 krb5_error_code
-krb5_get_permitted_enctypes(context, ktypes)
-    krb5_context context;
-    krb5_enctype **ktypes;
+KRB5_CALLCONV
+krb5_get_tgs_ktypes(krb5_context context, krb5_const_principal princ, krb5_enctype **ktypes)
+{
+    if (context->use_conf_ktypes)
+       /* This one is set *only* by reading the config file; it's not
+          set by the application.  */
+       return(get_profile_etype_list(context, ktypes, "default_tgs_enctypes",
+                                     0, NULL));
+    else
+       return(get_profile_etype_list(context, ktypes, "default_tgs_enctypes",
+                                     context->tgs_ktype_count,
+                                     context->tgs_ktypes));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_permitted_enctypes(krb5_context context, krb5_enctype **ktypes)
 {
     return(get_profile_etype_list(context, ktypes, "permitted_enctypes",
                                  context->tgs_ktype_count,
@@ -390,9 +468,7 @@ krb5_get_permitted_enctypes(context, ktypes)
 }
 
 krb5_boolean
-krb5_is_permitted_enctype(context, etype)
-     krb5_context context;
-     krb5_enctype etype;
+krb5_is_permitted_enctype(krb5_context context, krb5_enctype etype)
 {
     krb5_enctype *list, *ptr;
     krb5_boolean ret;
@@ -407,7 +483,97 @@ krb5_is_permitted_enctype(context, etype)
        if (*ptr == etype)
            ret = 1;
 
-    krb5_xfree(list);
+    krb5_free_ktypes (context, list);
 
     return(ret);
 }
+
+static krb5_error_code
+copy_ktypes(krb5_context ctx,
+           unsigned int nktypes,
+           krb5_enctype *oldktypes,
+           krb5_enctype **newktypes)
+{
+    unsigned int i;
+
+    *newktypes = NULL;
+    if (!nktypes)
+       return 0;
+
+    *newktypes = malloc(nktypes * sizeof(krb5_enctype));
+    if (*newktypes == NULL)
+       return ENOMEM;
+    for (i = 0; i < nktypes; i++)
+       (*newktypes)[i] = oldktypes[i];
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_copy_context(krb5_context ctx, krb5_context *nctx_out)
+{
+    krb5_error_code ret;
+    krb5_context nctx;
+
+    *nctx_out = NULL;
+    if (ctx == NULL)
+       return EINVAL;          /* XXX */
+
+    nctx = malloc(sizeof(*nctx));
+    if (nctx == NULL)
+       return ENOMEM;
+
+    *nctx = *ctx;
+
+    nctx->in_tkt_ktypes = NULL;
+    nctx->in_tkt_ktype_count = 0;
+    nctx->tgs_ktypes = NULL;
+    nctx->tgs_ktype_count = 0;
+    nctx->default_realm = NULL;
+    nctx->profile = NULL;
+    nctx->db_context = NULL;
+    nctx->ser_ctx_count = 0;
+    nctx->ser_ctx = NULL;
+    nctx->prompt_types = NULL;
+    nctx->os_context->default_ccname = NULL;
+
+    memset(&nctx->preauth_plugins, 0, sizeof(nctx->preauth_plugins));
+    nctx->preauth_context = NULL;
+
+    memset(&nctx->libkrb5_plugins, 0, sizeof(nctx->libkrb5_plugins));
+    nctx->vtbl = NULL;
+    nctx->locate_fptrs = NULL;
+
+    memset(&nctx->err, 0, sizeof(nctx->err));
+
+    ret = copy_ktypes(nctx, ctx->in_tkt_ktype_count,
+                     ctx->in_tkt_ktypes, &nctx->in_tkt_ktypes);
+    if (ret)
+       goto errout;
+    nctx->in_tkt_ktype_count = ctx->in_tkt_ktype_count;
+
+    ret = copy_ktypes(nctx, ctx->tgs_ktype_count,
+                     ctx->tgs_ktypes, &nctx->in_tkt_ktypes);
+    if (ret)
+       goto errout;
+    nctx->tgs_ktype_count = ctx->tgs_ktype_count;
+
+    if (ctx->os_context->default_ccname != NULL) {
+       nctx->os_context->default_ccname =
+           strdup(ctx->os_context->default_ccname);
+       if (nctx->os_context->default_ccname == NULL) {
+           ret = ENOMEM;
+           goto errout;
+       }
+    }
+    ret = krb5_get_profile(ctx, &nctx->profile);
+    if (ret)
+       goto errout;
+
+errout:
+    if (ret) {
+       krb5_free_context(nctx);
+    } else {
+       *nctx_out = nctx;
+    }
+    return ret;
+}