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