Windows: Defer deref of a directoryEntry
[openafs.git] / src / WINNT / afsrdr / user / RDRPipe.c
1 /*
2  * Copyright (c) 2008 Secure Endpoints, Inc.
3  * Copyright (c) 2009-2011 Your File System, Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * - Redistributions of source code must retain the above copyright notice,
10  *   this list of conditions and the following disclaimer.
11  * - Redistributions in binary form must reproduce the above copyright notice,
12  *   this list of conditions and the following disclaimer in the documentation
13  *   and/or other materials provided with the distribution.
14  * - Neither the name of Secure Endpoints Inc. nor the names of its contributors
15  *   may be used to endorse or promote products derived from this software without
16  *   specific prior written permission from Secure Endpoints, Inc. and
17  *   Your File System, Inc.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
23  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include <afsconfig.h>
33 #include <afs/param.h>
34 #include <ntstatus.h>
35 #define WIN32_NO_STATUS
36 #include <roken.h>
37
38 #include <afs/stds.h>
39
40 #include <windows.h>
41 #include <stdlib.h>
42 #include <malloc.h>
43 #include <string.h>
44 #include <stdio.h>
45 #include <time.h>
46 #include <strsafe.h>
47
48 #include <osi.h>
49
50 #include "afsd.h"
51
52 #include "cm_rpc.h"
53 #include "afs/afsrpc.h"
54 #include "afs/auth.h"
55
56 #include "msrpc.h"
57 #define RDR_PIPE_PRIVATE
58 #include "RDRPipe.h"
59 #include "smb.h"
60 #include "cm_nls.h"
61
62 static RDR_pipe_t * RDR_allPipes = NULL, *RDR_allPipesLast = NULL;
63 static osi_rwlock_t  RDR_globalPipeLock;
64 static wchar_t       RDR_UNCName[64]=L"AFS";
65
66 void
67 RDR_InitPipe(void)
68 {
69     lock_InitializeRWLock(&RDR_globalPipeLock, "RDR global pipe lock", LOCK_HIERARCHY_RDR_GLOBAL);
70 }
71
72 RDR_pipe_t *
73 RDR_FindPipe(ULONG index, int locked)
74 {
75     RDR_pipe_t *pipep;
76
77     if ( !locked)
78         lock_ObtainRead(&RDR_globalPipeLock);
79     for ( pipep=RDR_allPipes; pipep; pipep=pipep->next) {
80         if (pipep->index == index)
81             break;
82     }
83     if ( !locked)
84         lock_ReleaseRead(&RDR_globalPipeLock);
85     return pipep;
86 }
87
88 /* called to make a fid structure into an Pipe fid structure */
89 DWORD
90 RDR_SetupPipe( ULONG index, cm_fid_t *parentFid, cm_fid_t *rootFid,
91                WCHAR     *Name, DWORD      NameLength,
92                cm_user_t *userp)
93 {
94     RDR_pipe_t *pipep;
95     cm_req_t req;
96     DWORD status;
97     char name[MAX_PATH];
98
99     cm_InitReq(&req);
100
101     lock_ObtainWrite(&RDR_globalPipeLock);
102     pipep = RDR_FindPipe(index, TRUE);
103
104     if (pipep) {
105         /* we are reusing a previous pipe */
106         if (cm_FidCmp(&pipep->parentFid, parentFid)) {
107             pipep->parentFid = *parentFid;
108             if (pipep->parentScp) {
109                 cm_ReleaseSCache(pipep->parentScp);
110                 pipep->parentScp = NULL;
111             }
112             cm_GetSCache(parentFid, &pipep->parentScp, userp, &req);
113             pipep->rootFid = *rootFid;
114         }
115     } else {
116         /* need to allocate a new one */
117         pipep = malloc(sizeof(*pipep));
118         if (pipep == NULL) {
119             status = STATUS_NO_MEMORY;
120             goto done;
121         }
122         memset(pipep, 0, sizeof(*pipep));
123         if (RDR_allPipes == NULL)
124             RDR_allPipes = RDR_allPipesLast = pipep;
125         else {
126             pipep->prev = RDR_allPipesLast;
127             RDR_allPipesLast->next = pipep;
128             RDR_allPipesLast = pipep;
129         }
130         pipep->index = index;
131         if (parentFid->cell == 0) {
132             pipep->parentFid = cm_data.rootFid;
133             pipep->parentScp = cm_RootSCachep(userp, &req);
134             cm_HoldSCache(pipep->parentScp);
135         } else {
136             pipep->parentFid = *parentFid;
137             cm_GetSCache(parentFid, &pipep->parentScp, userp, &req);
138         }
139         if (rootFid->cell == 0) {
140             pipep->rootFid = cm_data.rootFid;
141         } else {
142             pipep->rootFid = *rootFid;
143         }
144     }
145
146     StringCbCopyNW( pipep->name, sizeof(pipep->name), Name, NameLength);
147     cm_Utf16ToUtf8( pipep->name, -1, name, sizeof(name));
148
149     status = MSRPC_InitConn(&pipep->rpc_conn, name);
150     if (status == STATUS_SUCCESS) {
151         pipep->flags |= RDR_PIPEFLAG_MESSAGE_MODE;
152         pipep->devstate = RDR_DEVICESTATE_READMSGFROMPIPE |
153                           RDR_DEVICESTATE_MESSAGEMODEPIPE |
154                           RDR_DEVICESTATE_PIPECLIENTEND;
155     }
156
157   done:
158     lock_ReleaseWrite(&RDR_globalPipeLock);
159
160     return status;
161 }
162
163
164 void
165 RDR_CleanupPipe(ULONG index)
166 {
167     RDR_pipe_t *pipep;
168
169     lock_ObtainWrite(&RDR_globalPipeLock);
170     pipep = RDR_FindPipe(index, TRUE);
171
172     if (pipep) {
173         if (pipep->parentScp)
174             cm_ReleaseSCache(pipep->parentScp);
175
176         if (pipep->inAllocp)
177             free(pipep->inAllocp);
178         if (pipep->outAllocp)
179             free(pipep->outAllocp);
180
181         MSRPC_FreeConn(&pipep->rpc_conn);
182
183         if (RDR_allPipes == RDR_allPipesLast)
184             RDR_allPipes = RDR_allPipesLast = NULL;
185         else {
186             if (pipep->prev == NULL)
187                 RDR_allPipes = pipep->next;
188             else
189                 pipep->prev->next = pipep->next;
190             if (pipep->next == NULL) {
191                 RDR_allPipesLast = pipep->prev;
192                 pipep->prev->next = NULL;
193             } else
194                 pipep->next->prev = pipep->prev;
195         }
196         free(pipep);
197     }
198     lock_ReleaseWrite(&RDR_globalPipeLock);
199
200 }
201
202 DWORD
203 RDR_Pipe_Read(ULONG index, ULONG BufferLength, void *MappedBuffer,
204               ULONG *pBytesProcessed, cm_req_t *reqp, cm_user_t *userp)
205 {
206     RDR_pipe_t *pipep;
207     DWORD   code = STATUS_INVALID_PIPE_STATE;
208
209     lock_ObtainWrite(&RDR_globalPipeLock);
210     pipep = RDR_FindPipe(index, TRUE);
211
212     if (pipep) {
213         code = MSRPC_PrepareRead(&pipep->rpc_conn);
214         if (code == 0) {
215             *pBytesProcessed = MSRPC_ReadMessageLength(&pipep->rpc_conn, BufferLength);
216             code = MSRPC_ReadMessage(&pipep->rpc_conn, MappedBuffer, *pBytesProcessed);
217         }
218
219     }
220     lock_ReleaseWrite(&RDR_globalPipeLock);
221
222     return code;
223 }
224
225 DWORD
226 RDR_Pipe_Write( ULONG index, ULONG BufferLength, void *MappedBuffer,
227                 cm_req_t *reqp, cm_user_t *userp)
228 {
229     RDR_pipe_t *pipep;
230     DWORD   code = STATUS_INVALID_PIPE_STATE;
231
232     lock_ObtainWrite(&RDR_globalPipeLock);
233     pipep = RDR_FindPipe(index, TRUE);
234
235     if (pipep) {
236         code = MSRPC_WriteMessage( &pipep->rpc_conn, MappedBuffer,
237                                    BufferLength, userp);
238     }
239     lock_ReleaseWrite(&RDR_globalPipeLock);
240
241     return code;
242 }
243
244 DWORD
245 RDR_Pipe_QueryInfo( ULONG index, ULONG InfoClass,
246                     ULONG BufferLength, void *MappedBuffer,
247                     ULONG *pBytesProcessed, cm_req_t *reqp, cm_user_t *userp)
248 {
249     RDR_pipe_t *pipep;
250     DWORD   code = STATUS_INVALID_PIPE_STATE;
251     size_t      length;
252
253     lock_ObtainWrite(&RDR_globalPipeLock);
254     pipep = RDR_FindPipe(index, TRUE);
255
256     if (pipep) {
257         switch ( InfoClass ) {
258         case FileBasicInformation: {
259             FILE_BASIC_INFORMATION * fbInfo = (FILE_BASIC_INFORMATION *)MappedBuffer;
260
261             memset(fbInfo, 0, sizeof(FILE_BASIC_INFORMATION));
262             fbInfo->FileAttributes = FILE_ATTRIBUTE_NORMAL;
263             *pBytesProcessed = (DWORD)(sizeof(FILE_BASIC_INFORMATION));
264             code = STATUS_SUCCESS;
265             break;
266         }
267         case FileStandardInformation: {
268             FILE_STANDARD_INFORMATION * fsInfo = (FILE_STANDARD_INFORMATION *)MappedBuffer;
269
270             memset(fsInfo, 0, sizeof(FILE_STANDARD_INFORMATION));
271             *pBytesProcessed = (DWORD)(sizeof(FILE_STANDARD_INFORMATION));
272             code = STATUS_SUCCESS;
273             break;
274         }
275         case FileNameInformation: {
276             FILE_NAME_INFORMATION * fnInfo = (FILE_NAME_INFORMATION *)MappedBuffer;
277
278             StringCbLengthW(pipep->name, sizeof(pipep->name), &length);
279             if (BufferLength < sizeof(FILE_NAME_INFORMATION) + length) {
280                 code = STATUS_BUFFER_OVERFLOW;
281                 goto done;
282             }
283             fnInfo->FileNameLength = (DWORD)length;
284             memcpy( fnInfo->FileName, pipep->name, length);
285             *pBytesProcessed = (DWORD)(sizeof(DWORD) + length);
286             code = STATUS_SUCCESS;
287             break;
288         }
289         default:
290             code = STATUS_NOT_SUPPORTED;
291         }
292     }
293
294   done:
295     lock_ReleaseWrite(&RDR_globalPipeLock);
296
297     if (code)
298         *pBytesProcessed = 0;
299
300     return code;
301 }
302
303 DWORD
304 RDR_Pipe_SetInfo( ULONG index, ULONG InfoClass,
305                   ULONG BufferLength, void *MappedBuffer,
306                   cm_req_t *reqp, cm_user_t *userp)
307 {
308     RDR_pipe_t *pipep;
309     DWORD   code = STATUS_INVALID_PIPE_STATE;
310
311     lock_ObtainWrite(&RDR_globalPipeLock);
312     pipep = RDR_FindPipe(index, TRUE);
313
314     if (pipep) {
315         switch ( InfoClass ) {
316         case FilePipeInformation: {
317             FILE_PIPE_INFORMATION * fpInfo = (FILE_PIPE_INFORMATION *)MappedBuffer;
318
319             if (BufferLength != sizeof(FILE_PIPE_INFORMATION)) {
320                 code = STATUS_INFO_LENGTH_MISMATCH;
321                 goto done;
322             }
323
324             switch ( fpInfo->ReadMode ) {
325             case FILE_PIPE_BYTE_STREAM_MODE:
326                 pipep->flags &= ~RDR_PIPEFLAG_MESSAGE_MODE;
327                 break;
328             case FILE_PIPE_MESSAGE_MODE:
329                 pipep->flags |= RDR_PIPEFLAG_MESSAGE_MODE;
330                 break;
331             }
332             switch ( fpInfo->CompletionMode ) {
333             case FILE_PIPE_QUEUE_OPERATION:
334                 pipep->flags |= RDR_PIPEFLAG_BLOCKING;
335                 break;
336             case FILE_PIPE_COMPLETE_OPERATION:
337                 pipep->flags &= ~RDR_PIPEFLAG_BLOCKING;
338                 break;
339             }
340             code = STATUS_SUCCESS;
341             break;
342         }
343         default:
344             code = STATUS_NOT_SUPPORTED;
345         }
346     }
347   done:
348     lock_ReleaseWrite(&RDR_globalPipeLock);
349
350     return code;
351 }