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