cryptlib.c: allow application to override OPENSSL_isservice.
[openssl.git] / crypto / cryptlib.c
index 33c70afa33333aa9af1b6488ecd54737fc906aa5..af1dbfb81d7ecaa091044cda15eeb94363db3e04 100644 (file)
@@ -122,7 +122,6 @@ static double SSLeay_MSVC5_hack=0.0; /* and for VC1.5 */
 #endif
 
 DECLARE_STACK_OF(CRYPTO_dynlock)
-IMPLEMENT_STACK_OF(CRYPTO_dynlock)
 
 /* real #defines in crypto.h, keep these upto date */
 static const char* const lock_names[CRYPTO_NUM_LOCKS] =
@@ -166,14 +165,16 @@ static const char* const lock_names[CRYPTO_NUM_LOCKS] =
        "ec_pre_comp",
        "store",
        "comp",
-#if CRYPTO_NUM_LOCKS != 39
+       "fips",
+       "fips2",
+#if CRYPTO_NUM_LOCKS != 41
 # error "Inconsistency between crypto.h and cryptlib.c"
 #endif
        };
 
 /* This is for applications to allocate new type names in the non-dynamic
    array of lock names.  These are numbered with positive numbers.  */
-static STACK *app_locks=NULL;
+static STACK_OF(OPENSSL_STRING) *app_locks=NULL;
 
 /* For applications that want a more dynamic way of handling threads, the
    following stack is used.  These are externally numbered with negative
@@ -185,8 +186,10 @@ static void (MS_FAR *locking_callback)(int mode,int type,
        const char *file,int line)=0;
 static int (MS_FAR *add_lock_callback)(int *pointer,int amount,
        int type,const char *file,int line)=0;
+#ifndef OPENSSL_NO_DEPRECATED
 static unsigned long (MS_FAR *id_callback)(void)=0;
-static void *(MS_FAR *idptr_callback)(void)=0;
+#endif
+static void (MS_FAR *threadid_callback)(CRYPTO_THREADID *)=0;
 static struct CRYPTO_dynlock_value *(MS_FAR *dynlock_create_callback)
        (const char *file,int line)=0;
 static void (MS_FAR *dynlock_lock_callback)(int mode,
@@ -202,12 +205,12 @@ int CRYPTO_get_new_lockid(char *name)
 #if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_WIN16)
        /* A hack to make Visual C++ 5.0 work correctly when linking as
         * a DLL using /MT. Without this, the application cannot use
-        * and floating point printf's.
+        * any floating point printf's.
         * It also seems to be needed for Visual C 1.5 (win16) */
        SSLeay_MSVC5_hack=(double)name[0]*(double)name[1];
 #endif
 
-       if ((app_locks == NULL) && ((app_locks=sk_new_null()) == NULL))
+       if ((app_locks == NULL) && ((app_locks=sk_OPENSSL_STRING_new_null()) == NULL))
                {
                CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_LOCKID,ERR_R_MALLOC_FAILURE);
                return(0);
@@ -217,7 +220,7 @@ int CRYPTO_get_new_lockid(char *name)
                CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_LOCKID,ERR_R_MALLOC_FAILURE);
                return(0);
                }
-       i=sk_push(app_locks,str);
+       i=sk_OPENSSL_STRING_push(app_locks,str);
        if (!i)
                OPENSSL_free(str);
        else
