1 /*
2 * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10 #include <stdio.h>
11 #include <openssl/opensslv.h>
12 #include "internal/thread_once.h"
13 #include "internal/cryptlib.h"
14 #include "internal/e_os.h"
15
16 #if defined(_WIN32) && defined(OSSL_WINCTX)
17
18 # define TOSTR(x) #x
19 # define MAKESTR(x) TOSTR(x)
20 # define NOQUOTE(x) x
21 # if defined(OSSL_WINCTX)
22 # define REGISTRY_KEY "SOFTWARE\\WOW6432Node\\OpenSSL" "-" MAKESTR(OPENSSL_VERSION_MAJOR) "." MAKESTR(OPENSSL_VERSION_MINOR) "-" MAKESTR(OSSL_WINCTX)
23 # endif
24
25 /**
26 * @brief The directory where OpenSSL is installed.
27 */
28 static char openssldir[MAX_PATH + 1];
29
30 /**
31 * @brief The pointer to the openssldir buffer
32 */
33 static char *openssldirptr = NULL;
34
35 /**
36 * @brief The directory where OpenSSL engines are located.
37 */
38
39 static char enginesdir[MAX_PATH + 1];
40
41 /**
42 * @brief The pointer to the enginesdir buffer
43 */
44 static char *enginesdirptr = NULL;
45
46 /**
47 * @brief The directory where OpenSSL modules are located.
48 */
49 static char modulesdir[MAX_PATH + 1];
50
51 /**
52 * @brief The pointer to the modulesdir buffer
53 */
54 static char *modulesdirptr = NULL;
55
56 /**
57 * @brief Get the list of Windows registry directories.
58 *
59 * This function retrieves a list of Windows registry directories.
60 *
61 * @return A pointer to a char array containing the registry directories.
62 */
get_windows_regdirs(char * dst,DWORD dstsizebytes,LPCWSTR valuename)63 static char *get_windows_regdirs(char *dst, DWORD dstsizebytes, LPCWSTR valuename)
64 {
65 char *retval = NULL;
66 # ifdef REGISTRY_KEY
67 DWORD keysizebytes;
68 DWORD ktype;
69 HKEY hkey;
70 LSTATUS ret;
71 DWORD index = 0;
72 LPCWSTR tempstr = NULL;
73
74 ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
75 TEXT(REGISTRY_KEY), KEY_WOW64_32KEY,
76 KEY_QUERY_VALUE, &hkey);
77 if (ret != ERROR_SUCCESS)
78 goto out;
79
80 /* Always use wide call so we can avoid extra encoding conversions on the output */
81 ret = RegQueryValueExW(hkey, valuename, NULL, &ktype, NULL,
82 &keysizebytes);
83 if (ret != ERROR_SUCCESS)
84 goto out;
85 if (ktype != REG_EXPAND_SZ && ktype != REG_SZ)
86 goto out;
87 if (keysizebytes > MAX_PATH * sizeof(WCHAR))
88 goto out;
89
90 /*
91 * RegQueryValueExW does not guarantee the buffer is null terminated,
92 * so we make space for one in the allocation
93 */
94 tempstr = OPENSSL_zalloc(keysizebytes + sizeof(WCHAR));
95
96 if (tempstr == NULL)
97 goto out;
98
99 if (RegQueryValueExW(hkey, valuename,
100 NULL, &ktype, (LPBYTE)tempstr, &keysizebytes) != ERROR_SUCCESS)
101 goto out;
102
103 if (!WideCharToMultiByte(CP_UTF8, 0, tempstr, -1, dst, dstsizebytes,
104 NULL, NULL))
105 goto out;
106
107 retval = dst;
108 out:
109 OPENSSL_free(tempstr);
110 RegCloseKey(hkey);
111 # endif /* REGISTRY_KEY */
112 return retval;
113 }
114
115 static CRYPTO_ONCE defaults_setup_init = CRYPTO_ONCE_STATIC_INIT;
116
117 /**
118 * @brief Function to setup default values to run once.
119 * Only used in Windows environments. Does run time initialization
120 * of openssldir/modulesdir/enginesdir from the registry
121 */
DEFINE_RUN_ONCE_STATIC(do_defaults_setup)122 DEFINE_RUN_ONCE_STATIC(do_defaults_setup)
123 {
124 get_windows_regdirs(openssldir, sizeof(openssldir), L"OPENSSLDIR");
125 get_windows_regdirs(enginesdir, sizeof(enginesdir), L"ENGINESDIR");
126 get_windows_regdirs(modulesdir, sizeof(modulesdir), L"MODULESDIR");
127
128 /*
129 * Set our pointers only if the directories are fetched properly
130 */
131 if (strlen(openssldir) > 0)
132 openssldirptr = openssldir;
133
134 if (strlen(enginesdir) > 0)
135 enginesdirptr = enginesdir;
136
137 if (strlen(modulesdir) > 0)
138 modulesdirptr = modulesdir;
139
140 return 1;
141 }
142 #endif /* defined(_WIN32) && defined(OSSL_WINCTX) */
143
144 /**
145 * @brief Get the directory where OpenSSL is installed.
146 *
147 * @return A pointer to a string containing the OpenSSL directory path.
148 */
ossl_get_openssldir(void)149 const char *ossl_get_openssldir(void)
150 {
151 #if defined(_WIN32) && defined (OSSL_WINCTX)
152 if (!RUN_ONCE(&defaults_setup_init, do_defaults_setup))
153 return NULL;
154 return (const char *)openssldirptr;
155 # else
156 return OPENSSLDIR;
157 #endif
158 }
159
160 /**
161 * @brief Get the directory where OpenSSL engines are located.
162 *
163 * @return A pointer to a string containing the engines directory path.
164 */
ossl_get_enginesdir(void)165 const char *ossl_get_enginesdir(void)
166 {
167 #if defined(_WIN32) && defined (OSSL_WINCTX)
168 if (!RUN_ONCE(&defaults_setup_init, do_defaults_setup))
169 return NULL;
170 return (const char *)enginesdirptr;
171 #else
172 return ENGINESDIR;
173 #endif
174 }
175
176 /**
177 * @brief Get the directory where OpenSSL modules are located.
178 *
179 * @return A pointer to a string containing the modules directory path.
180 */
ossl_get_modulesdir(void)181 const char *ossl_get_modulesdir(void)
182 {
183 #if defined(_WIN32) && defined(OSSL_WINCTX)
184 if (!RUN_ONCE(&defaults_setup_init, do_defaults_setup))
185 return NULL;
186 return (const char *)modulesdirptr;
187 #else
188 return MODULESDIR;
189 #endif
190 }
191
192 /**
193 * @brief Get the build time defined windows installer context
194 *
195 * @return A char pointer to a string representing the windows install context
196 */
ossl_get_wininstallcontext(void)197 const char *ossl_get_wininstallcontext(void)
198 {
199 #if defined(_WIN32) && defined (OSSL_WINCTX)
200 return MAKESTR(OSSL_WINCTX);
201 #else
202 return "Undefined";
203 #endif
204 }
205