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