xref: /openssl/crypto/cryptlib.c (revision da1c088f)
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) ||
70         GetLastError() != ERROR_INSUFFICIENT_BUFFER)
71         return -1;
72 
73     if (len > 512)
74         return -1;              /* paranoia */
75     len++, len &= ~1;           /* paranoia */
76     name = (WCHAR *)alloca(len + sizeof(WCHAR));
77     if (!GetUserObjectInformationW(h, UOI_NAME, name, len, &len))
78         return -1;
79 
80     len++, len &= ~1;           /* paranoia */
81     name[len / sizeof(WCHAR)] = L'\0'; /* paranoia */
82 #   if 1
83     /*
84      * This doesn't cover "interactive" services [working with real
85      * WinSta0's] nor programs started non-interactively by Task Scheduler
86      * [those are working with SAWinSta].
87      */
88     if (wcsstr(name, L"Service-0x"))
89         return 1;
90 #   else
91     /* This covers all non-interactive programs such as services. */
92     if (!wcsstr(name, L"WinSta0"))
93         return 1;
94 #   endif
95     else
96         return 0;
97 }
98 #  endif
99 # else
OPENSSL_isservice(void)100 int OPENSSL_isservice(void)
101 {
102     return 0;
103 }
104 # endif
105 
OPENSSL_showfatal(const char * fmta,...)106 void OPENSSL_showfatal(const char *fmta, ...)
107 {
108     va_list ap;
109     TCHAR buf[256];
110     const TCHAR *fmt;
111     /*
112      * First check if it's a console application, in which case the
113      * error message would be printed to standard error.
114      * Windows CE does not have a concept of a console application,
115      * so we need to guard the check.
116      */
117 # ifdef STD_ERROR_HANDLE
118     HANDLE h;
119 
120     if ((h = GetStdHandle(STD_ERROR_HANDLE)) != NULL &&
121         GetFileType(h) != FILE_TYPE_UNKNOWN) {
122         /* must be console application */
123         int len;
124         DWORD out;
125 
126         va_start(ap, fmta);
127         len = _vsnprintf((char *)buf, sizeof(buf), fmta, ap);
128         WriteFile(h, buf, len < 0 ? sizeof(buf) : (DWORD) len, &out, NULL);
129         va_end(ap);
130         return;
131     }
132 # endif
133 
134     if (sizeof(TCHAR) == sizeof(char))
135         fmt = (const TCHAR *)fmta;
136     else
137         do {
138             int keepgoing;
139             size_t len_0 = strlen(fmta) + 1, i;
140             WCHAR *fmtw;
141 
142             fmtw = (WCHAR *)alloca(len_0 * sizeof(WCHAR));
143             if (fmtw == NULL) {
144                 fmt = (const TCHAR *)L"no stack?";
145                 break;
146             }
147             if (!MultiByteToWideChar(CP_ACP, 0, fmta, len_0, fmtw, len_0))
148                 for (i = 0; i < len_0; i++)
149                     fmtw[i] = (WCHAR)fmta[i];
150             for (i = 0; i < len_0; i++) {
151                 if (fmtw[i] == L'%')
152                     do {
153                         keepgoing = 0;
154                         switch (fmtw[i + 1]) {
155                         case L'0':
156                         case L'1':
157                         case L'2':
158                         case L'3':
159                         case L'4':
160                         case L'5':
161                         case L'6':
162                         case L'7':
163                         case L'8':
164                         case L'9':
165                         case L'.':
166                         case L'*':
167                         case L'-':
168                             i++;
169                             keepgoing = 1;
170                             break;
171                         case L's':
172                             fmtw[i + 1] = L'S';
173                             break;
174                         case L'S':
175                             fmtw[i + 1] = L's';
176                             break;
177                         case L'c':
178                             fmtw[i + 1] = L'C';
179                             break;
180                         case L'C':
181                             fmtw[i + 1] = L'c';
182                             break;
183                         }
184                     } while (keepgoing);
185             }
186             fmt = (const TCHAR *)fmtw;
187         } while (0);
188 
189     va_start(ap, fmta);
190     _vsntprintf(buf, OSSL_NELEM(buf) - 1, fmt, ap);
191     buf[OSSL_NELEM(buf) - 1] = _T('\0');
192     va_end(ap);
193 
194 # if defined(_WIN32_WINNT) && _WIN32_WINNT>=0x0333
195 #  ifdef OPENSSL_SYS_WIN_CORE
196     /* ONECORE is always NONGUI and NT >= 0x0601 */
197 #   if !defined(NDEBUG)
198         /*
199         * We are in a situation where we tried to report a critical
200         * error and this failed for some reason. As a last resort,
201         * in debug builds, send output to the debugger or any other
202         * tool like DebugView which can monitor the output.
203         */
204         OutputDebugString(buf);
205 #   endif
206 #  else
207     /* this -------------v--- guards NT-specific calls */
208     if (check_winnt() && OPENSSL_isservice() > 0) {
209         HANDLE hEventLog = RegisterEventSource(NULL, _T("OpenSSL"));
210 
211         if (hEventLog != NULL) {
212             const TCHAR *pmsg = buf;
213 
214             if (!ReportEvent(hEventLog, EVENTLOG_ERROR_TYPE, 0, 0, NULL,
215                              1, 0, &pmsg, NULL)) {
216 #   if !defined(NDEBUG)
217                 /*
218                  * We are in a situation where we tried to report a critical
219                  * error and this failed for some reason. As a last resort,
220                  * in debug builds, send output to the debugger or any other
221                  * tool like DebugView which can monitor the output.
222                  */
223                 OutputDebugString(pmsg);
224 #   endif
225             }
226 
227             (void)DeregisterEventSource(hEventLog);
228         }
229     } else {
230         MessageBox(NULL, buf, _T("OpenSSL: FATAL"), MB_OK | MB_ICONERROR);
231     }
232 #  endif
233 # else
234     MessageBox(NULL, buf, _T("OpenSSL: FATAL"), MB_OK | MB_ICONERROR);
235 # endif
236 }
237 #else
OPENSSL_showfatal(const char * fmta,...)238 void OPENSSL_showfatal(const char *fmta, ...)
239 {
240 #ifndef OPENSSL_NO_STDIO
241     va_list ap;
242 
243     va_start(ap, fmta);
244     vfprintf(stderr, fmta, ap);
245     va_end(ap);
246 #endif
247 }
248 
OPENSSL_isservice(void)249 int OPENSSL_isservice(void)
250 {
251     return 0;
252 }
253 #endif
254 
OPENSSL_die(const char * message,const char * file,int line)255 void OPENSSL_die(const char *message, const char *file, int line)
256 {
257     OPENSSL_showfatal("%s:%d: OpenSSL internal error: %s\n",
258                       file, line, message);
259 #if !defined(_WIN32) || defined(OPENSSL_SYS_UEFI)
260     abort();
261 #else
262     /*
263      * Win32 abort() customarily shows a dialog, but we just did that...
264      */
265 # if !defined(_WIN32_WCE)
266     raise(SIGABRT);
267 # endif
268     _exit(3);
269 #endif
270 }
271 
272 #if defined(__TANDEM) && defined(OPENSSL_VPROC)
273 /*
274  * Define a VPROC function for HP NonStop build crypto library.
275  * This is used by platform version identification tools.
276  * Do not inline this procedure or make it static.
277  */
278 # define OPENSSL_VPROC_STRING_(x)    x##_CRYPTO
279 # define OPENSSL_VPROC_STRING(x)     OPENSSL_VPROC_STRING_(x)
280 # define OPENSSL_VPROC_FUNC          OPENSSL_VPROC_STRING(OPENSSL_VPROC)
OPENSSL_VPROC_FUNC(void)281 void OPENSSL_VPROC_FUNC(void) {}
282 #endif /* __TANDEM */
283