33
44using System . Diagnostics ;
55using System . Runtime . InteropServices ;
6+ using System . Security . AccessControl ;
67using Microsoft . Extensions . Logging ;
78using Windows . Win32 ;
89using Windows . Win32 . Networking . HttpServer ;
10+ using Windows . Win32 . Security ;
911
1012namespace Microsoft . AspNetCore . Server . HttpSys ;
1113
@@ -16,82 +18,116 @@ internal sealed partial class RequestQueue
1618 private bool _disposed ;
1719
1820 internal RequestQueue ( string requestQueueName , ILogger logger )
19- : this ( requestQueueName , RequestQueueMode . Attach , logger , receiver : true )
21+ : this ( requestQueueName , RequestQueueMode . Attach , securityDescriptor : null , logger , receiver : true )
2022 {
2123 }
2224
23- internal RequestQueue ( string ? requestQueueName , RequestQueueMode mode , ILogger logger )
24- : this ( requestQueueName , mode , logger , false )
25+ internal RequestQueue ( string ? requestQueueName , RequestQueueMode mode , GenericSecurityDescriptor ? securityDescriptor , ILogger logger )
26+ : this ( requestQueueName , mode , securityDescriptor , logger , false )
2527 { }
2628
27- private RequestQueue ( string ? requestQueueName , RequestQueueMode mode , ILogger logger , bool receiver )
29+ private RequestQueue ( string ? requestQueueName , RequestQueueMode mode , GenericSecurityDescriptor ? securityDescriptor , ILogger logger , bool receiver )
2830 {
2931 _mode = mode ;
3032 _logger = logger ;
3133
3234 var flags = 0u ;
3335 Created = true ;
3436
35- if ( _mode == RequestQueueMode . Attach )
37+ SECURITY_ATTRIBUTES ? securityAttributes = null ;
38+ nint ? pSecurityDescriptor = null ;
39+
40+ try
3641 {
37- flags = PInvoke . HTTP_CREATE_REQUEST_QUEUE_FLAG_OPEN_EXISTING ;
38- Created = false ;
39- if ( receiver )
42+ if ( _mode == RequestQueueMode . Attach )
4043 {
41- flags |= PInvoke . HTTP_CREATE_REQUEST_QUEUE_FLAG_DELEGATION ;
44+ flags = PInvoke . HTTP_CREATE_REQUEST_QUEUE_FLAG_OPEN_EXISTING ;
45+ Created = false ;
46+ if ( receiver )
47+ {
48+ flags |= PInvoke . HTTP_CREATE_REQUEST_QUEUE_FLAG_DELEGATION ;
49+ }
50+ }
51+ else if ( securityDescriptor is not null ) // Create or CreateOrAttach
52+ {
53+ // Convert the security descriptor to a byte array
54+ byte [ ] securityDescriptorBytes = new byte [ securityDescriptor . BinaryLength ] ;
55+ securityDescriptor . GetBinaryForm ( securityDescriptorBytes , 0 ) ;
56+
57+ // Allocate native memory for the security descriptor
58+ pSecurityDescriptor = Marshal . AllocHGlobal ( securityDescriptorBytes . Length ) ;
59+ Marshal . Copy ( securityDescriptorBytes , 0 , pSecurityDescriptor . Value , securityDescriptorBytes . Length ) ;
60+
61+ unsafe
62+ {
63+ securityAttributes = new SECURITY_ATTRIBUTES
64+ {
65+ nLength = ( uint ) Marshal . SizeOf < SECURITY_ATTRIBUTES > ( ) ,
66+ lpSecurityDescriptor = pSecurityDescriptor . Value . ToPointer ( ) ,
67+ bInheritHandle = false
68+ } ;
69+ }
4270 }
43- }
44-
45- var statusCode = PInvoke . HttpCreateRequestQueue (
46- HttpApi . Version ,
47- requestQueueName ,
48- default ,
49- flags ,
50- out var requestQueueHandle ) ;
5171
52- if ( _mode == RequestQueueMode . CreateOrAttach && statusCode == ErrorCodes . ERROR_ALREADY_EXISTS )
53- {
54- // Tried to create, but it already exists so attach to it instead.
55- Created = false ;
56- flags = PInvoke . HTTP_CREATE_REQUEST_QUEUE_FLAG_OPEN_EXISTING ;
57- statusCode = PInvoke . HttpCreateRequestQueue (
72+ var statusCode = PInvoke . HttpCreateRequestQueue (
5873 HttpApi . Version ,
5974 requestQueueName ,
60- default ,
75+ securityAttributes ,
6176 flags ,
62- out requestQueueHandle ) ;
63- }
77+ out var requestQueueHandle ) ;
6478
65- if ( ( flags & PInvoke . HTTP_CREATE_REQUEST_QUEUE_FLAG_OPEN_EXISTING ) != 0 && statusCode == ErrorCodes . ERROR_FILE_NOT_FOUND )
66- {
67- throw new HttpSysException ( ( int ) statusCode , $ "Failed to attach to the given request queue ' { requestQueueName } ', the queue could not be found." ) ;
68- }
69- else if ( statusCode == ErrorCodes . ERROR_INVALID_NAME )
70- {
71- throw new HttpSysException ( ( int ) statusCode , $ "The given request queue name ' { requestQueueName } ' is invalid." ) ;
72- }
73- else if ( statusCode != ErrorCodes . ERROR_SUCCESS )
74- {
75- throw new HttpSysException ( ( int ) statusCode ) ;
76- }
79+ if ( _mode == RequestQueueMode . CreateOrAttach && statusCode == ErrorCodes . ERROR_ALREADY_EXISTS )
80+ {
81+ // Tried to create, but it already exists so attach to it instead.
82+ Created = false ;
83+ flags = PInvoke . HTTP_CREATE_REQUEST_QUEUE_FLAG_OPEN_EXISTING ;
84+ statusCode = PInvoke . HttpCreateRequestQueue (
85+ HttpApi . Version ,
86+ requestQueueName ,
87+ SecurityAttributes : default , // Attaching should not pass any security attributes
88+ flags ,
89+ out requestQueueHandle ) ;
90+ }
7791
78- // Disabling callbacks when IO operation completes synchronously (returns ErrorCodes.ERROR_SUCCESS)
79- if ( HttpSysListener . SkipIOCPCallbackOnSuccess &&
80- ! PInvoke . SetFileCompletionNotificationModes (
81- requestQueueHandle ,
82- ( byte ) ( PInvoke . FILE_SKIP_COMPLETION_PORT_ON_SUCCESS |
83- PInvoke . FILE_SKIP_SET_EVENT_ON_HANDLE ) ) )
84- {
85- requestQueueHandle . Dispose ( ) ;
86- throw new HttpSysException ( Marshal . GetLastWin32Error ( ) ) ;
87- }
92+ if ( ( flags & PInvoke . HTTP_CREATE_REQUEST_QUEUE_FLAG_OPEN_EXISTING ) != 0 && statusCode == ErrorCodes . ERROR_FILE_NOT_FOUND )
93+ {
94+ throw new HttpSysException ( ( int ) statusCode , $ "Failed to attach to the given request queue '{ requestQueueName } ', the queue could not be found.") ;
95+ }
96+ else if ( statusCode == ErrorCodes . ERROR_INVALID_NAME )
97+ {
98+ throw new HttpSysException ( ( int ) statusCode , $ "The given request queue name '{ requestQueueName } ' is invalid.") ;
99+ }
100+ else if ( statusCode != ErrorCodes . ERROR_SUCCESS )
101+ {
102+ throw new HttpSysException ( ( int ) statusCode ) ;
103+ }
104+
105+ // Disabling callbacks when IO operation completes synchronously (returns ErrorCodes.ERROR_SUCCESS)
106+ if ( HttpSysListener . SkipIOCPCallbackOnSuccess &&
107+ ! PInvoke . SetFileCompletionNotificationModes (
108+ requestQueueHandle ,
109+ ( byte ) ( PInvoke . FILE_SKIP_COMPLETION_PORT_ON_SUCCESS |
110+ PInvoke . FILE_SKIP_SET_EVENT_ON_HANDLE ) ) )
111+ {
112+ requestQueueHandle . Dispose ( ) ;
113+ throw new HttpSysException ( Marshal . GetLastWin32Error ( ) ) ;
114+ }
88115
89- Handle = requestQueueHandle ;
90- BoundHandle = ThreadPoolBoundHandle . BindHandle ( Handle ) ;
116+ Handle = requestQueueHandle ;
117+ BoundHandle = ThreadPoolBoundHandle . BindHandle ( Handle ) ;
91118
92- if ( ! Created )
119+ if ( ! Created )
120+ {
121+ Log . AttachedToQueue ( _logger , requestQueueName ) ;
122+ }
123+ }
124+ finally
93125 {
94- Log . AttachedToQueue ( _logger , requestQueueName ) ;
126+ if ( pSecurityDescriptor is not null )
127+ {
128+ // Free the allocated memory for the security descriptor
129+ Marshal . FreeHGlobal ( pSecurityDescriptor . Value ) ;
130+ }
95131 }
96132 }
97133
@@ -143,6 +179,9 @@ public void Dispose()
143179 }
144180
145181 _disposed = true ;
182+
183+ PInvoke . HttpCloseRequestQueue ( Handle ) ;
184+
146185 BoundHandle . Dispose ( ) ;
147186 Handle . Dispose ( ) ;
148187 }
0 commit comments