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