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