xref: /reactos/base/services/dhcpcsvc/dhcp/pipe.c (revision bbccad0e)
1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS kernel
4  * FILE:             subsys/system/dhcp/pipe.c
5  * PURPOSE:          DHCP client pipe
6  * PROGRAMMER:       arty
7  */
8 
9 #include <rosdhcp.h>
10 
11 #define NDEBUG
12 #include <reactos/debug.h>
13 
14 #define COMM_PIPE_OUTPUT_BUFFER sizeof(COMM_DHCP_REQ)
15 #define COMM_PIPE_INPUT_BUFFER sizeof(COMM_DHCP_REPLY)
16 #define COMM_PIPE_DEFAULT_TIMEOUT 1000
17 
18 DWORD PipeSend( HANDLE CommPipe, COMM_DHCP_REPLY *Reply ) {
19     DWORD Written = 0;
20     OVERLAPPED Overlapped = {0};
21     BOOL Success =
22         WriteFile( CommPipe,
23                    Reply,
24                    sizeof(*Reply),
25                    &Written,
26                    &Overlapped);
27     if (!Success)
28     {
29         WaitForSingleObject(CommPipe, INFINITE);
30         Success = GetOverlappedResult(CommPipe,
31                                       &Overlapped,
32                                       &Written,
33                                       TRUE);
34     }
35 
36     return Success ? Written : -1;
37 }
38 
39 /**
40  * @brief
41  * Creates a security descriptor for the DHCP pipe
42  * service.
43  *
44  * @param[out] SecurityDescriptor
45  * A pointer to an allocated security descriptor
46  * for the DHCP pipe.
47  *
48  * @return
49  * ERROR_SUCCESS is returned if the function has
50  * successfully created the descriptor otherwise
51  * a Win32 error code is returned.
52  *
53  * @remarks
54  * Both admins and local system are given full power
55  * over the DHCP pipe whereas authenticated users
56  * and network operators can only read over this pipe.
57  * They can also execute it.
58  */
59 DWORD CreateDhcpPipeSecurity( PSECURITY_DESCRIPTOR *SecurityDescriptor ) {
60     DWORD ErrCode;
61     PACL Dacl;
62     ULONG DaclSize, RelSDSize = 0;
63     PSECURITY_DESCRIPTOR AbsSD = NULL, RelSD = NULL;
64     PSID AuthenticatedUsersSid = NULL, NetworkOpsSid = NULL, AdminsSid = NULL, SystemSid = NULL;
65     static SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
66 
67     if (!AllocateAndInitializeSid(&NtAuthority,
68                                   1,
69                                   SECURITY_AUTHENTICATED_USER_RID,
70                                   0, 0, 0, 0, 0, 0, 0,
71                                   &AuthenticatedUsersSid))
72     {
73         DPRINT1("CreateDhcpPipeSecurity(): Failed to create Authenticated Users SID (error code %d)\n", GetLastError());
74         return GetLastError();
75     }
76 
77     if (!AllocateAndInitializeSid(&NtAuthority,
78                                   2,
79                                   SECURITY_BUILTIN_DOMAIN_RID,
80                                   DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS,
81                                   0, 0, 0, 0, 0, 0,
82                                   &NetworkOpsSid))
83     {
84         DPRINT1("CreateDhcpPipeSecurity(): Failed to create Network Ops SID (error code %d)\n", GetLastError());
85         ErrCode = GetLastError();
86         goto Quit;
87     }
88 
89     if (!AllocateAndInitializeSid(&NtAuthority,
90                                   2,
91                                   SECURITY_BUILTIN_DOMAIN_RID,
92                                   DOMAIN_ALIAS_RID_ADMINS,
93                                   0, 0, 0, 0, 0, 0,
94                                   &AdminsSid))
95     {
96         DPRINT1("CreateDhcpPipeSecurity(): Failed to create Admins SID (error code %d)\n", GetLastError());
97         ErrCode = GetLastError();
98         goto Quit;
99     }
100 
101     if (!AllocateAndInitializeSid(&NtAuthority,
102                                   1,
103                                   SECURITY_LOCAL_SYSTEM_RID,
104                                   0, 0, 0, 0, 0, 0, 0,
105                                   &SystemSid))
106     {
107         DPRINT1("CreateDhcpPipeSecurity(): Failed to create Local System SID (error code %d)\n", GetLastError());
108         ErrCode = GetLastError();
109         goto Quit;
110     }
111 
112     AbsSD = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SECURITY_DESCRIPTOR));
113     if (!AbsSD)
114     {
115         DPRINT1("CreateDhcpPipeSecurity(): Failed to allocate absolute security descriptor!\n");
116         ErrCode = ERROR_OUTOFMEMORY;
117         goto Quit;
118     }
119 
120     if (!InitializeSecurityDescriptor(AbsSD, SECURITY_DESCRIPTOR_REVISION))
121     {
122         DPRINT1("CreateDhcpPipeSecurity(): Failed to initialize absolute security descriptor (error code %d)\n", GetLastError());
123         ErrCode = GetLastError();
124         goto Quit;
125     }
126 
127     DaclSize = sizeof(ACL) +
128                sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(AuthenticatedUsersSid) +
129                sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(NetworkOpsSid) +
130                sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(AdminsSid) +
131                sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(SystemSid);
132 
133     Dacl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, DaclSize);
134     if (!Dacl)
135     {
136         DPRINT1("CreateDhcpPipeSecurity(): Failed to allocate DACL!\n");
137         ErrCode = ERROR_OUTOFMEMORY;
138         goto Quit;
139     }
140 
141     if (!InitializeAcl(Dacl, DaclSize, ACL_REVISION))
142     {
143         DPRINT1("CreateDhcpPipeSecurity(): Failed to initialize DACL (error code %d)\n", GetLastError());
144         ErrCode = GetLastError();
145         goto Quit;
146     }
147 
148     if (!AddAccessAllowedAce(Dacl,
149                              ACL_REVISION,
150                              GENERIC_READ | GENERIC_EXECUTE,
151                              AuthenticatedUsersSid))
152     {
153         DPRINT1("CreateDhcpPipeSecurity(): Failed to set up ACE for Authenticated Users SID (error code %d)\n", GetLastError());
154         ErrCode = GetLastError();
155         goto Quit;
156     }
157 
158     if (!AddAccessAllowedAce(Dacl,
159                              ACL_REVISION,
160                              GENERIC_READ | GENERIC_EXECUTE,
161                              NetworkOpsSid))
162     {
163         DPRINT1("CreateDhcpPipeSecurity(): Failed to set up ACE for Network Ops SID (error code %d)\n", GetLastError());
164         ErrCode = GetLastError();
165         goto Quit;
166     }
167 
168     if (!AddAccessAllowedAce(Dacl,
169                              ACL_REVISION,
170                              GENERIC_ALL,
171                              AdminsSid))
172     {
173         DPRINT1("CreateDhcpPipeSecurity(): Failed to set up ACE for Admins SID (error code %d)\n", GetLastError());
174         ErrCode = GetLastError();
175         goto Quit;
176     }
177 
178     if (!AddAccessAllowedAce(Dacl,
179                              ACL_REVISION,
180                              GENERIC_ALL,
181                              SystemSid))
182     {
183         DPRINT1("CreateDhcpPipeSecurity(): Failed to set up ACE for Local System SID (error code %d)\n", GetLastError());
184         ErrCode = GetLastError();
185         goto Quit;
186     }
187 
188     if (!SetSecurityDescriptorDacl(AbsSD, TRUE, Dacl, FALSE))
189     {
190         DPRINT1("CreateDhcpPipeSecurity(): Failed to set up DACL to absolute security descriptor (error code %d)\n", GetLastError());
191         ErrCode = GetLastError();
192         goto Quit;
193     }
194 
195     if (!SetSecurityDescriptorOwner(AbsSD, AdminsSid, FALSE))
196     {
197         DPRINT1("CreateDhcpPipeSecurity(): Failed to set up owner to absolute security descriptor (error code %d)\n", GetLastError());
198         ErrCode = GetLastError();
199         goto Quit;
200     }
201 
202     if (!SetSecurityDescriptorGroup(AbsSD, SystemSid, FALSE))
203     {
204         DPRINT1("CreateDhcpPipeSecurity(): Failed to set up group to absolute security descriptor (error code %d)\n", GetLastError());
205         ErrCode = GetLastError();
206         goto Quit;
207     }
208 
209     if (!MakeSelfRelativeSD(AbsSD, NULL, &RelSDSize) && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
210     {
211         DPRINT1("CreateDhcpPipeSecurity(): Unexpected error code (error code %d -- must be ERROR_INSUFFICIENT_BUFFER)\n", GetLastError());
212         ErrCode = GetLastError();
213         goto Quit;
214     }
215 
216     RelSD = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, RelSDSize);
217     if (RelSD == NULL)
218     {
219         DPRINT1("CreateDhcpPipeSecurity(): Failed to allocate relative SD!\n");
220         ErrCode = ERROR_OUTOFMEMORY;
221         goto Quit;
222     }
223 
224     if (!MakeSelfRelativeSD(AbsSD, RelSD, &RelSDSize) && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
225     {
226         DPRINT1("CreateDhcpPipeSecurity(): Failed to allocate relative SD, buffer too smal (expected size %lu)\n", RelSDSize);
227         ErrCode = ERROR_INSUFFICIENT_BUFFER;
228         goto Quit;
229     }
230 
231     *SecurityDescriptor = RelSD;
232     ErrCode = ERROR_SUCCESS;
233 
234 Quit:
235     if (ErrCode != ERROR_SUCCESS)
236     {
237         if (RelSD)
238         {
239             HeapFree(GetProcessHeap(), 0, RelSD);
240         }
241     }
242 
243     if (AuthenticatedUsersSid)
244     {
245         FreeSid(AuthenticatedUsersSid);
246     }
247 
248     if (NetworkOpsSid)
249     {
250         FreeSid(NetworkOpsSid);
251     }
252 
253     if (AdminsSid)
254     {
255         FreeSid(AdminsSid);
256     }
257 
258     if (SystemSid)
259     {
260         FreeSid(SystemSid);
261     }
262 
263     if (Dacl)
264     {
265         HeapFree(GetProcessHeap(), 0, Dacl);
266     }
267 
268     if (AbsSD)
269     {
270         HeapFree(GetProcessHeap(), 0, AbsSD);
271     }
272 
273     return ErrCode;
274 }
275 
276 DWORD WINAPI PipeThreadProc( LPVOID Parameter ) {
277     DWORD BytesRead;
278     COMM_DHCP_REQ Req;
279     COMM_DHCP_REPLY Reply;
280     BOOL Result, Connected;
281     HANDLE Events[2];
282     HANDLE CommPipe;
283     OVERLAPPED Overlapped = {0};
284     DWORD dwError;
285     SECURITY_ATTRIBUTES SecurityAttributes;
286     PSECURITY_DESCRIPTOR DhcpPipeSD = NULL;
287 
288     DPRINT("PipeThreadProc(%p)\n", Parameter);
289 
290     dwError = CreateDhcpPipeSecurity(&DhcpPipeSD);
291     if (dwError != ERROR_SUCCESS)
292     {
293         DbgPrint("DHCP: Could not create security descriptor for pipe\n");
294         return FALSE;
295     }
296 
297     SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
298     SecurityAttributes.lpSecurityDescriptor = DhcpPipeSD;
299     SecurityAttributes.bInheritHandle = FALSE;
300 
301     CommPipe = CreateNamedPipeW
302         ( DHCP_PIPE_NAME,
303           PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED,
304           PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
305           1,
306           COMM_PIPE_OUTPUT_BUFFER,
307           COMM_PIPE_INPUT_BUFFER,
308           COMM_PIPE_DEFAULT_TIMEOUT,
309           &SecurityAttributes );
310     HeapFree(GetProcessHeap(), 0, DhcpPipeSD);
311     if (CommPipe == INVALID_HANDLE_VALUE)
312     {
313         DbgPrint("DHCP: Could not create named pipe\n");
314         return FALSE;
315     }
316 
317     Events[0] = (HANDLE)Parameter;
318     Events[1] = CommPipe;
319 
320     while( TRUE )
321     {
322         Connected = ConnectNamedPipe(CommPipe, &Overlapped);
323         if (!Connected)
324         {
325             dwError = GetLastError();
326             if (dwError == ERROR_IO_PENDING)
327             {
328                 dwError = WaitForMultipleObjects(2, Events, FALSE, INFINITE);
329                 DPRINT("WaitForMultipleObjects() returned %lu\n", dwError);
330                 if (dwError == WAIT_OBJECT_0 + 1)
331                 {
332                     Connected = GetOverlappedResult(CommPipe,
333                                                     &Overlapped,
334                                                     &BytesRead,
335                                                     TRUE);
336                 }
337                 else if (dwError == WAIT_OBJECT_0)
338                 {
339                     CancelIo(CommPipe);
340                     CloseHandle(CommPipe);
341                     CommPipe = INVALID_HANDLE_VALUE;
342                     break;
343                 }
344             }
345         }
346 
347         if (!Connected) {
348             DbgPrint("DHCP: Could not connect named pipe\n");
349             CloseHandle( CommPipe );
350             CommPipe = INVALID_HANDLE_VALUE;
351             break;
352         }
353 
354         Result = ReadFile(CommPipe, &Req, sizeof(Req), &BytesRead, &Overlapped);
355         if (!Result)
356         {
357             dwError = GetLastError();
358             if (dwError == ERROR_IO_PENDING)
359             {
360                 dwError = WaitForMultipleObjects(2, Events, FALSE, INFINITE);
361                 DPRINT("WaitForMultipleObjects() returned %lu\n", dwError);
362                 if (dwError == WAIT_OBJECT_0 + 1)
363                 {
364                     Result = GetOverlappedResult(CommPipe,
365                                                  &Overlapped,
366                                                  &BytesRead,
367                                                  TRUE);
368                 }
369                 else if (dwError == WAIT_OBJECT_0)
370                 {
371                     CancelIo(CommPipe);
372                     DisconnectNamedPipe( CommPipe );
373                     CloseHandle(CommPipe);
374                     CommPipe = INVALID_HANDLE_VALUE;
375                     break;
376                 }
377             }
378         }
379 
380         if( Result ) {
381             switch( Req.Type ) {
382             case DhcpReqQueryHWInfo:
383                 DSQueryHWInfo( PipeSend, CommPipe, &Req );
384                 break;
385 
386             case DhcpReqLeaseIpAddress:
387                 DSLeaseIpAddress( PipeSend, CommPipe, &Req );
388                 break;
389 
390             case DhcpReqReleaseIpAddress:
391                 DSReleaseIpAddressLease( PipeSend, CommPipe, &Req );
392                 break;
393 
394             case DhcpReqRenewIpAddress:
395                 DSRenewIpAddressLease( PipeSend, CommPipe, &Req );
396                 break;
397 
398             case DhcpReqStaticRefreshParams:
399                 DSStaticRefreshParams( PipeSend, CommPipe, &Req );
400                 break;
401 
402             case DhcpReqGetAdapterInfo:
403                 DSGetAdapterInfo( PipeSend, CommPipe, &Req );
404                 break;
405 
406             default:
407                 DPRINT1("Unrecognized request type %d\n", Req.Type);
408                 ZeroMemory( &Reply, sizeof( COMM_DHCP_REPLY ) );
409                 Reply.Reply = 0;
410                 PipeSend(CommPipe, &Reply );
411                 break;
412             }
413         }
414         DisconnectNamedPipe( CommPipe );
415     }
416 
417     DPRINT("Pipe thread stopped!\n");
418 
419     return TRUE;
420 }
421 
422 HANDLE PipeInit(HANDLE hStopEvent)
423 {
424     return CreateThread( NULL, 0, PipeThreadProc, (LPVOID)hStopEvent, 0, NULL);
425 }
426