Windows: cleanup redirector pipes
[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 void
73 RDR_ShutdownPipe(void)
74 {
75     while (RDR_allPipes) {
76         RDR_CleanupPipe(RDR_allPipes->index);
77     }
78     lock_FinalizeRWLock(&RDR_globalPipeLock);
79 }
80
81 RDR_pipe_t *
82 RDR_FindPipe(ULONG index, int locked)
83 {
84     RDR_pipe_t *pipep;
85
86     if ( !locked)
87         lock_ObtainRead(&RDR_globalPipeLock);
88     for ( pipep=RDR_allPipes; pipep; pipep=pipep->next) {
89         if (pipep->index == index)
90             break;
91     }
92     if ( !locked)
93         lock_ReleaseRead(&RDR_globalPipeLock);
94     return pipep;
95 }
96
97 /* called to make a fid structure into an Pipe fid structure */
98 DWORD
99 RDR_SetupPipe( ULONG index, cm_fid_t *parentFid, cm_fid_t *rootFid,
100                WCHAR     *Name, DWORD      NameLength,
101                cm_user_t *userp)
102 {
103     RDR_pipe_t *pipep;
104     cm_req_t req;
105     DWORD status;
106     char name[MAX_PATH];
107     int newpipe = 0;
108
109     cm_InitReq(&req);
110
111     lock_ObtainWrite(&RDR_globalPipeLock);
112     pipep = RDR_FindPipe(index, TRUE);
113
114     if (pipep) {
115         /* we are reusing a previous pipe */
116         if (cm_FidCmp(&pipep->parentFid, parentFid)) {
117             pipep->parentFid = *parentFid;
118             if (pipep->parentScp) {
119                 cm_ReleaseSCache(pipep->parentScp);
120                 pipep->parentScp = NULL;
121             }
122             cm_GetSCache(parentFid, NULL, &pipep->parentScp, userp, &req);
123             pipep->rootFid = *rootFid;
124         }
125     } else {
126         /* need to allocate a new one */
127         newpipe = 1;
128         pipep = malloc(sizeof(*pipep));
129         if (pipep == NULL) {
130             status = STATUS_NO_MEMORY;
131             goto done;
132         }
133         memset(pipep, 0, sizeof(*pipep));
134         pipep->index = index;
135         if (parentFid->cell == 0) {
136             pipep->parentFid = cm_data.rootFid;
137             pipep->parentScp = cm_RootSCachep(userp, &req);
138             cm_HoldSCache(pipep->parentScp);
139         } else {
140             pipep->parentFid = *parentFid;
141             cm_GetSCache(parentFid, NULL, &pipep->parentScp, userp, &req);
142         }
143         if (rootFid->cell == 0) {
144             pipep->rootFid = cm_data.rootFid;
145         } else {
146             pipep->rootFid = *rootFid;
147         }
148     }
149
150     StringCbCopyNW( pipep->name, sizeof(pipep->name), Name, NameLength);
151     cm_Utf16ToUtf8( pipep->name, -1, name, sizeof(name));
152
153     status = MSRPC_InitConn(&pipep->rpc_conn, name);
154     if (status == STATUS_SUCCESS) {
155         pipep->flags |= RDR_PIPEFLAG_MESSAGE_MODE;
156         pipep->devstate = RDR_DEVICESTATE_READMSGFROMPIPE |
157                           RDR_DEVICESTATE_MESSAGEMODEPIPE |
158                           RDR_DEVICESTATE_PIPECLIENTEND;
159
160         if (newpipe) {
161             if (RDR_allPipes == NULL)
162                 RDR_allPipes = RDR_allPipesLast = pipep;
163             else {
164                 pipep->prev = RDR_allPipesLast;
165                 RDR_allPipesLast->next = pipep;
166                 RDR_allPipesLast = pipep;
167             }
168         }
169     }
170     else
171     {
172         if (pipep->parentScp)
173             cm_ReleaseSCache(pipep->parentScp);
174
175         if (pipep->inAllocp)
176             free(pipep->inAllocp);
177         if (pipep->outAllocp)
178             free(pipep->outAllocp);
179
180         if (!newpipe) {
181             if (RDR_allPipes == RDR_allPipesLast)
182                 RDR_allPipes = RDR_allPipesLast = NULL;
183             else {
184                 if (pipep->prev == NULL)
185                     RDR_allPipes = pipep->next;
186                 else
187                     pipep->prev->next = pipep->next;
188                 if (pipep->next == NULL) {
189                     RDR_allPipesLast = pipep->prev;
190                     pipep->prev->next = NULL;
191                 } else
192                     pipep->next->prev = pipep->prev;
193             }
194         }
195         free(pipep);
196     }
197
198   done:
199     lock_ReleaseWrite(&RDR_globalPipeLock);
200
201     return status;
202 }
203
204
205 void
206 RDR_CleanupPipe(ULONG index)
207 {
208     RDR_pipe_t *pipep;
209
210     lock_ObtainWrite(&RDR_globalPipeLock);
211     pipep = RDR_FindPipe(index, TRUE);
212
213     if (pipep) {
214         if (pipep->parentScp)
215             cm_ReleaseSCache(pipep->parentScp);
216
217         if (pipep->inAllocp)
218             free(pipep->inAllocp);
219         if (pipep->outAllocp)
220             free(pipep->outAllocp);
221
222         MSRPC_FreeConn(&pipep->rpc_conn);
223
224         if (RDR_allPipes == RDR_allPipesLast)
225             RDR_allPipes = RDR_allPipesLast = NULL;
226         else {
227             if (pipep->prev == NULL)
228                 RDR_allPipes = pipep->next;
229             else
230                 pipep->prev->next = pipep->next;
231             if (pipep->next == NULL) {
232                 RDR_allPipesLast = pipep->prev;
233                 pipep->prev->next = NULL;
234             } else
235                 pipep->next->prev = pipep->prev;
236         }
237         free(pipep);
238     }
239     lock_ReleaseWrite(&RDR_globalPipeLock);
240
241 }
242
243 DWORD
244 RDR_Pipe_Read(ULONG index, ULONG BufferLength, void *MappedBuffer,
245               ULONG *pBytesProcessed, cm_req_t *reqp, cm_user_t *userp)
246 {
247     RDR_pipe_t *pipep;
248     DWORD   code = STATUS_INVALID_PIPE_STATE;
249
250     lock_ObtainWrite(&RDR_globalPipeLock);
251     pipep = RDR_FindPipe(index, TRUE);
252
253     if (pipep) {
254         code = MSRPC_PrepareRead(&pipep->rpc_conn);
255         if (code == 0) {
256             *pBytesProcessed = MSRPC_ReadMessageLength(&pipep->rpc_conn, BufferLength);
257             code = MSRPC_ReadMessage(&pipep->rpc_conn, MappedBuffer, *pBytesProcessed);
258         }
259
260     }
261     lock_ReleaseWrite(&RDR_globalPipeLock);
262
263     return code;
264 }
265
266 DWORD
267 RDR_Pipe_Write( ULONG index, ULONG BufferLength, void *MappedBuffer,
268                 cm_req_t *reqp, cm_user_t *userp)
269 {
270     RDR_pipe_t *pipep;
271     DWORD   code = STATUS_INVALID_PIPE_STATE;
272
273     lock_ObtainWrite(&RDR_globalPipeLock);
274     pipep = RDR_FindPipe(index, TRUE);
275
276     if (pipep) {
277         code = MSRPC_WriteMessage( &pipep->rpc_conn, MappedBuffer,
278                                    BufferLength, userp);
279     }
280     lock_ReleaseWrite(&RDR_globalPipeLock);
281
282     return code;
283 }
284
285 DWORD
286 RDR_Pipe_QueryInfo( ULONG index, ULONG InfoClass,
287                     ULONG BufferLength, void *MappedBuffer,
288                     ULONG *pBytesProcessed, cm_req_t *reqp, cm_user_t *userp)
289 {
290     RDR_pipe_t *pipep;
291     DWORD   code = STATUS_INVALID_PIPE_STATE;
292     size_t      length;
293
294     lock_ObtainWrite(&RDR_globalPipeLock);
295     pipep = RDR_FindPipe(index, TRUE);
296
297     if (pipep) {
298         switch ( InfoClass ) {
299         case FileBasicInformation: {
300             FILE_BASIC_INFORMATION * fbInfo = (FILE_BASIC_INFORMATION *)MappedBuffer;
301
302             memset(fbInfo, 0, sizeof(FILE_BASIC_INFORMATION));
303             fbInfo->FileAttributes = FILE_ATTRIBUTE_NORMAL;
304             *pBytesProcessed = (DWORD)(sizeof(FILE_BASIC_INFORMATION));
305             code = STATUS_SUCCESS;
306             break;
307         }
308         case FileStandardInformation: {
309             FILE_STANDARD_INFORMATION * fsInfo = (FILE_STANDARD_INFORMATION *)MappedBuffer;
310
311             memset(fsInfo, 0, sizeof(FILE_STANDARD_INFORMATION));
312             *pBytesProcessed = (DWORD)(sizeof(FILE_STANDARD_INFORMATION));
313             code = STATUS_SUCCESS;
314             break;
315         }
316         case FileNameInformation: {
317             FILE_NAME_INFORMATION * fnInfo = (FILE_NAME_INFORMATION *)MappedBuffer;
318
319             StringCbLengthW(pipep->name, sizeof(pipep->name), &length);
320             if (BufferLength < sizeof(FILE_NAME_INFORMATION) + length) {
321                 code = STATUS_BUFFER_OVERFLOW;
322                 goto done;
323             }
324             fnInfo->FileNameLength = (DWORD)length;
325             memcpy( fnInfo->FileName, pipep->name, length);
326             *pBytesProcessed = (DWORD)(sizeof(DWORD) + length);
327             code = STATUS_SUCCESS;
328             break;
329         }
330         default:
331             code = STATUS_NOT_SUPPORTED;
332         }
333     }
334
335   done:
336     lock_ReleaseWrite(&RDR_globalPipeLock);
337
338     if (code)
339         *pBytesProcessed = 0;
340
341     return code;
342 }
343
344 DWORD
345 RDR_Pipe_SetInfo( ULONG index, ULONG InfoClass,
346                   ULONG BufferLength, void *MappedBuffer,
347                   cm_req_t *reqp, cm_user_t *userp)
348 {
349     RDR_pipe_t *pipep;
350     DWORD   code = STATUS_INVALID_PIPE_STATE;
351
352     lock_ObtainWrite(&RDR_globalPipeLock);
353     pipep = RDR_FindPipe(index, TRUE);
354
355     if (pipep) {
356         switch ( InfoClass ) {
357         case FilePipeInformation: {
358             FILE_PIPE_INFORMATION * fpInfo = (FILE_PIPE_INFORMATION *)MappedBuffer;
359
360             if (BufferLength != sizeof(FILE_PIPE_INFORMATION)) {
361                 code = STATUS_INFO_LENGTH_MISMATCH;
362                 goto done;
363             }
364
365             switch ( fpInfo->ReadMode ) {
366             case FILE_PIPE_BYTE_STREAM_MODE:
367                 pipep->flags &= ~RDR_PIPEFLAG_MESSAGE_MODE;
368                 break;
369             case FILE_PIPE_MESSAGE_MODE:
370                 pipep->flags |= RDR_PIPEFLAG_MESSAGE_MODE;
371                 break;
372             }
373             switch ( fpInfo->CompletionMode ) {
374             case FILE_PIPE_QUEUE_OPERATION:
375                 pipep->flags |= RDR_PIPEFLAG_BLOCKING;
376                 break;
377             case FILE_PIPE_COMPLETE_OPERATION:
378                 pipep->flags &= ~RDR_PIPEFLAG_BLOCKING;
379                 break;
380             }
381             code = STATUS_SUCCESS;
382             break;
383         }
384         default:
385             code = STATUS_NOT_SUPPORTED;
386         }
387     }
388   done:
389     lock_ReleaseWrite(&RDR_globalPipeLock);
390
391     return code;
392 }