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