@@ -415,6 +418,108 @@ void CRYPTO_set_add_lock_callback(int (*func)(int *num,int mount,int type,
        add_lock_callback=func;
        }
 
+/* the memset() here and in set_pointer() seem overkill, but for the sake of
+ * CRYPTO_THREADID_cmp() this avoids any platform silliness that might cause two
+ * "equal" THREADID structs to not be memcmp()-identical. */
+void CRYPTO_THREADID_set_numeric(CRYPTO_THREADID *id, unsigned long val)
+       {
+       memset(id, 0, sizeof(*id));
+       id->val = val;
+       }
+
+static const unsigned char hash_coeffs[] = { 3, 5, 7, 11, 13, 17, 19, 23 };
+void CRYPTO_THREADID_set_pointer(CRYPTO_THREADID *id, void *ptr)
+       {
+       unsigned char *dest = (void *)&id->val;
+       unsigned int accum = 0;
+       unsigned char dnum = sizeof(id->val);
+
+       memset(id, 0, sizeof(*id));
+       id->ptr = ptr;
+       if (sizeof(id->val) >= sizeof(id->ptr))
+               {
+               /* 'ptr' can be embedded in 'val' without loss of uniqueness */
+               id->val = (unsigned long)id->ptr;
+               return;
+               }
+       /* hash ptr ==> val. Each byte of 'val' gets the mod-256 total of a
+        * linear function over the bytes in 'ptr', the co-efficients of which
+        * are a sequence of low-primes (hash_coeffs is an 8-element cycle) -
+        * the starting prime for the sequence varies for each byte of 'val'
+        * (unique polynomials unless pointers are >64-bit). For added spice,
+        * the totals accumulate rather than restarting from zero, and the index
+        * of the 'val' byte is added each time (position dependence). If I was
+        * a black-belt, I'd scan big-endian pointers in reverse to give
+        * low-order bits more play, but this isn't crypto and I'd prefer nobody
+        * mistake it as such. Plus I'm lazy. */
+       while (dnum--)
+               {
+               const unsigned char *src = (void *)&id->ptr;
+               unsigned char snum = sizeof(id->ptr);
+               while (snum--)
+                       accum += *(src++) * hash_coeffs[(snum + dnum) & 7];
+               accum += dnum;
+               *(dest++) = accum & 255;
+               }
+       }
+
+int CRYPTO_THREADID_set_callback(void (*func)(CRYPTO_THREADID *))
+       {
+       if (threadid_callback)
+               return 0;
+       threadid_callback = func;
+       return 1;
+       }
+
+void (*CRYPTO_THREADID_get_callback(void))(CRYPTO_THREADID *)
+       {
+       return threadid_callback;
+       }
+
+void CRYPTO_THREADID_current(CRYPTO_THREADID *id)
+       {
+       if (threadid_callback)
+               {
+               threadid_callback(id);
+               return;
+               }
+#ifndef OPENSSL_NO_DEPRECATED
+       /* If the deprecated callback was set, fall back to that */
+       if (id_callback)
+               {
+               CRYPTO_THREADID_set_numeric(id, id_callback());
+               return;
+               }
+#endif
+       /* Else pick a backup */
+#ifdef OPENSSL_SYS_WIN16
+       CRYPTO_THREADID_set_numeric(id, (unsigned long)GetCurrentTask());
+#elif defined(OPENSSL_SYS_WIN32)
+       CRYPTO_THREADID_set_numeric(id, (unsigned long)GetCurrentThreadId());
+#elif defined(OPENSSL_SYS_BEOS)
+       CRYPTO_THREADID_set_numeric(id, (unsigned long)find_thread(NULL));
+#else
+       /* For everything else, default to using the address of 'errno' */
+       CRYPTO_THREADID_set_pointer(id, &errno);
+#endif
+       }
+
+int CRYPTO_THREADID_cmp(const CRYPTO_THREADID *a, const CRYPTO_THREADID *b)
+       {
+       return memcmp(a, b, sizeof(*a));
+       }
+
+void CRYPTO_THREADID_cpy(CRYPTO_THREADID *dest, const CRYPTO_THREADID *src)
+       {
+       memcpy(dest, src, sizeof(*src));
+       }
+
+unsigned long CRYPTO_THREADID_hash(const CRYPTO_THREADID *id)
+       {
+       return id->val;
+       }
+
+#ifndef OPENSSL_NO_DEPRECATED
 unsigned long (*CRYPTO_get_id_callback(void))(void)
        {
        return(id_callback);
@@ -447,33 +552,13 @@ unsigned long CRYPTO_thread_id(void)
                ret=id_callback();
        return(ret);
        }
-
-void *(*CRYPTO_get_idptr_callback(void))(void)
-       {
-       return(idptr_callback);
-       }
-
-void CRYPTO_set_idptr_callback(void *(*func)(void))
-       {
-       idptr_callback=func;
-       }
-
-void *CRYPTO_thread_idptr(void)
-       {
-       void *ret=NULL;
-
-       if (idptr_callback == NULL)
-               ret = &errno;
-       else
-               ret = idptr_callback();
-
-       return ret;
-       }
+#endif
 
 void CRYPTO_lock(int mode, int type, const char *file, int line)
        {
 #ifdef LOCK_DEBUG
                {
+               CRYPTO_THREADID id;
                char *rw_text,*operation_text;
 
                if (mode & CRYPTO_LOCK)
@@ -490,8 +575,9 @@ void CRYPTO_lock(int mode, int type, const char *file, int line)
                else
                        rw_text="ERROR";
 
-               fprintf(stderr,"lock:%08lx/%08p:(%s)%s %-18s %s:%d\n",
-                       CRYPTO_thread_id(), CRYPTO_thread_idptr(), rw_text, operation_text,
+               CRYPTO_THREADID_current(&id);
+               fprintf(stderr,"lock:%08lx:(%s)%s %-18s %s:%d\n",
+                       CRYPTO_THREADID_hash(&id), rw_text, operation_text,
                        CRYPTO_get_lock_name(type), file, line);
                }
 #endif
@@ -527,11 +613,14 @@ int CRYPTO_add_lock(int *pointer, int amount, int type, const char *file,
 
                ret=add_lock_callback(pointer,amount,type,file,line);
 #ifdef LOCK_DEBUG
-               fprintf(stderr,"ladd:%08lx/%0xp:%2d+%2d->%2d %-18s %s:%d\n",
-                       CRYPTO_thread_id(), CRYPTO_thread_idptr(),
-                       before,amount,ret,
+               {
+               CRYPTO_THREADID id;
+               CRYPTO_THREADID_current(&id);
+               fprintf(stderr,"ladd:%08lx:%2d+%2d->%2d %-18s %s:%d\n",
+                       CRYPTO_THREADID_hash(&id), before,amount,ret,
                        CRYPTO_get_lock_name(type),
                        file,line);
+               }
 #endif
                }
        else
@@ -540,11 +629,15 @@ int CRYPTO_add_lock(int *pointer, int amount, int type, const char *file,
 
                ret= *pointer+amount;
 #ifdef LOCK_DEBUG
-               fprintf(stderr,"ladd:%08lx/%0xp:%2d+%2d->%2d %-18s %s:%d\n",
-                       CRYPTO_thread_id(), CRYPTO_thread_idptr(),
+               {
+               CRYPTO_THREADID id;
+               CRYPTO_THREADID_current(&id);
+               fprintf(stderr,"ladd:%08lx:%2d+%2d->%2d %-18s %s:%d\n",
+                       CRYPTO_THREADID_hash(&id),
                        *pointer,amount,ret,
                        CRYPTO_get_lock_name(type),
                        file,line);
+               }
 #endif
                *pointer=ret;
                CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_WRITE,type,file,line);
@@ -558,43 +651,56 @@ const char *CRYPTO_get_lock_name(int type)
                return("dynamic");
        else if (type < CRYPTO_NUM_LOCKS)
                return(lock_names[type]);
-       else if (type-CRYPTO_NUM_LOCKS > sk_num(app_locks))
+       else if (type-CRYPTO_NUM_LOCKS > sk_OPENSSL_STRING_num(app_locks))
                return("ERROR");
        else
-               return(sk_value(app_locks,type-CRYPTO_NUM_LOCKS));
+               return(sk_OPENSSL_STRING_value(app_locks,type-CRYPTO_NUM_LOCKS));
        }
 
 #if    defined(__i386)   || defined(__i386__)   || defined(_M_IX86) || \
        defined(__INTEL__) || \
-       defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64)
+       defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64)
 
-unsigned long  OPENSSL_ia32cap_P=0;
-unsigned long *OPENSSL_ia32cap_loc(void) { return &OPENSSL_ia32cap_P; }
+unsigned int  OPENSSL_ia32cap_P[2];
+unsigned int *OPENSSL_ia32cap_loc(void) { return OPENSSL_ia32cap_P; }
 
 #if defined(OPENSSL_CPUID_OBJ) && !defined(OPENSSL_NO_ASM) && !defined(I386_ONLY)
 #define OPENSSL_CPUID_SETUP
+#if defined(_WIN32)
+typedef unsigned __int64 IA32CAP;
+#else
+typedef unsigned long long IA32CAP;
+#endif
 void OPENSSL_cpuid_setup(void)
 { static int trigger=0;
-  unsigned long OPENSSL_ia32_cpuid(void);
+  IA32CAP OPENSSL_ia32_cpuid(void);
+  IA32CAP vec;
   char *env;
 
     if (trigger)       return;
 
     trigger=1;
     if ((env=getenv("OPENSSL_ia32cap")))
-       OPENSSL_ia32cap_P = strtoul(env,NULL,0)|(1<<10);
+#if defined(_WIN32)
+    {  if (!sscanf(env,"%I64i",&vec)) vec = strtoul(env,NULL,0);   }
+#else
+       vec = strtoull(env,NULL,0);
+#endif
     else
-       OPENSSL_ia32cap_P = OPENSSL_ia32_cpuid()|(1<<10);
+       vec = OPENSSL_ia32_cpuid();
+
     /*
      * |(1<<10) sets a reserved bit to signal that variable
      * was initialized already... This is to avoid interference
      * with cpuid snippets in ELF .init segment.
      */
+    OPENSSL_ia32cap_P[0] = (unsigned int)vec|(1<<10);
+    OPENSSL_ia32cap_P[1] = (unsigned int)(vec>>32);
 }
 #endif
 
 #else
-unsigned long *OPENSSL_ia32cap_loc(void) { return NULL; }
+unsigned int *OPENSSL_ia32cap_loc(void) { return NULL; }
 #endif
 int OPENSSL_NONPIC_relocated = 0;
 #if !defined(OPENSSL_CPUID_SETUP) && !defined(OPENSSL_CPUID_OBJ)
@@ -605,6 +711,8 @@ void OPENSSL_cpuid_setup(void) {}
 #ifdef __CYGWIN__
 /* pick DLL_[PROCESS|THREAD]_[ATTACH|DETACH] definitions */
 #include <windows.h>
+/* this has side-effect of _WIN32 getting defined, which otherwise
+ * is mutually exclusive with __CYGWIN__... */
 #endif
 
 /* All we really need to do is remove the 'error' state when a thread
@@ -647,12 +755,25 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason,
 
 #if defined(_WIN32) && !defined(__CYGWIN__)
 #include <tchar.h>
+#include <signal.h>
 
 #if defined(_WIN32_WINNT) && _WIN32_WINNT>=0x0333
 int OPENSSL_isservice(void)
 { HWINSTA h;
   DWORD len;
   WCHAR *name;
+  static union { void *p; int (*f)(void); } _OPENSSL_isservice = { NULL };
+
+    if (_OPENSSL_isservice.p == NULL) {
+       HANDLE h = GetModuleHandle(NULL);
+       if (h != NULL)
+           _OPENSSL_isservice.p = GetProcAddress(h,"_OPENSSL_isservice");
+       if (_OPENSSL_isservice.p == NULL)
+           _OPENSSL_isservice.p = (void *)-1;
+    }
+
+    if (_OPENSSL_isservice.p != (void *)-1)
+       return (*_OPENSSL_isservice.f)();
 
     (void)GetDesktopWindow(); /* return value is ignored */
 
@@ -751,7 +872,7 @@ void OPENSSL_showfatal (const char *fmta,...)
 
 #if defined(_WIN32_WINNT) && _WIN32_WINNT>=0x0333
     /* this -------------v--- guards NT-specific calls */
-    if (GetVersion() < 0x80000000 && OPENSSL_isservice())
+    if (GetVersion() < 0x80000000 && OPENSSL_isservice() > 0)
     {  HANDLE h = RegisterEventSource(0,_T("OPENSSL"));
        const TCHAR *pmsg=buf;
        ReportEvent(h,EVENTLOG_ERROR_TYPE,0,0,0,1,0,&pmsg,0);
@@ -777,7 +898,13 @@ void OpenSSLDie(const char *file,int line,const char *assertion)
        OPENSSL_showfatal(
                "%s(%d): OpenSSL internal error, assertion failed: %s\n",
                file,line,assertion);
+#if !defined(_WIN32) || defined(__CYGWIN__)
        abort();
+#else
+       /* Win32 abort() customarily shows a dialog, but we just did that... */
+       raise(SIGABRT);
+       _exit(3);
+#endif
        }
 
 void *OPENSSL_stderr(void)     { return stderr; }