1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/*++
6
7
8
9Module Name:
10
11 miscpalapi.c
12
13Abstract:
14
15 Implementation misc PAL APIs
16
17Revision History:
18
19
20
21--*/
22
23#include "pal/palinternal.h"
24#include "pal/dbgmsg.h"
25#include "pal/file.h"
26#include "pal/process.h"
27#include "pal/module.h"
28#include "pal/malloc.hpp"
29#include "pal/stackstring.hpp"
30
31#include <errno.h>
32#include <unistd.h>
33#include <time.h>
34#include <pthread.h>
35#include <dlfcn.h>
36
37#include <pal_endian.h>
38
39#ifdef __APPLE__
40#include <mach-o/dyld.h>
41#endif // __APPLE__
42
43SET_DEFAULT_DEBUG_CHANNEL(MISC);
44
45static const char URANDOM_DEVICE_NAME[]="/dev/urandom";
46
47/*++
48
49Function :
50
51 PAL_GetPALDirectoryW
52
53 Returns the fully qualified path name
54 where the PALL DLL was loaded from.
55
56 On failure it returns FALSE and sets the
57 proper LastError code.
58
59--*/
60BOOL
61PAL_GetPALDirectoryW(PathWCharString& lpDirectoryName)
62{
63 LPCWSTR lpFullPathAndName = NULL;
64 LPCWSTR lpEndPoint = NULL;
65 BOOL bRet = FALSE;
66
67 PERF_ENTRY(PAL_GetPALDirectoryW);
68
69 MODSTRUCT *module = LOADGetPalLibrary();
70 if (!module)
71 {
72 SetLastError(ERROR_INTERNAL_ERROR);
73 goto EXIT;
74 }
75 lpFullPathAndName = module->lib_name;
76 if (lpFullPathAndName == NULL)
77 {
78 SetLastError(ERROR_INTERNAL_ERROR);
79 goto EXIT;
80 }
81 lpEndPoint = PAL_wcsrchr( lpFullPathAndName, '/' );
82 if ( lpEndPoint )
83 {
84 /* The path that we return is required to have
85 the trailing slash on the end.*/
86 lpEndPoint++;
87
88
89 if(!lpDirectoryName.Set(lpFullPathAndName,lpEndPoint - lpFullPathAndName))
90 {
91 ASSERT( "The buffer was not large enough.\n" );
92 SetLastError( ERROR_INSUFFICIENT_BUFFER );
93 goto EXIT;
94 }
95
96 bRet = TRUE;
97 }
98 else
99 {
100 ASSERT( "Unable to determine the path.\n" );
101 /* Error path, should not be executed. */
102 SetLastError( ERROR_INTERNAL_ERROR );
103 }
104
105EXIT:
106 PERF_EXIT(PAL_GetPALDirectoryW);
107 return bRet;
108}
109
110BOOL
111PAL_GetPALDirectoryA(PathCharString& lpDirectoryName)
112{
113 BOOL bRet;
114 PathWCharString directory;
115
116 PERF_ENTRY(PAL_GetPALDirectoryA);
117
118 bRet = PAL_GetPALDirectoryW(directory);
119
120 if (bRet)
121 {
122
123 int length = WideCharToMultiByte(CP_ACP, 0, directory.GetString(), -1, NULL, 0, NULL, 0);
124 LPSTR DirectoryName = lpDirectoryName.OpenStringBuffer(length);
125 if (NULL == DirectoryName)
126 {
127 SetLastError( ERROR_INSUFFICIENT_BUFFER );
128 bRet = FALSE;
129 }
130
131 length = WideCharToMultiByte(CP_ACP, 0, directory.GetString(), -1, DirectoryName, length, NULL, 0);
132
133 if (0 == length)
134 {
135 bRet = FALSE;
136 length++;
137 }
138
139 lpDirectoryName.CloseBuffer(length - 1);
140 }
141
142 PERF_EXIT(PAL_GetPALDirectoryA);
143 return bRet;
144}
145
146/*++
147
148Function :
149
150 PAL_GetPALDirectoryW
151
152 Returns the fully qualified path name
153 where the PALL DLL was loaded from.
154
155 On failure it returns FALSE and sets the
156 proper LastError code.
157
158--*/
159PALIMPORT
160BOOL
161PALAPI
162PAL_GetPALDirectoryW( OUT LPWSTR lpDirectoryName, IN OUT UINT* cchDirectoryName )
163{
164 PathWCharString directory;
165 BOOL bRet;
166 PERF_ENTRY(PAL_GetPALDirectoryW);
167 ENTRY( "PAL_GetPALDirectoryW( %p, %d )\n", lpDirectoryName, *cchDirectoryName );
168
169 bRet = PAL_GetPALDirectoryW(directory);
170
171 if (bRet) {
172
173 if (directory.GetCount() > *cchDirectoryName)
174 {
175 SetLastError( ERROR_INSUFFICIENT_BUFFER );
176 bRet = FALSE;
177 }
178 else
179 {
180 PAL_wcscpy(lpDirectoryName, directory.GetString());
181 }
182
183 *cchDirectoryName = directory.GetCount();
184 }
185
186 LOGEXIT( "PAL_GetPALDirectoryW returns BOOL %d.\n", bRet);
187 PERF_EXIT(PAL_GetPALDirectoryW);
188 return bRet;
189
190}
191
192PALIMPORT
193BOOL
194PALAPI
195PAL_GetPALDirectoryA(
196 OUT LPSTR lpDirectoryName,
197 IN UINT* cchDirectoryName)
198{
199 BOOL bRet;
200 PathCharString directory;
201
202 PERF_ENTRY(PAL_GetPALDirectoryA);
203 ENTRY( "PAL_GetPALDirectoryA( %p, %d )\n", lpDirectoryName, *cchDirectoryName );
204
205 bRet = PAL_GetPALDirectoryA(directory);
206
207 if (bRet)
208 {
209 if (directory.GetCount() > *cchDirectoryName)
210 {
211 SetLastError( ERROR_INSUFFICIENT_BUFFER );
212 bRet = FALSE;
213 *cchDirectoryName = directory.GetCount();
214 }
215 else if (strcpy_s(lpDirectoryName, directory.GetCount(), directory.GetString()) == SAFECRT_SUCCESS)
216 {
217 }
218 else
219 {
220 bRet = FALSE;
221 }
222 }
223
224 LOGEXIT( "PAL_GetPALDirectoryA returns BOOL %d.\n", bRet);
225 PERF_EXIT(PAL_GetPALDirectoryA);
226 return bRet;
227}
228
229VOID
230PALAPI
231PAL_Random(
232 IN OUT LPVOID lpBuffer,
233 IN DWORD dwLength)
234{
235 int rand_des = -1;
236 DWORD i;
237 long num = 0;
238 static BOOL sMissingDevURandom;
239 static BOOL sInitializedMRand;
240
241 PERF_ENTRY(PAL_Random);
242 ENTRY("PAL_Random(lpBuffer=%p, dwLength=%d)\n", lpBuffer, dwLength);
243
244 if (!sMissingDevURandom)
245 {
246 do
247 {
248 rand_des = open("/dev/urandom", O_RDONLY, O_CLOEXEC);
249 }
250 while ((rand_des == -1) && (errno == EINTR));
251
252 if (rand_des == -1)
253 {
254 if (errno == ENOENT)
255 {
256 sMissingDevURandom = TRUE;
257 }
258 else
259 {
260 ASSERT("PAL__open() failed, errno:%d (%s)\n", errno, strerror(errno));
261 }
262
263 // Back off and try mrand48.
264 }
265 else
266 {
267 DWORD offset = 0;
268 do
269 {
270 DWORD n = read(rand_des, (BYTE*)lpBuffer + offset , dwLength - offset);
271 if (n == -1)
272 {
273 if (errno == EINTR)
274 {
275 continue;
276 }
277 ASSERT("read() failed, errno:%d (%s)\n", errno, strerror(errno));
278
279 break;
280 }
281
282 offset += n;
283 }
284 while (offset != dwLength);
285
286 _ASSERTE(offset == dwLength);
287
288 close(rand_des);
289 }
290 }
291
292 if (!sInitializedMRand)
293 {
294 srand48(time(NULL));
295 sInitializedMRand = TRUE;
296 }
297
298 // always xor srand48 over the whole buffer to get some randomness
299 // in case /dev/urandom is not really random
300
301 for (i = 0; i < dwLength; i++)
302 {
303 if (i % sizeof(long) == 0) {
304 num = mrand48();
305 }
306
307 *(((BYTE*)lpBuffer) + i) ^= num;
308 num >>= 8;
309 }
310
311 LOGEXIT("PAL_Random\n");
312 PERF_EXIT(PAL_Random);
313}
314