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