[Tizen] Unify dnetmemoryenumlib terms to match the codebase (#291)
[platform/upstream/coreclr.git] / src / utilcode / securitywrapper.cpp
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 // File: SecurityWrapper.cpp
6 //
7
8 // 
9 // Wrapper around Win32 Security functions
10 //
11 //*****************************************************************************
12
13 #include "stdafx.h"
14
15 #include "securitywrapper.h"
16 #include "ex.h"
17 #include "holder.h"
18
19
20 // For GetSidFromProcess*
21 #include <tlhelp32.h>
22 #include "wtsapi32.h"
23
24
25 //-----------------------------------------------------------------------------
26 // Constructor for Sid wrapper class.
27 // pSid - OS sid to wrap
28 //-----------------------------------------------------------------------------
29 Sid::Sid(PSID pSid)
30 {
31     _ASSERTE(pSid != NULL);
32     m_pSid = pSid;
33 }
34
35 //-----------------------------------------------------------------------------
36 // Aesthetic wrapper for Sid equality
37 //-----------------------------------------------------------------------------
38 bool Sid::Equals(PSID a, PSID b)
39
40     return EqualSid(a, b) != 0; 
41 }
42
43 //-----------------------------------------------------------------------------
44 // Ctor for SidBuffer class
45 //-----------------------------------------------------------------------------
46 SidBuffer::SidBuffer()
47 {
48     m_pBuffer = NULL;
49 }
50
51 //-----------------------------------------------------------------------------
52 // Dtor for SidBuffer class.
53 //-----------------------------------------------------------------------------
54 SidBuffer::~SidBuffer()
55 {
56     delete [] m_pBuffer;
57 }
58
59 //-----------------------------------------------------------------------------
60 // Get the underlying sid
61 // Caller assumes SidBuffer has been initialized.
62 //-----------------------------------------------------------------------------
63 Sid SidBuffer::GetSid()
64 {
65     _ASSERTE(m_pBuffer != NULL);
66     Sid s((PSID) m_pBuffer);
67     return s;
68 }
69
70 // ----------------------------------------------------------------------------
71 // Used by GetSidFromProcessWorker to determine which SID from the
72 // process token to use when initializing the SID
73 enum SidType
74 {
75     // Use TokenOwner: the default owner SID used for newly created objects
76     kOwnerSid,
77
78     // Use TokenUser: the user account from the token
79     kUserSid,
80 };
81
82 // ----------------------------------------------------------------------------
83 // GetSidFromProcessWorker
84 //
85 // Description: 
86 //    Internal helper.  Gets the SID for the given process and given sid type
87 //
88 // Arguments:
89 //    * dwProcessId - [in] Process to get SID from
90 //    * sidType - [in] Type of sid to get (owner or user)
91 //    * ppSid - [out] SID found.  Caller responsible for deleting this memory.
92 //
93 // Return Value:
94 //    HRESULT indicating success / failure.
95 //
96 // Notes:
97 //    * Caller owns deleting (*ppSid) when done with the SID
98 //
99
100 HRESULT GetSidFromProcessWorker(DWORD dwProcessId, SidType sidType, PSID *ppSid)
101 {
102     CONTRACTL
103     {
104         NOTHROW;
105         GC_NOTRIGGER;
106     }
107     CONTRACTL_END;
108
109     HRESULT                     hr = S_OK;
110     TOKEN_USER                  *pTokUser = NULL;
111     HANDLE                      hProc = INVALID_HANDLE_VALUE;
112     HANDLE                      hToken = INVALID_HANDLE_VALUE;
113     DWORD                       dwRetLength;
114     LPVOID                      pvTokenInfo = NULL;
115     TOKEN_INFORMATION_CLASS     tokenInfoClass;
116     PSID                        pSidFromTokenInfo = NULL;
117     DWORD                       cbSid;
118     PSID                        pSid = NULL;
119
120     LOG((LF_CORDB, LL_INFO10000,
121          "SecurityUtil::GetSidFromProcess: 0x%08x\n",
122          dwProcessId));
123
124     _ASSERTE(ppSid);
125     *ppSid = NULL;
126
127     _ASSERTE((sidType == kOwnerSid) || (sidType == kUserSid));
128     tokenInfoClass = (sidType == kOwnerSid) ? TokenOwner : TokenUser;
129
130     hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwProcessId);
131
132     if (hProc == NULL)
133     {
134         hr = HRESULT_FROM_GetLastError();
135         goto exit;
136     }
137     if (!OpenProcessToken(hProc, TOKEN_QUERY, &hToken))
138     {
139         hr = HRESULT_FROM_GetLastError();
140         goto exit;
141     }
142
143     // figure out the length
144     GetTokenInformation(hToken, tokenInfoClass, NULL, 0, &dwRetLength);
145     _ASSERTE(dwRetLength);
146
147     pvTokenInfo = new (nothrow) BYTE[dwRetLength];
148     if (pvTokenInfo == NULL)
149     {
150         hr = E_OUTOFMEMORY;
151         goto exit;
152     }
153
154     if (!GetTokenInformation(hToken, tokenInfoClass, pvTokenInfo, dwRetLength, &dwRetLength))
155     {
156         hr = HRESULT_FROM_GetLastError();
157         goto exit;
158     }
159
160     // Copy over the SID
161     pSidFromTokenInfo = 
162         (sidType == kOwnerSid) ?
163             ((TOKEN_OWNER *) pvTokenInfo)->Owner :
164             ((TOKEN_USER *) pvTokenInfo)->User.Sid;
165     cbSid = GetLengthSid(pSidFromTokenInfo);
166     pSid = new (nothrow) BYTE[cbSid];
167     if (pSid == NULL)
168     {
169         hr = E_OUTOFMEMORY;
170     }
171     else
172     {
173         if (!CopySid(cbSid, pSid, pSidFromTokenInfo))
174         {
175             hr = HRESULT_FROM_GetLastError();
176             goto exit;
177         }
178     }
179
180     *ppSid = pSid;
181     pSid = NULL;
182     
183 exit:
184     if (hToken != INVALID_HANDLE_VALUE)
185     {
186         CloseHandle(hToken);
187     }
188     if (hProc != INVALID_HANDLE_VALUE)
189     {
190         // clean up
191         CloseHandle(hProc);
192     }
193     if (pvTokenInfo)
194     {
195         delete [] (reinterpret_cast<BYTE*>(pvTokenInfo));
196     }
197
198     if (pSid)
199     {
200         delete [] (reinterpret_cast<BYTE*>(pSid));
201     }
202
203     LOG((LF_CORDB, LL_INFO10000,
204          "SecurityUtil::GetSidFromProcess return hr : 0x%08x\n",
205          hr));
206
207     return hr;
208 }
209
210 #ifndef FEATURE_CORESYSTEM
211 //-----------------------------------------------------------------------------
212 // get the sid of a given process id using WTSEnumerateProcesses
213 // @todo: Make this function fail when WTSEnumerateProcesses is not available
214 // Or is it always available on all of our platform?
215 //
216 // Caller remember to call delete on *ppSid
217 //-----------------------------------------------------------------------------
218 HRESULT GetSidFromProcessEXWorker(DWORD dwProcessId, PSID *ppSid)
219 {
220     CONTRACTL
221     {
222         NOTHROW;
223         GC_NOTRIGGER;
224         PRECONDITION(CheckPointer(ppSid));
225     }
226     CONTRACTL_END;
227
228     HRESULT            hr = S_OK;
229     PWTS_PROCESS_INFOW rgProcessInfo = NULL;
230     DWORD              dwNumProcesses;
231     DWORD              iProc;
232     DWORD              cbSid;
233     PSID               pSid = NULL;
234
235     LOG((LF_CORDB, LL_INFO10000,
236          "SecurityUtil::GetSidFromProcessEx: 0x%08x\n",
237          dwProcessId));
238
239
240     *ppSid = NULL;
241     if (!WTSEnumerateProcessesW(WTS_CURRENT_SERVER_HANDLE,   // use local server
242                                 0,              // Reserved must be zero
243                                 1,              // version must be 1
244                                 &rgProcessInfo, // Receives pointer to process list
245                                 &dwNumProcesses))
246     {
247         hr = HRESULT_FROM_GetLastError();
248         goto exit;
249     }
250
251     for (iProc = 0; iProc < dwNumProcesses; iProc++)
252     {
253
254         if (rgProcessInfo[iProc].ProcessId == dwProcessId)
255         {
256             if (rgProcessInfo[iProc].pUserSid == NULL)
257             {
258                 LOG((LF_CORDB, LL_INFO10000,
259                      "SecurityUtil::GetSidFromProcessEx is not able to retreive SID\n"));
260
261                 // if there is no Sid for the user, don't call GetLengthSid.
262                 // It will crash! It is ok to return E_FAIL as caller will ignore it.
263                 hr = E_FAIL;
264                 goto exit;
265             }
266             cbSid = GetLengthSid(rgProcessInfo[iProc].pUserSid);
267             pSid = new (nothrow) BYTE[cbSid];
268             if (pSid == NULL)
269             {
270                 hr = E_OUTOFMEMORY;
271             }
272             else
273             {
274                 if (!CopySid(cbSid, pSid, rgProcessInfo[iProc].pUserSid))
275                 {
276                     hr = HRESULT_FROM_GetLastError();
277                 }
278                 else
279                 {
280                     // We are done. Go to exit
281                     hr = S_OK;
282                 }
283             }
284
285             // we already find a match. Even if we fail from memory allocation of CopySid, still
286             // goto exit.
287             goto exit;
288         }
289     }
290
291     // Walk the whole list and cannot find the matching PID
292     // Find a better error code.
293     hr = E_FAIL;
294
295 exit:
296
297     if (rgProcessInfo)
298     {
299         WTSFreeMemory(rgProcessInfo);
300     }
301
302     if (FAILED(hr) && pSid)
303     {
304         delete [] (reinterpret_cast<BYTE*>(pSid));
305     }
306
307     if (SUCCEEDED(hr))
308     {
309         _ASSERTE(pSid);
310         *ppSid = pSid;
311     }
312     LOG((LF_CORDB, LL_INFO10000,
313          "SecurityUtil::GetSidFromProcessEx return hr : 0x%08x\n",
314          hr));
315
316
317     return hr;
318 }
319 #endif // !FEATURE_CORESYSTEM
320
321 //-----------------------------------------------------------------------------
322 // The functions below initialize this SidBuffer instance with a Sid from
323 // the token of the specified process.  The first pair use the OWNER sid from
324 // the process token if possible; else use the term serv API to find the
325 // USER sid from the process token.  This seems a little inconsistent, but
326 // remains this way for backward compatibility.  The second pair consistently
327 // use the USER sid (never the OWNER).
328 // 
329 // While the USER and OWNER sid are often the same, they are not always the
330 // same.  For example, running a process on win2k3 server as a member of the
331 // local admin group causes the USER sid to be the logged-on user, and the
332 // OWNER sid to be the local admins group.  At least, that's how it was on
333 // Monday.  Expect this to change randomly at unexpected times, as most
334 // security-related behavior does.
335 //-----------------------------------------------------------------------------
336
337
338 // ----------------------------------------------------------------------------
339 // SidBuffer::InitFromProcessNoThrow
340 // 
341 // Description:
342 //    Initialize this SidBuffer instance with a Sid from the token of the specified
343 //    process. Use the OWNER sid from the process token if possible; else use the term
344 //    serv API to find the USER sid from the process token. This seems a little
345 //    inconsistent, but remains this way for backward compatibility.
346 //    
347 // Arguments:
348 //    * pid - Process ID from which to grab the SID
349 //
350 // Return Value:
351 //    HRESULT indicating success / failure
352 //    
353
354 HRESULT SidBuffer::InitFromProcessNoThrow(DWORD pid)
355 {
356     CONTRACTL
357     {
358         NOTHROW;
359         GC_NOTRIGGER;
360     }
361     CONTRACTL_END;
362
363     _ASSERTE(m_pBuffer == NULL);
364     HRESULT hr = GetSidFromProcessWorker(pid, kOwnerSid, (PSID *) &m_pBuffer);
365 #ifndef FEATURE_CORESYSTEM
366     if (FAILED(hr))
367     {
368         hr = GetSidFromProcessEXWorker(pid, (PSID *) &m_pBuffer);
369     }
370 #endif // !FEATURE_CORESYSTEM
371     if (FAILED(hr))
372     {
373         return hr;
374     }    
375     
376     _ASSERTE(m_pBuffer != NULL);
377     return S_OK;
378 }
379
380 // See code:SidBuffer::InitFromProcessNoThrow.  Throws if there's an error.
381 void SidBuffer::InitFromProcess(DWORD pid)
382 {
383     CONTRACTL
384     {
385         THROWS;
386         GC_NOTRIGGER;
387     }
388     CONTRACTL_END;
389
390     HRESULT hr = InitFromProcessNoThrow(pid);
391     if (FAILED(hr))
392     {
393         ThrowHR(hr);
394     }    
395 }
396
397 // ----------------------------------------------------------------------------
398 // SidBuffer::InitFromProcessAppContainerSidNoThrow
399 // 
400 // Description:
401 //    Initialize this SidBuffer instance with the TokenAppContainerSid from
402 //    the process token
403 //    
404 // Arguments:
405 //    * pid - Process ID from which to grab the SID
406 //
407 // Return Value:
408 //    HRESULT indicating success / failure
409 //    S_FALSE indicates the process isn't in an AppContainer
410 //   
411 HRESULT SidBuffer::InitFromProcessAppContainerSidNoThrow(DWORD pid)
412 {
413     HRESULT hr = S_OK;
414     HANDLE hToken = NULL;
415     BOOL fIsLowBox = FALSE;
416
417     HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
418     if (hProcess == NULL)
419     {
420         hr = HRESULT_FROM_GetLastError();
421         goto exit;
422     }
423     if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
424     {
425         hr = HRESULT_FROM_GetLastError();
426         goto exit;
427     }
428
429     // Define new TOKEN_INFORMATION_CLASS/ TOKEN_APPCONTAINER_INFORMATION members for Win8 since they are not in the DevDiv copy of WinSDK yet
430     typedef enum _TOKEN_INFORMATION_CLASS_WIN8 {
431         TokenIsAppContainer = TokenLogonSid + 1,
432         TokenCapabilities,
433         TokenAppContainerSid
434     } TOKEN_INFORMATION_CLASS_WIN8;
435
436     typedef struct _TOKEN_APPCONTAINER_INFORMATION
437     {
438         PSID TokenPackage;
439     } TOKEN_APPCONTAINER_INFORMATION, *PTOKEN_APPCONTAINER_INFORMATION;
440
441     DWORD size;
442     if (!GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS)TokenIsAppContainer, &fIsLowBox, sizeof(fIsLowBox), &size))
443     {
444         DWORD gle = GetLastError();
445         if (gle == ERROR_INVALID_PARAMETER || gle == ERROR_INVALID_FUNCTION)
446         {
447             hr = S_FALSE; // We are on an OS which doesn't understand LowBox
448         }
449         else
450         {
451             hr = HRESULT_FROM_WIN32(gle);
452         }
453         goto exit;
454     }
455
456     if (!fIsLowBox)
457     {
458         hr = S_FALSE;
459         goto exit;
460     }
461
462     UCHAR PackSid[SECURITY_MAX_SID_SIZE + sizeof(TOKEN_APPCONTAINER_INFORMATION)];
463     if (!GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS)TokenAppContainerSid, &PackSid, sizeof(PackSid), &size))
464     {
465         hr = HRESULT_FROM_GetLastError();
466         goto exit;
467     }
468
469     {
470         PTOKEN_APPCONTAINER_INFORMATION pTokPack = (PTOKEN_APPCONTAINER_INFORMATION)&PackSid;
471         PSID pLowBoxPackage = pTokPack->TokenPackage;
472         DWORD dwSidLen = GetLengthSid(pLowBoxPackage);
473         m_pBuffer = new (nothrow) BYTE[dwSidLen];
474         if (m_pBuffer == NULL)
475         {
476             hr = E_OUTOFMEMORY;
477             goto exit;
478         }
479         else
480         {
481             if (!CopySid(dwSidLen, m_pBuffer, pLowBoxPackage))
482             {
483                 hr = HRESULT_FROM_GetLastError();
484                 delete m_pBuffer;
485                 m_pBuffer = NULL;
486                 goto exit;
487             }
488         }
489     }
490
491 exit:
492     if (hProcess != NULL)
493     {
494         CloseHandle(hProcess);
495     }
496     if (hToken != NULL)
497     {
498         CloseHandle(hToken);
499     }
500
501     return hr;
502 }
503
504 // ----------------------------------------------------------------------------
505 // SidBuffer::InitFromProcessUserNoThrow
506 // 
507 // Description:
508 //    Initialize this SidBuffer instance with a Sid from the token of the specified
509 //    process. Use the USER sid from the process token if possible; else use the term
510 //    serv API to find the USER sid from the process token.
511 //    
512 // Arguments:
513 //    * pid - Process ID from which to grab the SID
514 //
515 // Return Value:
516 //    HRESULT indicating success / failure
517 //    
518
519 HRESULT SidBuffer::InitFromProcessUserNoThrow(DWORD pid)
520 {
521     CONTRACTL
522     {
523         NOTHROW;
524         GC_NOTRIGGER;
525     }
526     CONTRACTL_END;
527
528     _ASSERTE(m_pBuffer == NULL);
529     HRESULT hr = GetSidFromProcessWorker(pid, kUserSid, (PSID *) &m_pBuffer);
530 #ifndef FEATURE_CORESYSTEM
531     if (FAILED(hr))
532     {
533         hr = GetSidFromProcessEXWorker(pid, (PSID *) &m_pBuffer);
534     }
535 #endif // !FEATURE_CORESYSTEM
536     if (FAILED(hr))
537     {
538         return hr;
539     }    
540     
541     _ASSERTE(m_pBuffer != NULL);
542     return S_OK;
543 }
544
545 // See code:SidBuffer::InitFromProcessUserNoThrow.  Throws if there's an error.
546 void SidBuffer::InitFromProcessUser(DWORD pid)
547 {
548     CONTRACTL
549     {
550         THROWS;
551         GC_NOTRIGGER;
552     }
553     CONTRACTL_END;
554
555     HRESULT hr = InitFromProcessUserNoThrow(pid);
556     if (FAILED(hr))
557     {
558         ThrowHR(hr);
559     }    
560 }
561
562 //-----------------------------------------------------------------------------
563 // Ctor for Dacl class. Wraps a win32 dacl.
564 //-----------------------------------------------------------------------------
565 Dacl::Dacl(PACL pAcl)
566 {
567     m_acl = pAcl;   
568 }
569
570 //-----------------------------------------------------------------------------
571 // Get number of ACE (Access Control Entries) in this DACL.
572 //-----------------------------------------------------------------------------
573 SIZE_T Dacl::GetAceCount()
574 {
575     return (SIZE_T) m_acl->AceCount;
576 }
577
578 //-----------------------------------------------------------------------------
579 // Get Raw a ACE at the given index.
580 // Caller assumes index is valid (0 <= dwAceIndex < GetAceCount())
581 // Throws on error (which should only be if the index is out of bounds).
582 //-----------------------------------------------------------------------------
583 ACE_HEADER * Dacl::GetAce(SIZE_T dwAceIndex)
584 {
585     CONTRACTL {
586         THROWS;
587         GC_NOTRIGGER;
588     } CONTRACTL_END;
589     
590     ACE_HEADER * pAce = NULL;
591     BOOL fOk = ::GetAce(m_acl, (DWORD) dwAceIndex, (LPVOID*) &pAce);
592     _ASSERTE(fOk == (pAce != NULL));
593     if (!fOk)
594     {
595         ThrowLastError();
596     }
597     return pAce;
598 }
599
600
601
602 //-----------------------------------------------------------------------------
603 // Ctor for SecurityDescriptor
604 //-----------------------------------------------------------------------------
605 Win32SecurityDescriptor::Win32SecurityDescriptor()
606 {
607     m_pDesc = NULL;
608 }
609
610 //-----------------------------------------------------------------------------
611 // Dtor for security Descriptor.
612 //-----------------------------------------------------------------------------
613 Win32SecurityDescriptor::~Win32SecurityDescriptor()
614 {
615     delete [] ((BYTE*) m_pDesc);
616 }
617
618
619
620 //-----------------------------------------------------------------------------
621 // Get the dacl for this security descriptor.
622 //-----------------------------------------------------------------------------
623 Dacl Win32SecurityDescriptor::GetDacl()
624 {
625     CONTRACTL {
626         THROWS;
627         GC_NOTRIGGER;
628     } CONTRACTL_END;
629
630     _ASSERTE(m_pDesc != NULL);
631
632     BOOL bPresent;
633     BOOL bDaclDefaulted;
634     PACL acl;
635     
636     if (GetSecurityDescriptorDacl(m_pDesc, &bPresent, &acl, &bDaclDefaulted) == 0)
637     {
638         ThrowLastError();
639     }
640     if (!bPresent)
641     {
642         // No dacl. We consider this an error because all of the objects we expect
643         // to see should be dacled. If it's not dacled, then it's a malicious user spoofing it.
644         ThrowHR(E_INVALIDARG);
645     }
646
647     Dacl d(acl);
648     return d;
649 }
650
651 //-----------------------------------------------------------------------------
652 // Get the owner from the security descriptor.
653 //-----------------------------------------------------------------------------
654 HRESULT Win32SecurityDescriptor::GetOwnerNoThrow( PSID* ppSid)
655 {
656     CONTRACTL {
657         NOTHROW;
658         GC_NOTRIGGER;
659     } CONTRACTL_END;
660
661     _ASSERTE(m_pDesc != NULL);
662     BOOL bOwnerDefaulted;
663
664     if( ppSid == NULL )
665     {
666         return E_INVALIDARG;
667     }
668
669     if (GetSecurityDescriptorOwner(m_pDesc, ppSid, &bOwnerDefaulted) == 0)
670     {
671         DWORD err = GetLastError();
672         return HRESULT_FROM_WIN32(err);
673     }
674
675     return S_OK;
676 }
677 Sid Win32SecurityDescriptor::GetOwner()
678 {
679     CONTRACTL {
680         THROWS;
681         GC_NOTRIGGER;
682     } CONTRACTL_END;
683
684     PSID pSid;
685     HRESULT hr = GetOwnerNoThrow( &pSid );
686     if( FAILED(hr) )
687     {
688         ThrowHR( hr );
689     }
690
691     Sid s(pSid);
692     return s;
693 }
694
695 //-----------------------------------------------------------------------------
696 // Initialize this instance of a SecurityDescriptor with the SD for the handle.
697 // The handle must have READ_CONTROL permissions to do this.
698 // Throws on error.
699 //-----------------------------------------------------------------------------
700 HRESULT Win32SecurityDescriptor::InitFromHandleNoThrow(HANDLE h)
701 {
702     CONTRACTL {
703         NOTHROW;
704         GC_NOTRIGGER;
705     } CONTRACTL_END;
706     
707     _ASSERTE(m_pDesc == NULL); //  only init once.
708
709     DWORD       cbNeeded = 0;
710
711     DWORD flags = OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
712     
713     // Now get the creator's SID. First get the size of the array needed.
714     BOOL fOk = GetKernelObjectSecurity(h, flags, NULL, 0, &cbNeeded);
715     DWORD err = GetLastError();
716
717     // Caller should give us a handle for which this succeeds. First call will 
718     // fail w/ InsufficientBuffer.
719     CONSISTENCY_CHECK_MSGF(fOk || (err == ERROR_INSUFFICIENT_BUFFER), ("Failed to get KernelSecurity for object handle=%p.Err=%d\n", h, err));
720     
721     PSECURITY_DESCRIPTOR pSD = (PSECURITY_DESCRIPTOR) new(nothrow) BYTE[cbNeeded]; 
722     if( pSD == NULL )
723     {
724         return E_OUTOFMEMORY;
725     }
726
727     if (GetKernelObjectSecurity(h, flags, pSD, cbNeeded, &cbNeeded) == 0)
728     {
729         // get last error and fail out.
730         err = GetLastError();
731         delete [] ((BYTE*) pSD);
732         return HRESULT_FROM_WIN32(err);
733     }
734     
735     m_pDesc = pSD;
736     return S_OK;
737 }
738 void Win32SecurityDescriptor::InitFromHandle(HANDLE h)
739 {
740     CONTRACTL {
741         THROWS;
742         GC_NOTRIGGER;
743     } CONTRACTL_END;
744
745     HRESULT hr = InitFromHandleNoThrow(h);
746     if (FAILED(hr))
747     {
748         ThrowHR(hr);
749     }      
750 }