Windows: Redir Ioctl thread safety
[openafs.git] / src / WINNT / afsrdr / user / RDRIoctl.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * Copyright (c) 2008 Secure Endpoints, Inc.
12  * Copyright (c) 2009-2011 Your File System, Inc.
13  * All rights reserved.
14  *
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions are met:
17  *
18  * - Redistributions of source code must retain the above copyright notice,
19  *   this list of conditions and the following disclaimer.
20  * - Redistributions in binary form must reproduce the above copyright notice,
21  *   this list of conditions and the following disclaimer in the documentation
22  *   and/or other materials provided with the distribution.
23  * - Neither the name of Secure Endpoints Inc. nor the names of its contributors
24  *   may be used to endorse or promote products derived from this software without
25  *   specific prior written permission from Secure Endpoints, Inc. and
26  *   Your File System, Inc.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39  */
40
41 #include <afsconfig.h>
42 #include <afs/param.h>
43 #include <roken.h>
44
45 #include <afs/stds.h>
46
47 #include <windows.h>
48 #include <sddl.h>
49 #include <stdlib.h>
50 #include <malloc.h>
51 #include <string.h>
52 #include <stdio.h>
53 #include <time.h>
54 #include <strsafe.h>
55
56 #include <osi.h>
57
58 #include "afsd.h"
59
60 #include "cm_rpc.h"
61 #include "afs/afsrpc.h"
62 #include "afs/auth.h"
63
64 #include "smb_iocons.h"
65 #define RDR_IOCTL_PRIVATE 1
66 #include "RDRIoctl.h"
67 #include "smb.h"
68 #include "cm_nls.h"
69
70 static RDR_ioctlProc_t *RDR_ioctlProcsp[CM_IOCTL_MAXPROCS];
71
72 static RDR_ioctl_t * RDR_allIoctls = NULL, *RDR_allIoctlsLast = NULL;
73 static osi_rwlock_t  RDR_globalIoctlLock;
74
75 extern wchar_t       RDR_UNCName[];
76
77 void
78 RDR_InitIoctl(void)
79 {
80     int i;
81
82     lock_InitializeRWLock(&RDR_globalIoctlLock, "RDR global ioctl lock", LOCK_HIERARCHY_RDR_GLOBAL);
83
84     for (i=0; i<CM_IOCTL_MAXPROCS; i++)
85         RDR_ioctlProcsp[i] = NULL;
86
87     RDR_ioctlProcsp[VIOCGETAL] = RDR_IoctlGetACL;
88     RDR_ioctlProcsp[VIOC_FILE_CELL_NAME] = RDR_IoctlGetFileCellName;
89     RDR_ioctlProcsp[VIOCSETAL] = RDR_IoctlSetACL;
90     RDR_ioctlProcsp[VIOC_FLUSHVOLUME] = RDR_IoctlFlushVolume;
91     RDR_ioctlProcsp[VIOCFLUSH] = RDR_IoctlFlushFile;
92     RDR_ioctlProcsp[VIOCSETVOLSTAT] = RDR_IoctlSetVolumeStatus;
93     RDR_ioctlProcsp[VIOCGETVOLSTAT] = RDR_IoctlGetVolumeStatus;
94     RDR_ioctlProcsp[VIOCWHEREIS] = RDR_IoctlWhereIs;
95     RDR_ioctlProcsp[VIOC_AFS_STAT_MT_PT] = RDR_IoctlStatMountPoint;
96     RDR_ioctlProcsp[VIOC_AFS_DELETE_MT_PT] = RDR_IoctlDeleteMountPoint;
97     RDR_ioctlProcsp[VIOCCKSERV] = RDR_IoctlCheckServers;
98     RDR_ioctlProcsp[VIOC_GAG] = RDR_IoctlGag;
99     RDR_ioctlProcsp[VIOCCKBACK] = RDR_IoctlCheckVolumes;
100     RDR_ioctlProcsp[VIOCSETCACHESIZE] = RDR_IoctlSetCacheSize;
101     RDR_ioctlProcsp[VIOCGETCACHEPARMS] = RDR_IoctlGetCacheParms;
102     RDR_ioctlProcsp[VIOCGETCELL] = RDR_IoctlGetCell;
103     RDR_ioctlProcsp[VIOCNEWCELL] = RDR_IoctlNewCell;
104     RDR_ioctlProcsp[VIOC_GET_WS_CELL] = RDR_IoctlGetWsCell;
105     RDR_ioctlProcsp[VIOC_AFS_SYSNAME] = RDR_IoctlSysName;
106     RDR_ioctlProcsp[VIOC_GETCELLSTATUS] = RDR_IoctlGetCellStatus;
107     RDR_ioctlProcsp[VIOC_SETCELLSTATUS] = RDR_IoctlSetCellStatus;
108     RDR_ioctlProcsp[VIOC_SETSPREFS] = RDR_IoctlSetSPrefs;
109     RDR_ioctlProcsp[VIOC_GETSPREFS] = RDR_IoctlGetSPrefs;
110     RDR_ioctlProcsp[VIOC_STOREBEHIND] = RDR_IoctlStoreBehind;
111     RDR_ioctlProcsp[VIOC_AFS_CREATE_MT_PT] = RDR_IoctlCreateMountPoint;
112     RDR_ioctlProcsp[VIOC_TRACECTL] = RDR_IoctlTraceControl;
113     RDR_ioctlProcsp[VIOCSETTOK] = RDR_IoctlSetToken;
114     RDR_ioctlProcsp[VIOCGETTOK] = RDR_IoctlGetTokenIter;
115     RDR_ioctlProcsp[VIOCNEWGETTOK] = RDR_IoctlGetToken;
116     RDR_ioctlProcsp[VIOCDELTOK] = RDR_IoctlDelToken;
117     RDR_ioctlProcsp[VIOCDELALLTOK] = RDR_IoctlDelAllToken;
118     RDR_ioctlProcsp[VIOC_SYMLINK] = RDR_IoctlSymlink;
119     RDR_ioctlProcsp[VIOC_LISTSYMLINK] = RDR_IoctlListlink;
120     RDR_ioctlProcsp[VIOC_DELSYMLINK] = RDR_IoctlDeletelink;
121     RDR_ioctlProcsp[VIOC_MAKESUBMOUNT] = RDR_IoctlMakeSubmount;
122     RDR_ioctlProcsp[VIOC_GETRXKCRYPT] = RDR_IoctlGetRxkcrypt;
123     RDR_ioctlProcsp[VIOC_SETRXKCRYPT] = RDR_IoctlSetRxkcrypt;
124     RDR_ioctlProcsp[VIOC_ISSYMLINK] = RDR_IoctlIslink;
125     RDR_ioctlProcsp[VIOC_TRACEMEMDUMP] = RDR_IoctlMemoryDump;
126     RDR_ioctlProcsp[VIOC_ISSYMLINK] = RDR_IoctlIslink;
127     RDR_ioctlProcsp[VIOC_FLUSHALL] = RDR_IoctlFlushAllVolumes;
128     RDR_ioctlProcsp[VIOCGETFID] = RDR_IoctlGetFid;
129     RDR_ioctlProcsp[VIOCGETOWNER] = RDR_IoctlGetOwner;
130     RDR_ioctlProcsp[VIOC_RXSTAT_PROC] = RDR_IoctlRxStatProcess;
131     RDR_ioctlProcsp[VIOC_RXSTAT_PEER] = RDR_IoctlRxStatPeer;
132     RDR_ioctlProcsp[VIOC_UUIDCTL] = RDR_IoctlUUIDControl;
133     RDR_ioctlProcsp[VIOC_PATH_AVAILABILITY] = RDR_IoctlPathAvailability;
134     RDR_ioctlProcsp[VIOC_GETFILETYPE] = RDR_IoctlGetFileType;
135     RDR_ioctlProcsp[VIOC_VOLSTAT_TEST] = RDR_IoctlVolStatTest;
136     RDR_ioctlProcsp[VIOC_UNICODECTL] = RDR_IoctlUnicodeControl;
137     RDR_ioctlProcsp[VIOC_SETOWNER] = RDR_IoctlSetOwner;
138     RDR_ioctlProcsp[VIOC_SETGROUP] = RDR_IoctlSetGroup;
139     RDR_ioctlProcsp[VIOCNEWCELL2] = RDR_IoctlNewCell2;
140     RDR_ioctlProcsp[VIOC_GETUNIXMODE] = RDR_IoctlGetUnixMode;
141     RDR_ioctlProcsp[VIOC_SETUNIXMODE] = RDR_IoctlSetUnixMode;
142     RDR_ioctlProcsp[VIOC_GETVERIFYDATA] = RDR_IoctlGetVerifyData;
143     RDR_ioctlProcsp[VIOC_SETVERIFYDATA] = RDR_IoctlSetVerifyData;
144 }
145
146 void
147 RDR_ShutdownIoctl(void)
148 {
149     lock_FinalizeRWLock(&RDR_globalIoctlLock);
150 }
151
152 /* called to make a fid structure into an IOCTL fid structure */
153 void
154 RDR_SetupIoctl(ULONG index, cm_fid_t *parentFid, cm_fid_t *rootFid, cm_user_t *userp)
155 {
156     RDR_ioctl_t *iop;
157     cm_req_t req;
158
159     cm_InitReq(&req);
160
161     lock_ObtainWrite(&RDR_globalIoctlLock);
162     for ( iop=RDR_allIoctls; iop; iop=iop->next) {
163         if (iop->index == index)
164             break;
165     }
166
167     if (iop) {
168         iop->flags = 0;
169
170         /* we are reusing a previous ioctl */
171         if (cm_FidCmp(&iop->parentFid, parentFid)) {
172             iop->parentFid = *parentFid;
173             if (iop->parentScp) {
174                 cm_ReleaseSCache(iop->parentScp);
175                 iop->parentScp = NULL;
176             }
177             cm_GetSCache(parentFid, NULL, &iop->parentScp, userp, &req);
178             iop->rootFid = *rootFid;
179         }
180     } else {
181         /* need to allocate a new one */
182         iop = malloc(sizeof(*iop));
183         memset(iop, 0, sizeof(*iop));
184         if (RDR_allIoctls == NULL)
185             RDR_allIoctls = RDR_allIoctlsLast = iop;
186         else {
187             iop->prev = RDR_allIoctlsLast;
188             RDR_allIoctlsLast->next = iop;
189             RDR_allIoctlsLast = iop;
190         }
191         iop->index = index;
192         if (parentFid->cell == 0) {
193             iop->parentFid = cm_data.rootFid;
194             iop->parentScp = cm_RootSCachep(userp, &req);
195             cm_HoldSCache(iop->parentScp);
196         } else {
197             iop->parentFid = *parentFid;
198             cm_GetSCache(parentFid, NULL, &iop->parentScp, userp, &req);
199         }
200         if (rootFid->cell == 0) {
201             iop->rootFid = cm_data.rootFid;
202         } else {
203             iop->rootFid = *rootFid;
204         }
205     }
206     lock_ReleaseWrite(&RDR_globalIoctlLock);
207 }
208
209 static void
210 RDR_DestroyIoctl(RDR_ioctl_t *iop)
211 {
212     if (iop == NULL)
213         return;
214
215     if (iop->parentScp)
216         cm_ReleaseSCache(iop->parentScp);
217
218     if (iop->ioctl.inAllocp)
219         free(iop->ioctl.inAllocp);
220     if (iop->ioctl.outAllocp)
221         free(iop->ioctl.outAllocp);
222
223     if (RDR_allIoctls == RDR_allIoctlsLast)
224         RDR_allIoctls = RDR_allIoctlsLast = NULL;
225     else {
226         if (iop->prev == NULL)
227             RDR_allIoctls = iop->next;
228         else
229             iop->prev->next = iop->next;
230         if (iop->next == NULL) {
231             RDR_allIoctlsLast = iop->prev;
232             iop->prev->next = NULL;
233         } else
234             iop->next->prev = iop->prev;
235     }
236     free(iop);
237 }
238
239 void
240 RDR_CleanupIoctl(ULONG index)
241 {
242     RDR_ioctl_t *iop;
243
244     lock_ObtainWrite(&RDR_globalIoctlLock);
245     for ( iop=RDR_allIoctls; iop; iop=iop->next) {
246         if (iop->index == index)
247             break;
248     }
249
250     if (iop) {
251         if (iop->refCount == 0) {
252             RDR_DestroyIoctl(iop);
253         }
254         else
255         {
256             iop->flags |= RDR_IOCTL_FLAG_CLEANED;
257         }
258     }
259     lock_ReleaseWrite(&RDR_globalIoctlLock);
260 }
261
262 /* called when we receive a write call.  If this is the first write call after
263  * a series of reads (or the very first call), then we start a new call.
264  * We also ensure that things are properly initialized for the start of a call.
265  */
266 void
267 RDR_IoctlPrepareWrite(RDR_ioctl_t *ioctlp)
268 {
269     /* make sure the buffer(s) are allocated */
270     if (!ioctlp->ioctl.inAllocp)
271         ioctlp->ioctl.inAllocp = malloc(CM_IOCTL_MAXDATA);
272     if (!ioctlp->ioctl.outAllocp)
273         ioctlp->ioctl.outAllocp = malloc(CM_IOCTL_MAXDATA);
274
275     /* Fixes fs la problem.  We do a StrToOEM later and if this data isn't initialized we get memory issues. */
276     (void) memset(ioctlp->ioctl.inAllocp, 0, CM_IOCTL_MAXDATA);
277     (void) memset(ioctlp->ioctl.outAllocp, 0, CM_IOCTL_MAXDATA);
278
279     /* and make sure that we've reset our state for the new incoming request */
280     if (!(ioctlp->ioctl.flags & CM_IOCTLFLAG_DATAIN)) {
281         ioctlp->ioctl.inCopied = 0;
282         ioctlp->ioctl.outCopied = 0;
283         ioctlp->ioctl.inDatap = ioctlp->ioctl.inAllocp;
284         ioctlp->ioctl.outDatap = ioctlp->ioctl.outAllocp;
285         ioctlp->ioctl.flags |= CM_IOCTLFLAG_DATAIN;
286     }
287 }
288
289 /* called when we receive a read call, does the send of the received data if
290  * this is the first read call.  This is the function that actually makes the
291  * call to the ioctl code.
292  */
293 afs_int32
294 RDR_IoctlPrepareRead(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags)
295 {
296     afs_int32 opcode;
297     RDR_ioctlProc_t *procp = NULL;
298     afs_int32 code;
299
300     if (ioctlp->ioctl.flags & CM_IOCTLFLAG_DATAIN) {
301         ioctlp->ioctl.flags &= ~CM_IOCTLFLAG_DATAIN;
302
303         /* do the call now, or fail if we didn't get an opcode, or
304          * enough of an opcode.
305          */
306         if (ioctlp->ioctl.inCopied < sizeof(afs_int32))
307             return CM_ERROR_INVAL;
308
309         memcpy(&opcode, ioctlp->ioctl.inDatap, sizeof(afs_int32));
310         ioctlp->ioctl.inDatap += sizeof(afs_int32);
311
312         osi_Log1(afsd_logp, "Ioctl opcode 0x%x", opcode);
313
314         /* check for opcode out of bounds */
315         if (opcode < 0 || opcode >= CM_IOCTL_MAXPROCS)
316             return CM_ERROR_TOOBIG;
317
318         /* check for no such proc */
319         procp = RDR_ioctlProcsp[opcode];
320         if (procp == NULL)
321             return CM_ERROR_BADOP;
322
323         /* otherwise, make the call */
324         ioctlp->ioctl.outDatap += sizeof(afs_int32); /* reserve room for return code */
325         code = (*procp)(ioctlp, userp, pflags);
326
327         osi_Log1(afsd_logp, "Ioctl return code 0x%x", code);
328
329         /* copy in return code */
330         memcpy(ioctlp->ioctl.outAllocp, &code, sizeof(afs_int32));
331     }
332     return 0;
333 }
334
335 RDR_ioctl_t *
336 RDR_FindIoctl(ULONG index)
337 {
338     RDR_ioctl_t *iop;
339
340     lock_ObtainRead(&RDR_globalIoctlLock);
341     for ( iop=RDR_allIoctls; iop; iop=iop->next) {
342         if (iop->index == index &&
343             !(iop->flags & RDR_IOCTL_FLAG_CLEANED)) {
344             InterlockedIncrement(&iop->refCount);
345             break;
346         }
347     }
348     lock_ReleaseRead(&RDR_globalIoctlLock);
349     return iop;
350 }
351
352 void
353 RDR_ReleaseIoctl(RDR_ioctl_t * iop)
354 {
355     lock_ObtainWrite(&RDR_globalIoctlLock);
356     InterlockedDecrement(&iop->refCount);
357
358     if (iop->refCount == 0 &&
359         (iop->flags & RDR_IOCTL_FLAG_CLEANED))
360     {
361         RDR_DestroyIoctl(iop);
362     }
363     lock_ReleaseWrite(&RDR_globalIoctlLock);
364 }
365
366 /* called from RDR_ReceiveCoreRead when we receive a read on the ioctl fid */
367 afs_int32
368 RDR_IoctlRead(cm_user_t *userp, ULONG RequestId, ULONG BufferLength, void *MappedBuffer, ULONG *pBytesProcessed, cm_req_t *reqp, afs_uint32 pflags)
369 {
370     RDR_ioctl_t *iop;
371     afs_uint32 count;
372     afs_int32 code = 0;
373
374     iop = RDR_FindIoctl(RequestId);
375     if (iop == NULL)
376         return CM_ERROR_BADFD;
377
378     /* turn the connection around, if required */
379     code = RDR_IoctlPrepareRead(iop, userp, pflags);
380     if (code == 0) {
381
382         count = (afs_int32)((iop->ioctl.outDatap - iop->ioctl.outAllocp) - iop->ioctl.outCopied);
383         if (BufferLength < count)
384             count = BufferLength;
385
386         /* now copy the data into the response packet */
387         memcpy((char *)MappedBuffer, iop->ioctl.outCopied + iop->ioctl.outAllocp, count);
388
389         /* and adjust the counters */
390         iop->ioctl.outCopied += count;
391
392         *pBytesProcessed = count;
393
394         RDR_ReleaseIoctl(iop);
395     }
396     return code;
397 }
398
399 /* called from RDR_PioctWRite when we receive a write call on the IOCTL
400  * file descriptor.
401  */
402 afs_int32
403 RDR_IoctlWrite(cm_user_t *userp, ULONG RequestId, ULONG BufferLength, void *MappedBuffer, cm_req_t *reqp)
404 {
405     afs_int32 code = 0;
406     RDR_ioctl_t *iop;
407
408     iop = RDR_FindIoctl(RequestId);
409     if (iop == NULL)
410         return CM_ERROR_BADFD;
411
412     RDR_IoctlPrepareWrite(iop);
413
414     if (BufferLength + iop->ioctl.inCopied > CM_IOCTL_MAXDATA) {
415         code = CM_ERROR_TOOBIG;
416     }
417     else
418     {
419         /* copy data */
420         memcpy(iop->ioctl.inDatap + iop->ioctl.inCopied, (char *)MappedBuffer, BufferLength);
421
422         /* adjust counts */
423         iop->ioctl.inCopied += BufferLength;
424     }
425
426     RDR_ReleaseIoctl(iop);
427     return code;
428 }
429
430
431 /* parse the passed-in file name and do a namei on it.  If we fail,
432  * return an error code, otherwise return the vnode located in *scpp.
433  */
434 #define CM_PARSE_FLAG_LITERAL 1
435
436 afs_int32
437 RDR_ParseIoctlPath(RDR_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
438                    cm_scache_t **scpp, afs_uint32 flags)
439 {
440     afs_int32 code;
441     cm_scache_t *substRootp = NULL;
442     cm_scache_t *iscp = NULL;
443     char     *inPath;
444     wchar_t     *relativePath = NULL;
445     wchar_t     *lastComponent = NULL;
446     afs_uint32 follow = (flags & CM_PARSE_FLAG_LITERAL ? CM_FLAG_NOMOUNTCHASE : CM_FLAG_FOLLOW);
447     int free_path = FALSE;
448
449     inPath = ioctlp->ioctl.inDatap;
450     /* setup the next data value for the caller to use */
451     ioctlp->ioctl.inDatap += (long)strlen(ioctlp->ioctl.inDatap) + 1;;
452
453     osi_Log1(afsd_logp, "RDR_ParseIoctlPath inPath %s", osi_LogSaveString(afsd_logp,inPath));
454
455     /* This is usually the file name, but for StatMountPoint it is the path. */
456     /* ioctlp->inDatap can be either of the form:
457      *    \path\.
458      *    \path\file
459      *    \\netbios-name\submount\path\.
460      *    \\netbios-name\submount\path\file
461      */
462
463     /* We do not perform path name translation on the ioctl path data
464      * because these paths were not translated by Windows through the
465      * file system API.  Therefore, they are not OEM characters but
466      * whatever the display character set is.
467      */
468
469     // TranslateExtendedChars(relativePath);
470
471     /* This is usually nothing, but for StatMountPoint it is the file name. */
472     // TranslateExtendedChars(ioctlp->ioctl.inDatap);
473
474     /* If the string starts with our UTF-8 prefix (which is the
475        sequence [ESC,'%','G'] as used by ISO-2022 to designate UTF-8
476        strings), we assume that the provided path is UTF-8.  Otherwise
477        we have to convert the string to UTF-8, since that is what we
478        want to use everywhere else.*/
479
480     if (memcmp(inPath, utf8_prefix, utf8_prefix_size) == 0) {
481         /* String is UTF-8 */
482         inPath += utf8_prefix_size;
483         ioctlp->ioctl.flags |= CM_IOCTLFLAG_USEUTF8;
484
485         relativePath = cm_Utf8ToClientStringAlloc(inPath, -1, NULL);
486         osi_Log1(afsd_logp, "RDR_ParseIoctlPath UTF8 relativePath %S",
487                  osi_LogSaveStringW(afsd_logp,relativePath));
488     } else {
489         int cch;
490         /* Not a UTF-8 string */
491         /* TODO: If this is an OEM string, we should convert it to UTF-8. */
492         if (smb_StoreAnsiFilenames) {
493             cch = cm_AnsiToClientString(inPath, -1, NULL, 0);
494 #ifdef DEBUG
495             osi_assert(cch > 0);
496 #endif
497             relativePath = malloc(cch * sizeof(clientchar_t));
498             cm_AnsiToClientString(inPath, -1, relativePath, cch);
499         } else {
500             TranslateExtendedChars(inPath);
501
502             cch = cm_OemToClientString(inPath, -1, NULL, 0);
503 #ifdef DEBUG
504             osi_assert(cch > 0);
505 #endif
506             relativePath = malloc(cch * sizeof(clientchar_t));
507             cm_OemToClientString(inPath, -1, relativePath, cch);
508         }
509         osi_Log1(afsd_logp, "RDR_ParseIoctlPath ASCII relativePath %S",
510                  osi_LogSaveStringW(afsd_logp,relativePath));
511     }
512
513     if (relativePath[0] == relativePath[1] &&
514          relativePath[1] == '\\' &&
515          !cm_ClientStrCmpNI(RDR_UNCName,relativePath+2,(int)wcslen(RDR_UNCName)))
516     {
517         wchar_t shareName[256];
518         wchar_t *sharePath;
519         int shareFound, i;
520         wchar_t *p;
521
522         /* We may have found a UNC path.
523          * If the first component is the RDR UNC Name,
524          * then throw out the second component (the submount)
525          * since it had better expand into the value of ioctl->tidPathp
526          */
527         p = relativePath + 2 + wcslen(RDR_UNCName) + 1;                 /* buffer overflow vuln.? */
528         if ( !cm_ClientStrCmpNI(_C("all"), p, 3) )
529             p += 4;
530
531         for (i = 0; *p && *p != '\\'; i++,p++ ) {
532             shareName[i] = *p;
533         }
534         p++;                    /* skip past trailing slash */
535         shareName[i] = 0;       /* terminate string */
536
537         shareFound = smb_FindShare(NULL, NULL, shareName, &sharePath);
538         if ( shareFound ) {
539             /* we found a sharename, therefore use the resulting path */
540             code = cm_NameI(cm_RootSCachep(userp, reqp), sharePath,
541                              CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
542                              userp, NULL, reqp, &substRootp);
543             free(sharePath);
544             if (code) {
545                 osi_Log1(afsd_logp,"RDR_ParseIoctlPath [1] code 0x%x", code);
546                 if (free_path)
547                     free(relativePath);
548                 return code;
549             }
550
551             lastComponent = cm_ClientStrRChr(p, '\\');
552             if (lastComponent && (lastComponent - p) > 1 && wcslen(lastComponent) > 1) {
553                 *lastComponent = '\0';
554                 lastComponent++;
555
556                 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
557                                  userp, NULL, reqp, &iscp);
558                 if (code == 0)
559                     code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
560                                     userp, NULL, reqp, scpp);
561                 if (iscp)
562                     cm_ReleaseSCache(iscp);
563             } else {
564                 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD,
565                                 userp, NULL, reqp, scpp);
566             }
567             cm_ReleaseSCache(substRootp);
568             if (code) {
569                 osi_Log1(afsd_logp,"RDR_ParseIoctlPath [2] code 0x%x", code);
570                 if (free_path)
571                     free(relativePath);
572                 return code;
573             }
574         } else {
575             /* otherwise, treat the name as a cellname mounted off the afs root.
576              * This requires that we reconstruct the shareName string with
577              * leading and trailing slashes.
578              */
579             p = relativePath + 2 + wcslen(RDR_UNCName) + 1;
580             if ( !cm_ClientStrCmpNI(_C("all"), p, 3) )
581                 p += 4;
582
583             shareName[0] = '/';
584             for (i = 1; *p && *p != '\\'; i++,p++ ) {
585                 shareName[i] = *p;
586             }
587             p++;                    /* skip past trailing slash */
588             shareName[i++] = '/';       /* add trailing slash */
589             shareName[i] = 0;       /* terminate string */
590
591
592             code = cm_NameI(cm_RootSCachep(userp, reqp), shareName,
593                              CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
594                              userp, NULL, reqp, &substRootp);
595             if (code) {
596                 osi_Log1(afsd_logp,"RDR_ParseIoctlPath [3] code 0x%x", code);
597                 if (free_path)
598                     free(relativePath);
599                 return code;
600             }
601
602             lastComponent = cm_ClientStrRChr(p, '\\');
603             if (lastComponent && (lastComponent - p) > 1 && wcslen(lastComponent) > 1) {
604                 *lastComponent = '\0';
605                 lastComponent++;
606
607                 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
608                                  userp, NULL, reqp, &iscp);
609                 if (code == 0)
610                     code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
611                                     userp, NULL, reqp, scpp);
612                 if (iscp)
613                     cm_ReleaseSCache(iscp);
614             } else {
615                 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD,
616                                 userp, NULL, reqp, scpp);
617             }
618
619             if (code) {
620                 cm_ReleaseSCache(substRootp);
621                 osi_Log1(afsd_logp,"RDR_ParseIoctlPath code [4] 0x%x", code);
622                 if (free_path)
623                     free(relativePath);
624                 return code;
625             }
626         }
627     } else {
628         code = cm_GetSCache(&ioctlp->parentFid, NULL, &substRootp, userp, reqp);
629         if (code) {
630             osi_Log1(afsd_logp,"RDR_ParseIoctlPath [6] code 0x%x", code);
631             if (free_path)
632                 free(relativePath);
633             return code;
634         }
635
636         lastComponent = cm_ClientStrRChr(relativePath, '\\');
637         if (lastComponent && (lastComponent - relativePath) > 1 && wcslen(lastComponent) > 1) {
638             *lastComponent = '\0';
639             lastComponent++;
640
641             code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
642                              userp, NULL, reqp, &iscp);
643             if (code == 0)
644                 code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
645                                  userp, NULL, reqp, scpp);
646             if (iscp)
647                 cm_ReleaseSCache(iscp);
648         } else {
649             code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD | follow,
650                              userp, NULL, reqp, scpp);
651         }
652         if (code) {
653             cm_ReleaseSCache(substRootp);
654             osi_Log1(afsd_logp,"RDR_ParseIoctlPath [7] code 0x%x", code);
655             if (free_path)
656                 free(relativePath);
657             return code;
658         }
659     }
660
661     if (substRootp)
662         cm_ReleaseSCache(substRootp);
663
664     if (free_path)
665         free(relativePath);
666
667     /* Ensure that the status object is up to date */
668     lock_ObtainWrite(&(*scpp)->rw);
669     code = cm_SyncOp( *scpp, NULL, userp, reqp, 0,
670                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
671     if (code == 0)
672         cm_SyncOpDone( *scpp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
673     lock_ReleaseWrite(&(*scpp)->rw);
674
675     /* and return success */
676     osi_Log1(afsd_logp,"RDR_ParseIoctlPath [8] code 0x%x", code);
677     return 0;
678 }
679
680
681
682 #define LEAF_SIZE 256
683 /* parse the passed-in file name and do a namei on its parent.  If we fail,
684  * return an error code, otherwise return the vnode located in *scpp.
685  */
686 afs_int32
687 RDR_ParseIoctlParent(RDR_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
688                      cm_scache_t **scpp, wchar_t *leafp)
689 {
690     afs_int32 code;
691     clientchar_t tbuffer[1024];
692     clientchar_t *tp, *jp;
693     cm_scache_t *substRootp = NULL;
694     clientchar_t *inpathp;
695     char *inpathdatap;
696     int free_path = FALSE;
697
698     inpathdatap = ioctlp->ioctl.inDatap;
699
700     /* If the string starts with our UTF-8 prefix (which is the
701        sequence [ESC,'%','G'] as used by ISO-2022 to designate UTF-8
702        strings), we assume that the provided path is UTF-8.  Otherwise
703        we have to convert the string to UTF-8, since that is what we
704        want to use everywhere else.*/
705
706     if (memcmp(inpathdatap, utf8_prefix, utf8_prefix_size) == 0) {
707         /* String is UTF-8 */
708         inpathdatap += utf8_prefix_size;
709         ioctlp->ioctl.flags |= CM_IOCTLFLAG_USEUTF8;
710
711         inpathp = cm_Utf8ToClientStringAlloc(inpathdatap, -1, NULL);
712         osi_Log1(afsd_logp, "RDR_ParseIoctlParent UTF8 inpathp %S",
713                   osi_LogSaveStringW(afsd_logp, inpathp));
714     } else {
715         int cch;
716
717         /* Not a UTF-8 string */
718         /* TODO: If this is an OEM string, we should convert it to
719            UTF-8. */
720         if (smb_StoreAnsiFilenames) {
721             cch = cm_AnsiToClientString(inpathdatap, -1, NULL, 0);
722 #ifdef DEBUG
723             osi_assert(cch > 0);
724 #endif
725             inpathp = malloc(cch * sizeof(clientchar_t));
726             cm_AnsiToClientString(inpathdatap, -1, inpathp, cch);
727         } else {
728             TranslateExtendedChars(inpathdatap);
729
730             cch = cm_OemToClientString(inpathdatap, -1, NULL, 0);
731 #ifdef DEBUG
732             osi_assert(cch > 0);
733 #endif
734             inpathp = malloc(cch * sizeof(clientchar_t));
735             cm_OemToClientString(inpathdatap, -1, inpathp, cch);
736         }
737         osi_Log1(afsd_logp, "RDR_ParseIoctlParent ASCII inpathp %S",
738                  osi_LogSaveStringW(afsd_logp, inpathp));
739     }
740
741     cm_ClientStrCpy(tbuffer, lengthof(tbuffer), inpathp);
742     tp = cm_ClientStrRChr(tbuffer, '\\');
743     jp = cm_ClientStrRChr(tbuffer, '/');
744     if (!tp)
745         tp = jp;
746     else if (jp && (tp - tbuffer) < (jp - tbuffer))
747         tp = jp;
748     if (!tp) {
749         cm_ClientStrCpy(tbuffer, lengthof(tbuffer), _C("\\"));
750         if (leafp)
751             cm_ClientStrCpy(leafp, LEAF_SIZE, inpathp);
752     }
753     else {
754         *tp = 0;
755         if (leafp)
756             cm_ClientStrCpy(leafp, LEAF_SIZE, tp+1);
757     }
758
759     if (free_path)
760         free(inpathp);
761     inpathp = NULL;             /* We don't need this from this point on */
762
763     if (tbuffer[0] == tbuffer[1] &&
764         tbuffer[1] == '\\' &&
765         !cm_ClientStrCmpNI(RDR_UNCName,tbuffer+2, (int)wcslen(RDR_UNCName)))
766     {
767         wchar_t shareName[256];
768         wchar_t *sharePath;
769         int shareFound, i;
770
771         /* We may have found a UNC path.
772          * If the first component is the UNC Name,
773          * then throw out the second component (the submount)
774          * since it had better expand into the value of ioctl->tidPathp
775          */
776         clientchar_t * p;
777         p = tbuffer + 2 + cm_ClientStrLen(RDR_UNCName) + 1;
778         if ( !cm_ClientStrCmpNI(_C("all"), p, 3) )
779             p += 4;
780
781         for (i = 0; *p && *p != '\\'; i++,p++ ) {
782             shareName[i] = *p;
783         }
784         p++;                    /* skip past trailing slash */
785         shareName[i] = 0;       /* terminate string */
786
787         shareFound = smb_FindShare(NULL, NULL, shareName, &sharePath);
788         if ( shareFound ) {
789             /* we found a sharename, therefore use the resulting path */
790             code = cm_NameI(cm_RootSCachep(userp, reqp), sharePath,
791                              CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
792                              userp, NULL, reqp, &substRootp);
793             free(sharePath);
794             if (code) {
795                 osi_Log1(afsd_logp,"RDR_ParseIoctlParent [1] code 0x%x", code);
796                 return code;
797             }
798             code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
799                              userp, NULL, reqp, scpp);
800             cm_ReleaseSCache(substRootp);
801             if (code) {
802                 osi_Log1(afsd_logp,"RDR_ParseIoctlParent [2] code 0x%x", code);
803                 return code;
804             }
805         } else {
806             /* otherwise, treat the name as a cellname mounted off the afs root.
807              * This requires that we reconstruct the shareName string with
808              * leading and trailing slashes.
809              */
810             p = tbuffer + 2 + wcslen(RDR_UNCName) + 1;
811             if ( !cm_ClientStrCmpNI(_C("all"), p, 3) )
812                 p += 4;
813
814             shareName[0] = '/';
815             for (i = 1; *p && *p != '\\'; i++,p++ ) {
816                 shareName[i] = *p;
817             }
818             p++;                    /* skip past trailing slash */
819             shareName[i++] = '/';       /* add trailing slash */
820             shareName[i] = 0;       /* terminate string */
821
822             code = cm_NameI(cm_RootSCachep(userp, reqp), shareName,
823                              CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
824                              userp, NULL, reqp, &substRootp);
825             if (code) {
826                 osi_Log1(afsd_logp,"RDR_ParseIoctlParent [3] code 0x%x", code);
827                 return code;
828             }
829             code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
830                             userp, NULL, reqp, scpp);
831             cm_ReleaseSCache(substRootp);
832             if (code) {
833                 osi_Log1(afsd_logp,"RDR_ParseIoctlParent [4] code 0x%x", code);
834                 return code;
835             }
836         }
837     } else {
838         code = cm_GetSCache(&ioctlp->rootFid, NULL, &substRootp, userp, reqp);
839         if (code) {
840             osi_Log1(afsd_logp,"RDR_ParseIoctlParent [5] code 0x%x", code);
841             return code;
842         }
843         code = cm_NameI(substRootp, tbuffer, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
844                         userp, NULL, reqp, scpp);
845         cm_ReleaseSCache(substRootp);
846         if (code) {
847             osi_Log1(afsd_logp,"RDR_ParseIoctlParent [6] code 0x%x", code);
848             return code;
849         }
850     }
851
852     /* # of bytes of path */
853     code = (long)strlen(ioctlp->ioctl.inDatap) + 1;
854     ioctlp->ioctl.inDatap += code;
855
856     /* Ensure that the status object is up to date */
857     lock_ObtainWrite(&(*scpp)->rw);
858     code = cm_SyncOp( *scpp, NULL, userp, reqp, 0,
859                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
860     if (code == 0)
861         cm_SyncOpDone( *scpp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
862     lock_ReleaseWrite(&(*scpp)->rw);
863
864     /* and return success */
865     osi_Log1(afsd_logp,"RDR_ParseIoctlParent [7] code 0x%x", code);
866     return 0;
867 }
868
869 afs_int32
870 RDR_IoctlSetToken(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
871 {
872     char *saveDataPtr;
873     char *tp;
874     int ticketLen;
875     char *ticket;
876     int ctSize;
877     struct ClearToken ct;
878     cm_cell_t *cellp;
879     cm_ucell_t *ucellp;
880     afs_uuid_t uuid;
881     int flags;
882     char sessionKey[8];
883     wchar_t *smbname = NULL;
884     wchar_t *uname = NULL;
885     afs_uint32 code = 0;
886     int release_userp = 0;
887
888     saveDataPtr = ioctlp->ioctl.inDatap;
889
890     cm_SkipIoctlPath(&ioctlp->ioctl);
891
892     tp = ioctlp->ioctl.inDatap;
893
894     /* ticket length */
895     memcpy(&ticketLen, tp, sizeof(ticketLen));
896     tp += sizeof(ticketLen);
897     if (ticketLen < MINKTCTICKETLEN || ticketLen > MAXKTCTICKETLEN) {
898         code = CM_ERROR_INVAL;
899         goto done;
900     }
901
902     /* remember ticket and skip over it for now */
903     ticket = tp;
904     tp += ticketLen;
905
906     /* clear token size */
907     memcpy(&ctSize, tp, sizeof(ctSize));
908     tp += sizeof(ctSize);
909     if (ctSize != sizeof(struct ClearToken)) {
910         code = CM_ERROR_INVAL;
911         goto done;
912     }
913
914     /* clear token */
915     memcpy(&ct, tp, ctSize);
916     tp += ctSize;
917     if (ct.AuthHandle == -1)
918         ct.AuthHandle = 999;    /* more rxvab compat stuff */
919
920     /* more stuff, if any */
921     if (ioctlp->ioctl.inCopied > tp - saveDataPtr) {
922         /* flags:  logon flag */
923         memcpy(&flags, tp, sizeof(int));
924         tp += sizeof(int);
925
926         /* cell name */
927         cellp = cm_GetCell(tp, CM_FLAG_CREATE | CM_FLAG_NOPROBE);
928         if (!cellp) {
929             code = CM_ERROR_NOSUCHCELL;
930             goto done;
931         }
932         tp += strlen(tp) + 1;
933
934         /* user name */
935         uname = cm_ParseIoctlStringAlloc(&ioctlp->ioctl, tp);
936         tp += strlen(tp) + 1;
937
938         if (flags & PIOCTL_LOGON) {
939             /* SMB user name with which to associate tokens */
940             smbname = cm_ParseIoctlStringAlloc(&ioctlp->ioctl, tp);
941             tp += strlen(tp) + 1;
942             osi_Log2(afsd_logp,"RDR_IoctlSetToken for user [%S] smbname [%S]",
943                      osi_LogSaveStringW(afsd_logp,uname),
944                      osi_LogSaveStringW(afsd_logp,smbname));
945         } else {
946             osi_Log1(afsd_logp,"RDR_IoctlSetToken for user [%S]",
947                      osi_LogSaveStringW(afsd_logp, uname));
948         }
949
950         /* uuid */
951         memcpy(&uuid, tp, sizeof(uuid));
952         if (!cm_FindTokenEvent(uuid, sessionKey, NULL)) {
953             code = CM_ERROR_INVAL;
954             goto done;
955         }
956
957 #if defined(NO_AUTH_GROUPS)
958         /* after obtaining the session key check whether we can use it */
959         if (!(pflags & AFSCALL_FLAG_LOCAL_SYSTEM) && (flags & PIOCTL_LOGON)) {
960             code = CM_ERROR_NOACCESS;
961             goto done;
962         }
963 #endif
964     } else {
965         cellp = cm_data.rootCellp;
966         osi_Log0(afsd_logp,"cm_IoctlSetToken - no name specified");
967     }
968
969 #if defined(NO_AUTH_GROUPS)
970     if ((pflags & AFSCALL_FLAG_LOCAL_SYSTEM) && (flags & PIOCTL_LOGON)) {
971         PSID pSid = NULL;
972         DWORD dwSize1, dwSize2;
973         wchar_t *pszRefDomain = NULL;
974         SID_NAME_USE snu = SidTypeGroup;
975         clientchar_t * secSidString = NULL;
976         DWORD gle;
977         static wchar_t cname[MAX_COMPUTERNAME_LENGTH+1] = L"";
978
979         if ( cname[0] == '\0') {
980             int len = MAX_COMPUTERNAME_LENGTH+1;
981             GetComputerNameW(cname, &len);
982             _wcsupr(cname);
983         }
984
985         /*
986          * The input name is probably not a SID for the user which is how
987          * the user is now being identified as a result of the SMB
988          * extended authentication.  See if we can obtain the SID for the
989          * specified name.  If we can, use that instead of the name
990          * provided.
991          */
992
993         dwSize1 = dwSize2 = 0;
994         LookupAccountNameW( NULL /* System Name to begin Search */,
995                             smbname,
996                             NULL, &dwSize1,
997                             NULL, &dwSize2,
998                             &snu);
999         gle = GetLastError();
1000         if (gle == ERROR_INSUFFICIENT_BUFFER) {
1001             pSid = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, dwSize1);
1002             /*
1003              * Although dwSize2 is supposed to include the terminating
1004              * NUL character, on Win7 it does not.
1005              */
1006             pszRefDomain = malloc((dwSize2 + 1) * sizeof(wchar_t));
1007         }
1008
1009         if ( pSid && pszRefDomain ) {
1010             if (LookupAccountNameW( NULL /* System Name to begin Search */,
1011                                     smbname,
1012                                     pSid, &dwSize1,
1013                                     pszRefDomain, &dwSize2,
1014                                     &snu))
1015                 ConvertSidToStringSidW(pSid, &secSidString);
1016         }
1017
1018         if (secSidString) {
1019             userp = smb_FindCMUserBySID( secSidString, cname,
1020                                          SMB_FLAG_CREATE|SMB_FLAG_AFSLOGON);
1021             LocalFree(secSidString);
1022         } else {
1023             if (pSid) {
1024                 LocalFree(pSid);
1025                 pSid = NULL;
1026             }
1027
1028             if (!ConvertStringSidToSidW( smbname, &pSid)) {
1029                 userp = smb_FindCMUserBySID( smbname, cname,
1030                                              SMB_FLAG_CREATE|SMB_FLAG_AFSLOGON);
1031             } else {
1032                 userp = smb_FindCMUserByName( smbname, cname,
1033                                               SMB_FLAG_CREATE|SMB_FLAG_AFSLOGON);
1034             }
1035         }
1036
1037         if (pSid)
1038             LocalFree(pSid);
1039         if (pszRefDomain)
1040             free(pszRefDomain);
1041
1042         release_userp = 1;
1043     }
1044 #endif
1045
1046     /* store the token */
1047     lock_ObtainMutex(&userp->mx);
1048     ucellp = cm_GetUCell(userp, cellp);
1049     osi_Log1(afsd_logp,"cm_IoctlSetToken ucellp %lx", ucellp);
1050     ucellp->ticketLen = ticketLen;
1051     if (ucellp->ticketp)
1052         free(ucellp->ticketp);  /* Discard old token if any */
1053     ucellp->ticketp = malloc(ticketLen);
1054     memcpy(ucellp->ticketp, ticket, ticketLen);
1055     /*
1056      * Get the session key from the RPC, rather than from the pioctl.
1057      */
1058     /*
1059     memcpy(&ucellp->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
1060     */
1061     memcpy(ucellp->sessionKey.data, sessionKey, sizeof(sessionKey));
1062     ucellp->kvno = ct.AuthHandle;
1063     ucellp->expirationTime = ct.EndTimestamp;
1064     ucellp->gen++;
1065 #ifdef QUERY_AFSID
1066     ucellp->uid = ANONYMOUSID;
1067 #endif
1068     if (uname) {
1069         cm_ClientStringToFsString(uname, -1, ucellp->userName, MAXKTCNAMELEN);
1070 #ifdef QUERY_AFSID
1071         cm_UsernameToId(uname, ucellp, &ucellp->uid);
1072 #endif
1073     }
1074     ucellp->flags |= CM_UCELLFLAG_RXKAD;
1075     lock_ReleaseMutex(&userp->mx);
1076
1077     if ((pflags & AFSCALL_FLAG_LOCAL_SYSTEM) && (flags & PIOCTL_LOGON)) {
1078         ioctlp->ioctl.flags |= CM_IOCTLFLAG_LOGON;
1079     }
1080
1081     cm_ResetACLCache(cellp, userp);
1082
1083   done:
1084     SecureZeroMemory(sessionKey, sizeof(sessionKey));
1085
1086     if (release_userp)
1087         cm_ReleaseUser(userp);
1088
1089     if (uname)
1090         free(uname);
1091
1092     if (smbname)
1093         free(smbname);
1094
1095     return code;
1096 }
1097
1098 afs_int32
1099 RDR_IoctlGetACL(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags)
1100 {
1101     cm_scache_t *scp;
1102     afs_int32 code;
1103     cm_req_t req;
1104     cm_ioctlQueryOptions_t *optionsp;
1105     afs_uint32 flags = 0;
1106
1107     cm_InitReq(&req);
1108
1109     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1110     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1111         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1112
1113     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1114         cm_fid_t fid;
1115         cm_SkipIoctlPath(&ioctlp->ioctl);
1116         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
1117                   optionsp->fid.vnode, optionsp->fid.unique);
1118         code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
1119     } else {
1120         code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1121     }
1122     if (code)
1123         return code;
1124
1125     code = cm_IoctlGetACL(&ioctlp->ioctl, userp, scp, &req);
1126
1127     cm_ReleaseSCache(scp);
1128     return code;
1129 }
1130
1131 afs_int32
1132 RDR_IoctlSetACL(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags)
1133 {
1134     cm_scache_t *scp;
1135     afs_int32 code;
1136     cm_req_t req;
1137
1138     afs_uint32 flags = 0;
1139
1140     cm_InitReq(&req);
1141
1142     code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1143     if (code)
1144         return code;
1145
1146     code = cm_IoctlSetACL(&ioctlp->ioctl, userp, scp, &req);
1147
1148     cm_ReleaseSCache(scp);
1149     return code;
1150 }
1151
1152 afs_int32
1153 RDR_IoctlGetFileCellName(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1154 {
1155     afs_int32 code;
1156     cm_scache_t *scp;
1157     cm_req_t req;
1158     cm_ioctlQueryOptions_t *optionsp;
1159     afs_uint32 flags = 0;
1160
1161     cm_InitReq(&req);
1162
1163     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1164     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1165         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1166
1167     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1168         cm_fid_t fid;
1169         cm_SkipIoctlPath(&ioctlp->ioctl);
1170         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
1171                   optionsp->fid.vnode, optionsp->fid.unique);
1172         code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
1173     } else {
1174         code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1175     }
1176     if (code)
1177         return code;
1178
1179     code = cm_IoctlGetFileCellName(&ioctlp->ioctl, userp, scp, &req);
1180
1181     cm_ReleaseSCache(scp);
1182
1183     return code;
1184 }
1185
1186 afs_int32
1187 RDR_IoctlFlushAllVolumes(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1188 {
1189     cm_req_t req;
1190
1191     cm_InitReq(&req);
1192
1193     cm_SkipIoctlPath(&ioctlp->ioctl);   /* we don't care about the path */
1194
1195     return cm_IoctlFlushAllVolumes(&ioctlp->ioctl, userp, &req);
1196 }
1197
1198 afs_int32
1199 RDR_IoctlFlushVolume(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1200 {
1201     afs_int32 code;
1202     cm_scache_t *scp;
1203     cm_req_t req;
1204     cm_ioctlQueryOptions_t *optionsp;
1205     afs_uint32 flags = 0;
1206
1207     cm_InitReq(&req);
1208
1209     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1210     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1211         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1212
1213     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1214         cm_fid_t fid;
1215         cm_SkipIoctlPath(&ioctlp->ioctl);
1216         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
1217                   optionsp->fid.vnode, optionsp->fid.unique);
1218         code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
1219     } else {
1220         code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1221     }
1222     if (code)
1223         return code;
1224
1225     code = cm_IoctlFlushVolume(&ioctlp->ioctl, userp, scp, &req);
1226
1227     cm_ReleaseSCache(scp);
1228
1229     return code;
1230 }
1231
1232 afs_int32
1233 RDR_IoctlFlushFile(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1234 {
1235     afs_int32 code;
1236     cm_scache_t *scp;
1237     cm_req_t req;
1238     cm_ioctlQueryOptions_t *optionsp;
1239     afs_uint32 flags = 0;
1240
1241     cm_InitReq(&req);
1242
1243     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1244     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1245         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1246
1247     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1248         cm_fid_t fid;
1249         cm_SkipIoctlPath(&ioctlp->ioctl);
1250         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
1251                   optionsp->fid.vnode, optionsp->fid.unique);
1252         code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
1253     } else {
1254         code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1255     }
1256     if (code)
1257         return code;
1258
1259     code = cm_IoctlFlushFile(&ioctlp->ioctl, userp, scp, &req);
1260
1261     cm_ReleaseSCache(scp);
1262     return code;
1263 }
1264
1265 afs_int32
1266 RDR_IoctlSetVolumeStatus(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1267 {
1268     afs_int32 code;
1269     cm_scache_t *scp;
1270     cm_req_t req;
1271
1272     cm_InitReq(&req);
1273
1274     code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, 0);
1275     if (code) return code;
1276
1277     code = cm_IoctlSetVolumeStatus(&ioctlp->ioctl, userp, scp, &req);
1278     cm_ReleaseSCache(scp);
1279
1280     return code;
1281 }
1282
1283 afs_int32
1284 RDR_IoctlGetVolumeStatus(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1285 {
1286     afs_int32 code;
1287     cm_scache_t *scp;
1288     cm_ioctlQueryOptions_t *optionsp;
1289     afs_uint32 flags = 0;
1290     cm_req_t req;
1291
1292     cm_InitReq(&req);
1293
1294     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1295     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1296         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1297
1298     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1299         cm_fid_t fid;
1300         cm_SkipIoctlPath(&ioctlp->ioctl);
1301         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
1302                   optionsp->fid.vnode, optionsp->fid.unique);
1303         code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
1304     } else {
1305         code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1306     }
1307     if (code)
1308         return code;
1309
1310     code = cm_IoctlGetVolumeStatus(&ioctlp->ioctl, userp, scp, &req);
1311
1312     cm_ReleaseSCache(scp);
1313
1314     return code;
1315 }
1316
1317 afs_int32
1318 RDR_IoctlGetFid(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1319 {
1320     afs_int32 code;
1321     cm_scache_t *scp;
1322     cm_req_t req;
1323     cm_ioctlQueryOptions_t * optionsp;
1324     afs_uint32 flags = 0;
1325
1326     cm_InitReq(&req);
1327
1328     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1329     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1330         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1331
1332     code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1333     if (code)
1334         return code;
1335
1336     code = cm_IoctlGetFid(&ioctlp->ioctl, userp, scp, &req);
1337
1338     cm_ReleaseSCache(scp);
1339
1340     return code;
1341 }
1342
1343 afs_int32
1344 RDR_IoctlGetFileType(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1345 {
1346     afs_int32 code;
1347     cm_scache_t *scp;
1348     cm_req_t req;
1349     cm_ioctlQueryOptions_t * optionsp;
1350     afs_uint32 flags = 0;
1351
1352     cm_InitReq(&req);
1353
1354     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1355     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1356         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1357
1358     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1359         cm_fid_t fid;
1360         cm_SkipIoctlPath(&ioctlp->ioctl);
1361         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
1362                   optionsp->fid.vnode, optionsp->fid.unique);
1363         code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
1364     } else {
1365         code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1366     }
1367     if (code)
1368         return code;
1369
1370     code = cm_IoctlGetFileType(&ioctlp->ioctl, userp, scp, &req);
1371
1372     cm_ReleaseSCache(scp);
1373
1374     return code;
1375 }
1376
1377 afs_int32
1378 RDR_IoctlGetOwner(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1379 {
1380     afs_int32 code;
1381     cm_scache_t *scp;
1382     cm_req_t req;
1383     cm_ioctlQueryOptions_t *optionsp;
1384     afs_uint32 flags = 0;
1385
1386     cm_InitReq(&req);
1387
1388     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1389     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1390         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1391
1392     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1393         cm_fid_t fid;
1394         cm_SkipIoctlPath(&ioctlp->ioctl);
1395         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
1396                   optionsp->fid.vnode, optionsp->fid.unique);
1397         code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
1398     } else {
1399         code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1400     }
1401     if (code)
1402         return code;
1403
1404     code = cm_IoctlGetOwner(&ioctlp->ioctl, userp, scp, &req);
1405
1406     cm_ReleaseSCache(scp);
1407
1408     return code;
1409 }
1410
1411 afs_int32
1412 RDR_IoctlWhereIs(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1413 {
1414     afs_int32 code;
1415     cm_scache_t *scp;
1416     cm_req_t req;
1417     cm_ioctlQueryOptions_t *optionsp;
1418     afs_uint32 flags = 0;
1419
1420     cm_InitReq(&req);
1421
1422     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1423     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1424         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1425
1426     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1427         cm_fid_t fid;
1428         cm_SkipIoctlPath(&ioctlp->ioctl);
1429         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
1430                   optionsp->fid.vnode, optionsp->fid.unique);
1431         code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
1432     } else {
1433         code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1434     }
1435     if (code)
1436         return code;
1437
1438     code = cm_IoctlWhereIs(&ioctlp->ioctl, userp, scp, &req);
1439
1440     cm_ReleaseSCache(scp);
1441
1442     return code;
1443 }
1444
1445
1446 afs_int32
1447 RDR_IoctlStatMountPoint(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1448 {
1449     afs_int32 code;
1450     cm_scache_t *dscp;
1451     cm_req_t req;
1452
1453     cm_InitReq(&req);
1454
1455     code = RDR_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
1456     if (code)
1457         return code;
1458
1459     code = cm_IoctlStatMountPoint(&ioctlp->ioctl, userp, dscp, &req);
1460
1461     cm_ReleaseSCache(dscp);
1462
1463     return code;
1464 }
1465
1466 afs_int32
1467 RDR_IoctlDeleteMountPoint(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1468 {
1469     afs_int32 code;
1470     cm_scache_t *dscp;
1471     cm_req_t req;
1472
1473     cm_InitReq(&req);
1474
1475     code = RDR_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
1476     if (code)
1477         return code;
1478
1479     code = cm_IoctlDeleteMountPoint(&ioctlp->ioctl, userp, dscp, &req);
1480
1481     cm_ReleaseSCache(dscp);
1482
1483     return code;
1484 }
1485
1486 afs_int32
1487 RDR_IoctlCheckServers(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1488 {
1489     cm_SkipIoctlPath(&ioctlp->ioctl);   /* we don't care about the path */
1490
1491     return cm_IoctlCheckServers(&ioctlp->ioctl, userp);
1492 }
1493
1494 afs_int32
1495 RDR_IoctlGag(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1496 {
1497     /* we don't print anything superfluous, so we don't support the gag call */
1498     return CM_ERROR_INVAL;
1499 }
1500
1501 afs_int32
1502 RDR_IoctlCheckVolumes(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1503 {
1504     cm_SkipIoctlPath(&ioctlp->ioctl);
1505
1506     return cm_IoctlCheckVolumes(&ioctlp->ioctl, userp);
1507 }
1508
1509 afs_int32 RDR_IoctlSetCacheSize(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1510 {
1511     cm_SkipIoctlPath(&ioctlp->ioctl);
1512
1513     return cm_IoctlSetCacheSize(&ioctlp->ioctl, userp);
1514 }
1515
1516
1517 afs_int32
1518 RDR_IoctlTraceControl(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1519 {
1520     cm_SkipIoctlPath(&ioctlp->ioctl);
1521
1522     return cm_IoctlTraceControl(&ioctlp->ioctl, userp);
1523 }
1524
1525 afs_int32
1526 RDR_IoctlGetCacheParms(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1527 {
1528     cm_SkipIoctlPath(&ioctlp->ioctl);
1529
1530     return cm_IoctlGetCacheParms(&ioctlp->ioctl, userp);
1531 }
1532
1533 afs_int32
1534 RDR_IoctlGetCell(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1535 {
1536     cm_SkipIoctlPath(&ioctlp->ioctl);
1537
1538     return cm_IoctlGetCell(&ioctlp->ioctl, userp);
1539 }
1540
1541 afs_int32
1542 RDR_IoctlNewCell(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1543 {
1544     cm_SkipIoctlPath(&ioctlp->ioctl);
1545
1546     return cm_IoctlNewCell(&ioctlp->ioctl, userp);
1547 }
1548
1549 afs_int32
1550 RDR_IoctlNewCell2(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1551 {
1552     cm_SkipIoctlPath(&ioctlp->ioctl);
1553
1554     return cm_IoctlNewCell2(&ioctlp->ioctl, userp);
1555 }
1556
1557 afs_int32
1558 RDR_IoctlGetWsCell(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags)
1559 {
1560     cm_SkipIoctlPath(&ioctlp->ioctl);
1561
1562     return cm_IoctlGetWsCell(&ioctlp->ioctl, userp);
1563 }
1564
1565 afs_int32
1566 RDR_IoctlSysName(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1567 {
1568     cm_SkipIoctlPath(&ioctlp->ioctl);
1569
1570     return cm_IoctlSysName(&ioctlp->ioctl, userp);
1571 }
1572
1573 afs_int32
1574 RDR_IoctlGetCellStatus(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1575 {
1576     cm_SkipIoctlPath(&ioctlp->ioctl);
1577
1578     return cm_IoctlGetCellStatus(&ioctlp->ioctl, userp);
1579 }
1580
1581 afs_int32
1582 RDR_IoctlSetCellStatus(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1583 {
1584     cm_SkipIoctlPath(&ioctlp->ioctl);
1585
1586     return cm_IoctlSetCellStatus(&ioctlp->ioctl, userp);
1587 }
1588
1589 afs_int32
1590 RDR_IoctlSetSPrefs(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1591 {
1592     cm_SkipIoctlPath(&ioctlp->ioctl);
1593
1594     return cm_IoctlSetSPrefs(&ioctlp->ioctl, userp);
1595 }
1596
1597 afs_int32
1598 RDR_IoctlGetSPrefs(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1599 {
1600     cm_SkipIoctlPath(&ioctlp->ioctl);
1601
1602     return cm_IoctlGetSPrefs(&ioctlp->ioctl, userp);
1603 }
1604
1605 afs_int32
1606 RDR_IoctlStoreBehind(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1607 {
1608     /* we ignore default asynchrony since we only have one way
1609      * of doing this today.
1610      */
1611     return 0;
1612 }
1613
1614 afs_int32
1615 RDR_IoctlCreateMountPoint(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1616 {
1617     afs_int32 code;
1618     cm_scache_t *dscp;
1619     wchar_t leaf[LEAF_SIZE];
1620     cm_req_t req;
1621
1622     cm_InitReq(&req);
1623
1624     code = RDR_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
1625     if (code)
1626         return code;
1627
1628     code = cm_IoctlCreateMountPoint(&ioctlp->ioctl, userp, dscp, &req, leaf);
1629
1630     cm_ReleaseSCache(dscp);
1631     return code;
1632 }
1633
1634 afs_int32
1635 RDR_IoctlSymlink(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1636 {
1637     afs_int32 code;
1638     cm_scache_t *dscp;
1639     wchar_t leaf[LEAF_SIZE];
1640     cm_req_t req;
1641
1642     cm_InitReq(&req);
1643
1644     code = RDR_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
1645     if (code) return code;
1646
1647     code = cm_IoctlSymlink(&ioctlp->ioctl, userp, dscp, &req, leaf);
1648
1649     cm_ReleaseSCache(dscp);
1650
1651     return code;
1652 }
1653
1654 afs_int32
1655 RDR_IoctlListlink(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1656 {
1657     afs_int32 code;
1658     cm_scache_t *dscp;
1659     cm_req_t req;
1660
1661     cm_InitReq(&req);
1662
1663     code = RDR_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
1664     if (code) return code;
1665
1666     code = cm_IoctlListlink(&ioctlp->ioctl, userp, dscp, &req);
1667
1668     cm_ReleaseSCache(dscp);
1669     return code;
1670 }
1671
1672 afs_int32
1673 RDR_IoctlIslink(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1674 {/*CHECK FOR VALID SYMLINK*/
1675     afs_int32 code;
1676     cm_scache_t *dscp;
1677     cm_req_t req;
1678
1679     cm_InitReq(&req);
1680
1681     code = RDR_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
1682     if (code) return code;
1683
1684     code = cm_IoctlIslink(&ioctlp->ioctl, userp, dscp, &req);
1685
1686     cm_ReleaseSCache(dscp);
1687
1688     return code;
1689 }
1690
1691 afs_int32
1692 RDR_IoctlDeletelink(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1693 {
1694     afs_int32 code;
1695     cm_scache_t *dscp;
1696     cm_req_t req;
1697
1698     cm_InitReq(&req);
1699
1700     code = RDR_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
1701     if (code) return code;
1702
1703     code = cm_IoctlDeletelink(&ioctlp->ioctl, userp, dscp, &req);
1704
1705     cm_ReleaseSCache(dscp);
1706
1707     return code;
1708 }
1709
1710 afs_int32
1711 RDR_IoctlGetTokenIter(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1712 {
1713     cm_SkipIoctlPath(&ioctlp->ioctl);
1714
1715     return cm_IoctlGetTokenIter(&ioctlp->ioctl, userp);
1716 }
1717
1718 afs_int32
1719 RDR_IoctlGetToken(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1720 {
1721     cm_SkipIoctlPath(&ioctlp->ioctl);
1722
1723     return cm_IoctlGetToken(&ioctlp->ioctl, userp);
1724 }
1725
1726
1727 afs_int32
1728 RDR_IoctlDelToken(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1729 {
1730     cm_SkipIoctlPath(&ioctlp->ioctl);
1731
1732     return cm_IoctlDelToken(&ioctlp->ioctl, userp);
1733 }
1734
1735
1736 afs_int32
1737 RDR_IoctlDelAllToken(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1738 {
1739     cm_SkipIoctlPath(&ioctlp->ioctl);
1740
1741     return cm_IoctlDelAllToken(&ioctlp->ioctl, userp);
1742 }
1743
1744
1745 afs_int32
1746 RDR_IoctlMakeSubmount(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1747 {
1748     cm_SkipIoctlPath(&ioctlp->ioctl);
1749
1750     return cm_IoctlMakeSubmount(&ioctlp->ioctl, userp);
1751 }
1752
1753 afs_int32
1754 RDR_IoctlGetRxkcrypt(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1755 {
1756     cm_SkipIoctlPath(&ioctlp->ioctl);
1757
1758     return cm_IoctlGetRxkcrypt(&ioctlp->ioctl, userp);
1759 }
1760
1761 afs_int32
1762 RDR_IoctlSetRxkcrypt(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1763 {
1764     cm_SkipIoctlPath(&ioctlp->ioctl);
1765
1766     return cm_IoctlSetRxkcrypt(&ioctlp->ioctl, userp);
1767 }
1768
1769 afs_int32
1770 RDR_IoctlRxStatProcess(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1771 {
1772     cm_SkipIoctlPath(&ioctlp->ioctl);
1773
1774     return cm_IoctlRxStatProcess(&ioctlp->ioctl, userp);
1775 }
1776
1777
1778 afs_int32
1779 RDR_IoctlRxStatPeer(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1780 {
1781     cm_SkipIoctlPath(&ioctlp->ioctl);
1782
1783     return cm_IoctlRxStatPeer(&ioctlp->ioctl, userp);
1784 }
1785
1786 afs_int32
1787 RDR_IoctlUnicodeControl(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1788 {
1789     cm_SkipIoctlPath(&ioctlp->ioctl);
1790
1791     return cm_IoctlUnicodeControl(&ioctlp->ioctl, userp);
1792 }
1793
1794 afs_int32
1795 RDR_IoctlUUIDControl(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1796 {
1797     cm_SkipIoctlPath(&ioctlp->ioctl);
1798
1799     return cm_IoctlUUIDControl(&ioctlp->ioctl, userp);
1800 }
1801
1802
1803 afs_int32
1804 RDR_IoctlMemoryDump(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1805 {
1806     cm_SkipIoctlPath(&ioctlp->ioctl);
1807
1808     return cm_IoctlMemoryDump(&ioctlp->ioctl, userp);
1809 }
1810
1811 afs_int32
1812 RDR_IoctlPathAvailability(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1813 {
1814     afs_int32 code;
1815     cm_scache_t *scp;
1816     cm_req_t req;
1817     cm_ioctlQueryOptions_t *optionsp;
1818     afs_uint32 flags = 0;
1819
1820     cm_InitReq(&req);
1821
1822     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1823     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1824         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1825
1826     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1827         cm_fid_t fid;
1828         cm_SkipIoctlPath(&ioctlp->ioctl);
1829         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
1830                   optionsp->fid.vnode, optionsp->fid.unique);
1831         code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
1832     } else {
1833         code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1834     }
1835     if (code)
1836         return code;
1837
1838     code = cm_IoctlPathAvailability(&ioctlp->ioctl, userp, scp, &req);
1839     cm_ReleaseSCache(scp);
1840     return code;
1841 }
1842
1843 afs_int32
1844 RDR_IoctlVolStatTest(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1845 {
1846     cm_req_t req;
1847
1848     cm_InitReq(&req);
1849
1850     cm_SkipIoctlPath(&ioctlp->ioctl);
1851
1852     return cm_IoctlVolStatTest(&ioctlp->ioctl, userp, &req);
1853 }
1854
1855 /*
1856  * VIOC_SETOWNER
1857  *
1858  * This pioctl requires the use of the cm_ioctlQueryOptions_t structure.
1859  *
1860  */
1861 afs_int32
1862 RDR_IoctlSetOwner(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1863 {
1864     afs_int32 code;
1865     cm_scache_t *scp;
1866     cm_req_t req;
1867     cm_ioctlQueryOptions_t *optionsp;
1868     afs_uint32 flags = 0;
1869
1870     smb_InitReq(&req);
1871
1872     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1873     if (optionsp) {
1874         if (CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1875             flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1876
1877         if (CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1878             cm_fid_t fid;
1879             cm_SkipIoctlPath(&ioctlp->ioctl);
1880             cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
1881                        optionsp->fid.vnode, optionsp->fid.unique);
1882             code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
1883         } else {
1884             code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1885         }
1886         if (code)
1887             return code;
1888
1889         cm_IoctlSkipQueryOptions(&ioctlp->ioctl, userp);
1890     }
1891
1892     code = cm_IoctlSetOwner(&ioctlp->ioctl, userp, scp, &req);
1893
1894     cm_ReleaseSCache(scp);
1895
1896     return code;
1897 }
1898
1899 /*
1900  * VIOC_SETGROUP
1901  *
1902  * This pioctl requires the use of the cm_ioctlQueryOptions_t structure.
1903  *
1904  */
1905 afs_int32
1906 RDR_IoctlSetGroup(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1907 {
1908     afs_int32 code;
1909     cm_scache_t *scp;
1910     cm_req_t req;
1911     cm_ioctlQueryOptions_t *optionsp;
1912     afs_uint32 flags = 0;
1913
1914     smb_InitReq(&req);
1915
1916     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1917     if (optionsp) {
1918         if (CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1919             flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1920
1921         if (CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1922             cm_fid_t fid;
1923             cm_SkipIoctlPath(&ioctlp->ioctl);
1924             cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
1925                        optionsp->fid.vnode, optionsp->fid.unique);
1926             code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
1927         } else {
1928             code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1929         }
1930         if (code)
1931             return code;
1932
1933         cm_IoctlSkipQueryOptions(&ioctlp->ioctl, userp);
1934     }
1935
1936     code = cm_IoctlSetGroup(&ioctlp->ioctl, userp, scp, &req);
1937
1938     cm_ReleaseSCache(scp);
1939
1940     return code;
1941 }
1942
1943 afs_int32
1944 RDR_IoctlGetUnixMode(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1945 {
1946     afs_int32 code;
1947     cm_scache_t *scp;
1948     cm_req_t req;
1949     cm_ioctlQueryOptions_t *optionsp;
1950     afs_uint32 flags = 0;
1951
1952     cm_InitReq(&req);
1953
1954     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1955     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1956         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1957
1958     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1959         cm_fid_t fid;
1960         cm_SkipIoctlPath(&ioctlp->ioctl);
1961         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
1962                   optionsp->fid.vnode, optionsp->fid.unique);
1963         code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
1964     } else {
1965         code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1966     }
1967     if (code)
1968         return code;
1969
1970     code = cm_IoctlGetUnixMode(&ioctlp->ioctl, userp, scp, &req);
1971
1972     cm_ReleaseSCache(scp);
1973
1974     return code;
1975 }
1976
1977 /*
1978  * VIOC_SETUNIXMODE
1979  *
1980  * This pioctl requires the use of the cm_ioctlQueryOptions_t structure.
1981  *
1982  */
1983 afs_int32
1984 RDR_IoctlSetUnixMode(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1985 {
1986     afs_int32 code;
1987     cm_scache_t *scp;
1988     cm_req_t req;
1989     cm_ioctlQueryOptions_t *optionsp;
1990     afs_uint32 flags = 0;
1991
1992     smb_InitReq(&req);
1993
1994     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1995     if (optionsp) {
1996         if (CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1997             flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1998
1999         if (CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
2000             cm_fid_t fid;
2001             cm_SkipIoctlPath(&ioctlp->ioctl);
2002             cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
2003                        optionsp->fid.vnode, optionsp->fid.unique);
2004             code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
2005         } else {
2006             code = RDR_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
2007         }
2008         if (code)
2009             return code;
2010
2011         cm_IoctlSkipQueryOptions(&ioctlp->ioctl, userp);
2012     }
2013
2014     code = cm_IoctlSetUnixMode(&ioctlp->ioctl, userp, scp, &req);
2015
2016     cm_ReleaseSCache(scp);
2017
2018     return code;
2019 }
2020
2021 afs_int32
2022 RDR_IoctlGetVerifyData(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
2023 {
2024     cm_SkipIoctlPath(&ioctlp->ioctl);
2025
2026     return cm_IoctlGetVerifyData(&ioctlp->ioctl);
2027 }
2028
2029 afs_int32
2030 RDR_IoctlSetVerifyData(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
2031 {
2032     cm_SkipIoctlPath(&ioctlp->ioctl);
2033
2034     return cm_IoctlSetVerifyData(&ioctlp->ioctl);
2035 }