xref: /third_party/openssl/crypto/cryptlib.c (revision e1051a39)
1/*
2 * Copyright 1998-2021 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 "e_os.h"
12#include "crypto/cryptlib.h"
13#include <openssl/safestack.h>
14
15#if defined(_WIN32)
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
32int OPENSSL_isservice(void)
33{
34    /* OneCore API cannot interact with GUI */
35    return 1;
36}
37#  else
38int 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
100int OPENSSL_isservice(void)
101{
102    return 0;
103}
104# endif
105
106void 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
238void 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
249int OPENSSL_isservice(void)
250{
251    return 0;
252}
253#endif
254
255void 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)
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)
281void OPENSSL_VPROC_FUNC(void) {}
282#endif /* __TANDEM */
283