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 | |
9 | Module Name: |
10 | |
11 | miscpalapi.c |
12 | |
13 | Abstract: |
14 | |
15 | Implementation misc PAL APIs |
16 | |
17 | Revision 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 | |
43 | SET_DEFAULT_DEBUG_CHANNEL(MISC); |
44 | |
45 | static const char URANDOM_DEVICE_NAME[]="/dev/urandom" ; |
46 | |
47 | /*++ |
48 | |
49 | Function : |
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 | --*/ |
60 | BOOL |
61 | PAL_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 | |
105 | EXIT: |
106 | PERF_EXIT(PAL_GetPALDirectoryW); |
107 | return bRet; |
108 | } |
109 | |
110 | BOOL |
111 | PAL_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 | |
148 | Function : |
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 | --*/ |
159 | PALIMPORT |
160 | BOOL |
161 | PALAPI |
162 | PAL_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 | |
192 | PALIMPORT |
193 | BOOL |
194 | PALAPI |
195 | PAL_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 | |
229 | VOID |
230 | PALAPI |
231 | PAL_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 | |