xref: /freebsd/crypto/openssl/crypto/cryptlib.c (revision f25b8c9fb4f58cf61adb47d7570abe7caa6d385d)
1 /*
2  * Copyright 1998-2023 The OpenSSL Project Authors. All Rights Reserved.
3  * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
4  *
5  * Licensed under the Apache License 2.0 (the "License").  You may not use
6  * this file except in compliance with the License.  You can obtain a copy
7  * in the file LICENSE in the source distribution or at
8  * https://www.openssl.org/source/license.html
9  */
10 
11 #include "internal/e_os.h"
12 #include "crypto/cryptlib.h"
13 #include <openssl/safestack.h>
14 
15 #if defined(_WIN32) && !defined(OPENSSL_SYS_UEFI)
16 #include <tchar.h>
17 #include <signal.h>
18 #ifdef __WATCOMC__
19 #if defined(_UNICODE) || defined(__UNICODE__)
20 #define _vsntprintf _vsnwprintf
21 #else
22 #define _vsntprintf _vsnprintf
23 #endif
24 #endif
25 #ifdef _MSC_VER
26 #define alloca _alloca
27 #endif
28 
29 #if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0333
30 #ifdef OPENSSL_SYS_WIN_CORE
31 
OPENSSL_isservice(void)32 int OPENSSL_isservice(void)
33 {
34     /* OneCore API cannot interact with GUI */
35     return 1;
36 }
37 #else
OPENSSL_isservice(void)38 int OPENSSL_isservice(void)
39 {
40     HWINSTA h;
41     DWORD len;
42     WCHAR *name;
43     static union {
44         void *p;
45         FARPROC f;
46     } _OPENSSL_isservice = {
47         NULL
48     };
49 
50     if (_OPENSSL_isservice.p == NULL) {
51         HANDLE mod = GetModuleHandle(NULL);
52         FARPROC f = NULL;
53 
54         if (mod != NULL)
55             f = GetProcAddress(mod, "_OPENSSL_isservice");
56         if (f == NULL)
57             _OPENSSL_isservice.p = (void *)-1;
58         else
59             _OPENSSL_isservice.f = f;
60     }
61 
62     if (_OPENSSL_isservice.p != (void *)-1)
63         return (*_OPENSSL_isservice.f)();
64 
65     h = GetProcessWindowStation();
66     if (h == NULL)
67         return -1;
68 
69     if (GetUserObjectInformationW(h, UOI_NAME, NULL, 0, &len) || GetLastError() != ERROR_INSUFFICIENT_BUFFER)
70         return -1;
71 
72     if (len > 512)
73         return -1; /* paranoia */
74     len++, len &= ~1; /* paranoia */
75     name = (WCHAR *)alloca(len + sizeof(WCHAR));
76     if (!GetUserObjectInformationW(h, UOI_NAME, name, len, &len))
77         return -1;
78 
79     len++, len &= ~1; /* paranoia */
80     name[len / sizeof(WCHAR)] = L'\0'; /* paranoia */
81 #if 1
82     /*
83      * This doesn't cover "interactive" services [working with real
84      * WinSta0's] nor programs started non-interactively by Task Scheduler
85      * [those are working with SAWinSta].
86      */
87     if (wcsstr(name, L"Service-0x"))
88         return 1;
89 #else
90     /* This covers all non-interactive programs such as services. */
91     if (!wcsstr(name, L"WinSta0"))
92         return 1;
93 #endif
94     else
95         return 0;
96 }
97 #endif
98 #else
OPENSSL_isservice(void)99 int OPENSSL_isservice(void)
100 {
101     return 0;
102 }
103 #endif
104 
OPENSSL_showfatal(const char * fmta,...)105 void OPENSSL_showfatal(const char *fmta, ...)
106 {
107     va_list ap;
108     TCHAR buf[256];
109     const TCHAR *fmt;
110     /*
111      * First check if it's a console application, in which case the
112      * error message would be printed to standard error.
113      * Windows CE does not have a concept of a console application,
114      * so we need to guard the check.
115      */
116 #ifdef STD_ERROR_HANDLE
117     HANDLE h;
118 
119     if ((h = GetStdHandle(STD_ERROR_HANDLE)) != NULL && GetFileType(h) != FILE_TYPE_UNKNOWN) {
120         /* must be console application */
121         int len;
122         DWORD out;
123 
124         va_start(ap, fmta);
125         len = _vsnprintf((char *)buf, sizeof(buf), fmta, ap);
126         WriteFile(h, buf, len < 0 ? sizeof(buf) : (DWORD)len, &out, NULL);
127         va_end(ap);
128         return;
129     }
130 #endif
131 
132     if (sizeof(TCHAR) == sizeof(char))
133         fmt = (const TCHAR *)fmta;
134     else
135         do {
136             int keepgoing;
137             size_t len_0 = strlen(fmta) + 1, i;
138             WCHAR *fmtw;
139 
140             fmtw = (WCHAR *)alloca(len_0 * sizeof(WCHAR));
141             if (fmtw == NULL) {
142                 fmt = (const TCHAR *)L"no stack?";
143                 break;
144             }
145             if (!MultiByteToWideChar(CP_ACP, 0, fmta, len_0, fmtw, len_0))
146                 for (i = 0; i < len_0; i++)
147                     fmtw[i] = (WCHAR)fmta[i];
148             for (i = 0; i < len_0; i++) {
149                 if (fmtw[i] == L'%')
150                     do {
151                         keepgoing = 0;
152                         switch (fmtw[i + 1]) {
153                         case L'0':
154                         case L'1':
155                         case L'2':
156                         case L'3':
157                         case L'4':
158                         case L'5':
159                         case L'6':
160                         case L'7':
161                         case L'8':
162                         case L'9':
163                         case L'.':
164                         case L'*':
165                         case L'-':
166                             i++;
167                             keepgoing = 1;
168                             break;
169                         case L's':
170                             fmtw[i + 1] = L'S';
171                             break;
172                         case L'S':
173                             fmtw[i + 1] = L's';
174                             break;
175                         case L'c':
176                             fmtw[i + 1] = L'C';
177                             break;
178                         case L'C':
179                             fmtw[i + 1] = L'c';
180                             break;
181                         }
182                     } while (keepgoing);
183             }
184             fmt = (const TCHAR *)fmtw;
185         } while (0);
186 
187     va_start(ap, fmta);
188     _vsntprintf(buf, OSSL_NELEM(buf) - 1, fmt, ap);
189     buf[OSSL_NELEM(buf) - 1] = _T('\0');
190     va_end(ap);
191 
192 #if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0333
193 #ifdef OPENSSL_SYS_WIN_CORE
194     /* ONECORE is always NONGUI and NT >= 0x0601 */
195 #if !defined(NDEBUG)
196     /*
197      * We are in a situation where we tried to report a critical
198      * error and this failed for some reason. As a last resort,
199      * in debug builds, send output to the debugger or any other
200      * tool like DebugView which can monitor the output.
201      */
202     OutputDebugString(buf);
203 #endif
204 #else
205     /* this -------------v--- guards NT-specific calls */
206     if (check_winnt() && OPENSSL_isservice() > 0) {
207         HANDLE hEventLog = RegisterEventSource(NULL, _T("OpenSSL"));
208 
209         if (hEventLog != NULL) {
210             const TCHAR *pmsg = buf;
211 
212             if (!ReportEvent(hEventLog, EVENTLOG_ERROR_TYPE, 0, 0, NULL,
213                     1, 0, &pmsg, NULL)) {
214 #if !defined(NDEBUG)
215                 /*
216                  * We are in a situation where we tried to report a critical
217                  * error and this failed for some reason. As a last resort,
218                  * in debug builds, send output to the debugger or any other
219                  * tool like DebugView which can monitor the output.
220                  */
221                 OutputDebugString(pmsg);
222 #endif
223             }
224 
225             (void)DeregisterEventSource(hEventLog);
226         }
227     } else {
228         MessageBox(NULL, buf, _T("OpenSSL: FATAL"), MB_OK | MB_ICONERROR);
229     }
230 #endif
231 #else
232     MessageBox(NULL, buf, _T("OpenSSL: FATAL"), MB_OK | MB_ICONERROR);
233 #endif
234 }
235 #else
OPENSSL_showfatal(const char * fmta,...)236 void OPENSSL_showfatal(const char *fmta, ...)
237 {
238 #ifndef OPENSSL_NO_STDIO
239     va_list ap;
240 
241     va_start(ap, fmta);
242     vfprintf(stderr, fmta, ap);
243     va_end(ap);
244 #endif
245 }
246 
OPENSSL_isservice(void)247 int OPENSSL_isservice(void)
248 {
249     return 0;
250 }
251 #endif
252 
OPENSSL_die(const char * message,const char * file,int line)253 void OPENSSL_die(const char *message, const char *file, int line)
254 {
255     OPENSSL_showfatal("%s:%d: OpenSSL internal error: %s\n",
256         file, line, message);
257 #if !defined(_WIN32) || defined(OPENSSL_SYS_UEFI)
258     abort();
259 #else
260     /*
261      * Win32 abort() customarily shows a dialog, but we just did that...
262      */
263 #if !defined(_WIN32_WCE)
264     raise(SIGABRT);
265 #endif
266     _exit(3);
267 #endif
268 }
269 
270 #if defined(__TANDEM) && defined(OPENSSL_VPROC)
271 /*
272  * Define a VPROC function for HP NonStop build crypto library.
273  * This is used by platform version identification tools.
274  * Do not inline this procedure or make it static.
275  */
276 #define OPENSSL_VPROC_STRING_(x) x##_CRYPTO
277 #define OPENSSL_VPROC_STRING(x) OPENSSL_VPROC_STRING_(x)
278 #define OPENSSL_VPROC_FUNC OPENSSL_VPROC_STRING(OPENSSL_VPROC)
OPENSSL_VPROC_FUNC(void)279 void OPENSSL_VPROC_FUNC(void) { }
280 #endif /* __TANDEM */
281