9f38eb88f9953ed02e43ad745b75cbe283866447
[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 (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
1055         if (!(pflags & AFSCALL_FLAG_LOCAL_SYSTEM) && (flags & PIOCTL_LOGON)) {
1056             code = CM_ERROR_NOACCESS;
1057             goto done;
1058         }
1059     } else {
1060         cellp = cm_data.rootCellp;
1061         osi_Log0(smb_logp,"cm_IoctlSetToken - no name specified");
1062     }
1063
1064     if ((pflags & AFSCALL_FLAG_LOCAL_SYSTEM) && (flags & PIOCTL_LOGON)) {
1065         userp = smb_FindCMUserByName(smbname, ioctlp->fidp->vcp->rname,
1066                                      SMB_FLAG_CREATE|SMB_FLAG_AFSLOGON);
1067         release_userp = 1;
1068     }
1069
1070     /* store the token */
1071     lock_ObtainMutex(&userp->mx);
1072     ucellp = cm_GetUCell(userp, cellp);
1073     osi_Log1(smb_logp,"cm_IoctlSetToken ucellp %lx", ucellp);
1074     ucellp->ticketLen = ticketLen;
1075     if (ucellp->ticketp)
1076         free(ucellp->ticketp);  /* Discard old token if any */
1077     ucellp->ticketp = malloc(ticketLen);
1078     memcpy(ucellp->ticketp, ticket, ticketLen);
1079     /*
1080      * Get the session key from the RPC, rather than from the pioctl.
1081      */
1082     /*
1083     memcpy(&ucellp->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
1084     */
1085     memcpy(ucellp->sessionKey.data, sessionKey, sizeof(sessionKey));
1086     ucellp->kvno = ct.AuthHandle;
1087     ucellp->expirationTime = ct.EndTimestamp;
1088     ucellp->gen++;
1089 #ifdef QUERY_AFSID
1090     ucellp->uid = ANONYMOUSID;
1091 #endif
1092     if (uname) {
1093         cm_ClientStringToFsString(uname, -1, ucellp->userName, MAXKTCNAMELEN);
1094 #ifdef QUERY_AFSID
1095         cm_UsernameToId(uname, ucellp, &ucellp->uid);
1096 #endif
1097     }
1098     ucellp->flags |= CM_UCELLFLAG_RXKAD;
1099     lock_ReleaseMutex(&userp->mx);
1100
1101     if ((pflags & AFSCALL_FLAG_LOCAL_SYSTEM) && (flags & PIOCTL_LOGON)) {
1102         ioctlp->ioctl.flags |= CM_IOCTLFLAG_LOGON;
1103     }
1104
1105     cm_ResetACLCache(cellp, userp);
1106
1107   done:
1108     SecureZeroMemory(sessionKey, sizeof(sessionKey));
1109
1110     if (release_userp)
1111         cm_ReleaseUser(userp);
1112
1113     if (uname)
1114         free(uname);
1115
1116     if (smbname)
1117         free(smbname);
1118
1119     return code;
1120 }
1121
1122
1123
1124 afs_int32
1125 smb_IoctlGetSMBName(smb_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags)
1126 {
1127     smb_user_t *uidp = ioctlp->uidp;
1128
1129     if (uidp && uidp->unp) {
1130         int cch;
1131
1132         cch = cm_ClientStringToUtf8(uidp->unp->name,
1133                                     -1,
1134                                     ioctlp->ioctl.outDatap,
1135                                     (SMB_IOCTL_MAXDATA -
1136                                      (ioctlp->ioctl.outDatap - ioctlp->ioctl.outAllocp))
1137                                     / sizeof(cm_utf8char_t));
1138
1139         ioctlp->ioctl.outDatap += cch * sizeof(cm_utf8char_t);
1140     }
1141
1142     return 0;
1143 }
1144
1145 afs_int32 
1146 smb_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags)
1147 {
1148     cm_scache_t *scp;
1149     afs_int32 code;
1150     cm_req_t req;
1151     cm_ioctlQueryOptions_t *optionsp;
1152     afs_uint32 flags = 0;
1153
1154     smb_InitReq(&req);
1155
1156     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1157     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1158         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1159
1160     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1161         cm_fid_t fid;
1162         cm_SkipIoctlPath(&ioctlp->ioctl);
1163         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
1164                   optionsp->fid.vnode, optionsp->fid.unique);
1165         code = cm_GetSCache(&fid, &scp, userp, &req);
1166     } else {
1167         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1168     }
1169
1170     if (code) 
1171         return code;
1172
1173     code = cm_IoctlGetACL(&ioctlp->ioctl, userp, scp, &req);
1174
1175     cm_ReleaseSCache(scp);
1176     return code;
1177 }
1178
1179 afs_int32 
1180 smb_IoctlSetACL(smb_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags)
1181 {
1182     cm_scache_t *scp;
1183     afs_int32 code;
1184     cm_req_t req;
1185     afs_uint32 flags = 0;
1186
1187     smb_InitReq(&req);
1188
1189     code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1190     if (code) 
1191         return code;
1192
1193     code = cm_IoctlSetACL(&ioctlp->ioctl, userp, scp, &req);
1194
1195     cm_ReleaseSCache(scp);
1196     return code;
1197 }
1198
1199 afs_int32
1200 smb_IoctlGetFileCellName(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1201 {
1202     afs_int32 code;
1203     cm_scache_t *scp;
1204     cm_req_t req;
1205     cm_ioctlQueryOptions_t *optionsp;
1206     afs_uint32 flags = 0;
1207
1208     smb_InitReq(&req);
1209
1210     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1211     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1212         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1213
1214     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1215         cm_fid_t fid;
1216         cm_SkipIoctlPath(&ioctlp->ioctl);
1217         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
1218                   optionsp->fid.vnode, optionsp->fid.unique);
1219         code = cm_GetSCache(&fid, &scp, userp, &req);
1220     } else {
1221         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1222     }
1223     if (code) 
1224         return code;
1225
1226     code = cm_IoctlGetFileCellName(&ioctlp->ioctl, userp, scp, &req);
1227
1228     cm_ReleaseSCache(scp);
1229
1230     return code;
1231 }
1232
1233 afs_int32 
1234 smb_IoctlFlushAllVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1235 {
1236     cm_req_t req;
1237
1238     smb_InitReq(&req);
1239
1240     cm_SkipIoctlPath(&ioctlp->ioctl);   /* we don't care about the path */
1241
1242     return cm_IoctlFlushAllVolumes(&ioctlp->ioctl, userp, &req);
1243 }
1244
1245 afs_int32 
1246 smb_IoctlFlushVolume(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1247 {
1248     afs_int32 code;
1249     cm_scache_t *scp;
1250     cm_req_t req;
1251     cm_ioctlQueryOptions_t *optionsp;
1252     afs_uint32 flags = 0;
1253
1254     smb_InitReq(&req);
1255
1256     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1257     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1258         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1259
1260     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1261         cm_fid_t fid;
1262         cm_SkipIoctlPath(&ioctlp->ioctl);
1263         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
1264                   optionsp->fid.vnode, optionsp->fid.unique);
1265         code = cm_GetSCache(&fid, &scp, userp, &req);
1266     } else {
1267         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1268     }
1269     if (code) 
1270         return code;
1271
1272     code = cm_IoctlFlushVolume(&ioctlp->ioctl, userp, scp, &req);
1273
1274     cm_ReleaseSCache(scp);
1275
1276     return code;
1277 }
1278
1279 afs_int32 
1280 smb_IoctlFlushFile(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1281 {
1282     afs_int32 code;
1283     cm_scache_t *scp;
1284     cm_req_t req;
1285     cm_ioctlQueryOptions_t *optionsp;
1286     afs_uint32 flags = 0;
1287
1288     smb_InitReq(&req);
1289
1290     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1291     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1292         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1293
1294     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1295         cm_fid_t fid;
1296         cm_SkipIoctlPath(&ioctlp->ioctl);
1297         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
1298                   optionsp->fid.vnode, optionsp->fid.unique);
1299         code = cm_GetSCache(&fid, &scp, userp, &req);
1300     } else {
1301         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1302     }
1303     if (code) 
1304         return code;
1305
1306     code = cm_IoctlFlushFile(&ioctlp->ioctl, userp, scp, &req);
1307
1308     cm_ReleaseSCache(scp);
1309     return code;
1310 }
1311
1312 afs_int32 
1313 smb_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1314 {
1315     afs_int32 code;
1316     cm_scache_t *scp;
1317     cm_req_t req;
1318
1319     smb_InitReq(&req);
1320
1321     code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, 0);
1322     if (code) return code;
1323
1324     code = cm_IoctlSetVolumeStatus(&ioctlp->ioctl, userp, scp, &req);
1325     cm_ReleaseSCache(scp);
1326
1327     return code;
1328 }
1329
1330 afs_int32 
1331 smb_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1332 {
1333     afs_int32 code;
1334     cm_scache_t *scp;
1335     cm_ioctlQueryOptions_t *optionsp;
1336     afs_uint32 flags = 0;
1337     cm_req_t req;
1338
1339     smb_InitReq(&req);
1340
1341     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1342     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1343         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1344
1345     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1346         cm_fid_t fid;
1347         cm_SkipIoctlPath(&ioctlp->ioctl);
1348         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
1349                   optionsp->fid.vnode, optionsp->fid.unique);
1350         code = cm_GetSCache(&fid, &scp, userp, &req);
1351     } else {
1352         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1353     }
1354     if (code) 
1355         return code;
1356
1357     code = cm_IoctlGetVolumeStatus(&ioctlp->ioctl, userp, scp, &req);
1358
1359     cm_ReleaseSCache(scp);
1360
1361     return code;
1362 }
1363
1364 afs_int32 
1365 smb_IoctlGetFid(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1366 {
1367     afs_int32 code;
1368     cm_scache_t *scp;
1369     cm_req_t req;
1370     cm_ioctlQueryOptions_t * optionsp;
1371     afs_uint32 flags = 0;
1372
1373     smb_InitReq(&req);
1374
1375     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1376     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1377         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1378
1379     code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1380     if (code) 
1381         return code;
1382
1383     code = cm_IoctlGetFid(&ioctlp->ioctl, userp, scp, &req);
1384
1385     cm_ReleaseSCache(scp);
1386
1387     return code;
1388 }
1389
1390 afs_int32 
1391 smb_IoctlGetFileType(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1392 {
1393     afs_int32 code;
1394     cm_scache_t *scp;
1395     cm_req_t req;
1396     cm_ioctlQueryOptions_t * optionsp;
1397     afs_uint32 flags = 0;
1398
1399     smb_InitReq(&req);
1400
1401     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1402     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1403         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1404
1405     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1406         cm_fid_t fid;
1407         cm_SkipIoctlPath(&ioctlp->ioctl);
1408         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
1409                   optionsp->fid.vnode, optionsp->fid.unique);
1410         code = cm_GetSCache(&fid, &scp, userp, &req);
1411     } else {
1412         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1413     }
1414     if (code) 
1415         return code;
1416
1417     code = cm_IoctlGetFileType(&ioctlp->ioctl, userp, scp, &req);
1418
1419     cm_ReleaseSCache(scp);
1420
1421     return code;
1422 }
1423
1424 afs_int32 
1425 smb_IoctlGetOwner(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1426 {
1427     afs_int32 code;
1428     cm_scache_t *scp;
1429     cm_req_t req;
1430     cm_ioctlQueryOptions_t *optionsp;
1431     afs_uint32 flags = 0;
1432
1433     smb_InitReq(&req);
1434
1435     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1436     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1437         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1438
1439     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1440         cm_fid_t fid;
1441         cm_SkipIoctlPath(&ioctlp->ioctl);
1442         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
1443                   optionsp->fid.vnode, optionsp->fid.unique);
1444         code = cm_GetSCache(&fid, &scp, userp, &req);
1445     } else {
1446         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1447     }
1448     if (code) 
1449         return code;
1450
1451     code = cm_IoctlGetOwner(&ioctlp->ioctl, userp, scp, &req);
1452
1453     cm_ReleaseSCache(scp);
1454
1455     return code;
1456 }
1457
1458 afs_int32 
1459 smb_IoctlWhereIs(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1460 {
1461     afs_int32 code;
1462     cm_scache_t *scp;
1463     cm_req_t req;
1464     cm_ioctlQueryOptions_t *optionsp;
1465     afs_uint32 flags = 0;
1466
1467     smb_InitReq(&req);
1468
1469     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1470     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1471         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1472
1473     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1474         cm_fid_t fid;
1475         cm_SkipIoctlPath(&ioctlp->ioctl);
1476         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
1477                   optionsp->fid.vnode, optionsp->fid.unique);
1478         code = cm_GetSCache(&fid, &scp, userp, &req);
1479     } else {
1480         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1481     }
1482     if (code) 
1483         return code;
1484
1485     code = cm_IoctlWhereIs(&ioctlp->ioctl, userp, scp, &req);
1486
1487     cm_ReleaseSCache(scp);
1488
1489     return code;
1490 }
1491
1492
1493 afs_int32 
1494 smb_IoctlStatMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1495 {
1496     afs_int32 code;
1497     cm_scache_t *dscp;
1498     cm_req_t req;
1499
1500     smb_InitReq(&req);
1501
1502     code = smb_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
1503     if (code)
1504         return code;
1505
1506     code = cm_IoctlStatMountPoint(&ioctlp->ioctl, userp, dscp, &req);
1507
1508     cm_ReleaseSCache(dscp);
1509
1510     return code;
1511 }
1512
1513 afs_int32 
1514 smb_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1515 {
1516     afs_int32 code;
1517     cm_scache_t *dscp;
1518     cm_req_t req;
1519
1520     smb_InitReq(&req);
1521
1522     code = smb_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
1523     if (code) 
1524         return code;
1525
1526     code = cm_IoctlDeleteMountPoint(&ioctlp->ioctl, userp, dscp, &req);
1527
1528     cm_ReleaseSCache(dscp);
1529
1530     return code;
1531 }
1532
1533 afs_int32 
1534 smb_IoctlCheckServers(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1535 {
1536     cm_SkipIoctlPath(&ioctlp->ioctl);   /* we don't care about the path */
1537
1538     return cm_IoctlCheckServers(&ioctlp->ioctl, userp);
1539 }
1540
1541 afs_int32 
1542 smb_IoctlGag(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1543 {
1544     /* we don't print anything superfluous, so we don't support the gag call */
1545     return CM_ERROR_INVAL;
1546 }
1547
1548 afs_int32 
1549 smb_IoctlCheckVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1550 {
1551     cm_SkipIoctlPath(&ioctlp->ioctl);
1552
1553     return cm_IoctlCheckVolumes(&ioctlp->ioctl, userp);
1554 }
1555
1556 afs_int32 smb_IoctlSetCacheSize(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1557 {
1558     cm_SkipIoctlPath(&ioctlp->ioctl);
1559
1560     return cm_IoctlSetCacheSize(&ioctlp->ioctl, userp);
1561 }
1562
1563
1564 afs_int32 
1565 smb_IoctlTraceControl(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1566 {
1567     cm_SkipIoctlPath(&ioctlp->ioctl);
1568        
1569     return cm_IoctlTraceControl(&ioctlp->ioctl, userp);
1570 }
1571
1572 afs_int32 
1573 smb_IoctlGetCacheParms(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1574 {
1575     cm_SkipIoctlPath(&ioctlp->ioctl);
1576        
1577     return cm_IoctlGetCacheParms(&ioctlp->ioctl, userp);
1578 }
1579
1580 afs_int32 
1581 smb_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1582 {
1583     cm_SkipIoctlPath(&ioctlp->ioctl);
1584
1585     return cm_IoctlGetCell(&ioctlp->ioctl, userp);
1586 }
1587
1588 afs_int32 
1589 smb_IoctlNewCell(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1590 {
1591     cm_SkipIoctlPath(&ioctlp->ioctl);
1592
1593     return cm_IoctlNewCell(&ioctlp->ioctl, userp);
1594 }
1595
1596 afs_int32 
1597 smb_IoctlNewCell2(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1598 {
1599     cm_SkipIoctlPath(&ioctlp->ioctl);
1600
1601     return cm_IoctlNewCell2(&ioctlp->ioctl, userp);
1602 }
1603
1604 afs_int32
1605 smb_IoctlGetWsCell(smb_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags)
1606 {
1607     cm_SkipIoctlPath(&ioctlp->ioctl);
1608
1609     return cm_IoctlGetWsCell(&ioctlp->ioctl, userp);
1610 }
1611
1612 afs_int32 
1613 smb_IoctlSysName(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1614 {
1615     cm_SkipIoctlPath(&ioctlp->ioctl);
1616
1617     return cm_IoctlSysName(&ioctlp->ioctl, userp);
1618 }
1619
1620 afs_int32 
1621 smb_IoctlGetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1622 {
1623     cm_SkipIoctlPath(&ioctlp->ioctl);
1624
1625     return cm_IoctlGetCellStatus(&ioctlp->ioctl, userp);
1626 }
1627
1628 afs_int32 
1629 smb_IoctlSetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1630 {
1631     cm_SkipIoctlPath(&ioctlp->ioctl);
1632
1633     return cm_IoctlSetCellStatus(&ioctlp->ioctl, userp);
1634 }
1635
1636 afs_int32
1637 smb_IoctlSetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1638 {
1639     cm_SkipIoctlPath(&ioctlp->ioctl);
1640
1641     return cm_IoctlSetSPrefs(&ioctlp->ioctl, userp);
1642 }
1643
1644 afs_int32
1645 smb_IoctlGetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1646 {
1647     cm_SkipIoctlPath(&ioctlp->ioctl);
1648
1649     return cm_IoctlGetSPrefs(&ioctlp->ioctl, userp);
1650 }
1651
1652 afs_int32
1653 smb_IoctlStoreBehind(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1654 {
1655     /* we ignore default asynchrony since we only have one way
1656      * of doing this today.
1657      */
1658     return 0;
1659 }       
1660
1661 afs_int32
1662 smb_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1663 {
1664     afs_int32 code;
1665     cm_scache_t *dscp;
1666     clientchar_t leaf[LEAF_SIZE];
1667     cm_req_t req;
1668
1669     smb_InitReq(&req);
1670         
1671     code = smb_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
1672     if (code)
1673         return code;
1674
1675     code = cm_IoctlCreateMountPoint(&ioctlp->ioctl, userp, dscp, &req, leaf);
1676
1677     cm_ReleaseSCache(dscp);
1678     return code;
1679 }
1680
1681 afs_int32
1682 smb_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1683 {
1684     afs_int32 code;
1685     cm_scache_t *dscp;
1686     clientchar_t leaf[LEAF_SIZE];
1687     cm_req_t req;
1688
1689     smb_InitReq(&req);
1690
1691     code = smb_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
1692     if (code) return code;
1693
1694     code = cm_IoctlSymlink(&ioctlp->ioctl, userp, dscp, &req, leaf);
1695
1696     cm_ReleaseSCache(dscp);
1697
1698     return code;
1699 }
1700
1701 afs_int32 
1702 smb_IoctlListlink(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1703 {
1704     afs_int32 code;
1705     cm_scache_t *dscp;
1706     cm_req_t req;
1707
1708     smb_InitReq(&req);
1709
1710     code = smb_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
1711     if (code) return code;
1712
1713     code = cm_IoctlListlink(&ioctlp->ioctl, userp, dscp, &req);
1714
1715     cm_ReleaseSCache(dscp);
1716     return code;
1717 }
1718
1719 afs_int32 
1720 smb_IoctlIslink(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1721 {/*CHECK FOR VALID SYMLINK*/
1722     afs_int32 code;
1723     cm_scache_t *dscp;
1724     cm_req_t req;
1725
1726     smb_InitReq(&req);
1727
1728     code = smb_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
1729     if (code) return code;
1730
1731     code = cm_IoctlIslink(&ioctlp->ioctl, userp, dscp, &req);
1732
1733     cm_ReleaseSCache(dscp);
1734
1735     return code;
1736 }
1737
1738 afs_int32 
1739 smb_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1740 {
1741     afs_int32 code;
1742     cm_scache_t *dscp;
1743     cm_req_t req;
1744
1745     smb_InitReq(&req);
1746
1747     code = smb_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
1748     if (code) return code;
1749
1750     code = cm_IoctlDeletelink(&ioctlp->ioctl, userp, dscp, &req);
1751
1752     cm_ReleaseSCache(dscp);
1753
1754     return code;
1755 }
1756
1757 afs_int32 
1758 smb_IoctlGetTokenIter(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1759 {
1760     cm_SkipIoctlPath(&ioctlp->ioctl);
1761
1762     return cm_IoctlGetTokenIter(&ioctlp->ioctl, userp);
1763 }
1764
1765 afs_int32
1766 smb_IoctlGetToken(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1767 {
1768     cm_SkipIoctlPath(&ioctlp->ioctl);
1769
1770     return cm_IoctlGetToken(&ioctlp->ioctl, userp);
1771 }
1772
1773
1774 afs_int32
1775 smb_IoctlDelToken(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1776 {
1777     cm_SkipIoctlPath(&ioctlp->ioctl);
1778
1779     return cm_IoctlDelToken(&ioctlp->ioctl, userp);
1780 }
1781
1782
1783 afs_int32
1784 smb_IoctlDelAllToken(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1785 {
1786     cm_SkipIoctlPath(&ioctlp->ioctl);
1787
1788     return cm_IoctlDelAllToken(&ioctlp->ioctl, userp);
1789 }
1790
1791
1792 afs_int32
1793 smb_IoctlMakeSubmount(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1794 {
1795     cm_SkipIoctlPath(&ioctlp->ioctl);
1796
1797     return cm_IoctlMakeSubmount(&ioctlp->ioctl, userp);
1798 }
1799
1800 afs_int32
1801 smb_IoctlGetRxkcrypt(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1802 {
1803     cm_SkipIoctlPath(&ioctlp->ioctl);
1804
1805     return cm_IoctlGetRxkcrypt(&ioctlp->ioctl, userp);
1806 }
1807
1808 afs_int32
1809 smb_IoctlSetRxkcrypt(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1810 {
1811     cm_SkipIoctlPath(&ioctlp->ioctl);
1812
1813     return cm_IoctlSetRxkcrypt(&ioctlp->ioctl, userp);
1814 }
1815
1816 afs_int32
1817 smb_IoctlRxStatProcess(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1818 {
1819     cm_SkipIoctlPath(&ioctlp->ioctl);
1820
1821     return cm_IoctlRxStatProcess(&ioctlp->ioctl, userp);
1822 }
1823
1824
1825 afs_int32
1826 smb_IoctlRxStatPeer(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1827 {
1828     cm_SkipIoctlPath(&ioctlp->ioctl);
1829
1830     return cm_IoctlRxStatPeer(&ioctlp->ioctl, userp);
1831 }
1832
1833 afs_int32
1834 smb_IoctlUnicodeControl(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1835 {
1836     cm_SkipIoctlPath(&ioctlp->ioctl);
1837
1838     return cm_IoctlUnicodeControl(&ioctlp->ioctl, userp);
1839 }
1840
1841 afs_int32
1842 smb_IoctlUUIDControl(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1843 {
1844     cm_SkipIoctlPath(&ioctlp->ioctl);
1845
1846     return cm_IoctlUUIDControl(&ioctlp->ioctl, userp);
1847 }
1848
1849
1850 afs_int32
1851 smb_IoctlMemoryDump(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1852 {
1853     cm_SkipIoctlPath(&ioctlp->ioctl);
1854
1855     return cm_IoctlMemoryDump(&ioctlp->ioctl, userp);
1856 }
1857
1858 afs_int32
1859 smb_IoctlPathAvailability(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1860 {
1861     afs_int32 code;
1862     cm_scache_t *scp;
1863     cm_req_t req;
1864     cm_ioctlQueryOptions_t *optionsp;
1865     afs_uint32 flags = 0;
1866
1867     smb_InitReq(&req);
1868
1869     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1870     if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1871         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1872
1873     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1874         cm_fid_t fid;
1875         cm_SkipIoctlPath(&ioctlp->ioctl);
1876         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
1877                   optionsp->fid.vnode, optionsp->fid.unique);
1878         code = cm_GetSCache(&fid, &scp, userp, &req);
1879     } else {
1880         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1881     }
1882     if (code) 
1883         return code;
1884
1885     code = cm_IoctlPathAvailability(&ioctlp->ioctl, userp, scp, &req);
1886     cm_ReleaseSCache(scp);
1887     return code;
1888 }
1889
1890 afs_int32
1891 smb_IoctlVolStatTest(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1892 {
1893     cm_req_t req;
1894
1895     smb_InitReq(&req);
1896
1897     cm_SkipIoctlPath(&ioctlp->ioctl);
1898
1899     return cm_IoctlVolStatTest(&ioctlp->ioctl, userp, &req);
1900 }
1901
1902 /* 
1903  * VIOC_SETOWNER
1904  * 
1905  * This pioctl requires the use of the cm_ioctlQueryOptions_t structure.
1906  *
1907  */
1908 afs_int32 
1909 smb_IoctlSetOwner(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1910 {
1911     afs_int32 code;
1912     cm_scache_t *scp;
1913     cm_req_t req;
1914     cm_ioctlQueryOptions_t *optionsp;
1915     afs_uint32 flags = 0;
1916
1917     smb_InitReq(&req);
1918
1919     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1920     if (optionsp) {
1921         if (CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1922             flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1923
1924         if (CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1925             cm_fid_t fid;
1926             cm_SkipIoctlPath(&ioctlp->ioctl);
1927             cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
1928                        optionsp->fid.vnode, optionsp->fid.unique);
1929             code = cm_GetSCache(&fid, &scp, userp, &req);
1930         } else {
1931             code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1932         }
1933         if (code) 
1934             return code;
1935
1936         cm_IoctlSkipQueryOptions(&ioctlp->ioctl, userp);
1937     }
1938
1939     code = cm_IoctlSetOwner(&ioctlp->ioctl, userp, scp, &req);
1940
1941     cm_ReleaseSCache(scp);
1942
1943     return code;
1944 }
1945
1946 /* 
1947  * VIOC_GETOWNER
1948  * 
1949  * This pioctl requires the use of the cm_ioctlQueryOptions_t structure.
1950  *
1951  */
1952 afs_int32 
1953 smb_IoctlSetGroup(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
1954 {
1955     afs_int32 code;
1956     cm_scache_t *scp;
1957     cm_req_t req;
1958     cm_ioctlQueryOptions_t *optionsp;
1959     afs_uint32 flags = 0;
1960
1961     smb_InitReq(&req);
1962
1963     optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
1964     if (optionsp) {
1965         if (CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
1966             flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
1967
1968         if (CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
1969             cm_fid_t fid;
1970             cm_SkipIoctlPath(&ioctlp->ioctl);
1971             cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
1972                        optionsp->fid.vnode, optionsp->fid.unique);
1973             code = cm_GetSCache(&fid, &scp, userp, &req);
1974         } else {
1975             code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
1976         }
1977         if (code) 
1978             return code;
1979
1980         cm_IoctlSkipQueryOptions(&ioctlp->ioctl, userp);
1981     }
1982
1983     code = cm_IoctlSetGroup(&ioctlp->ioctl, userp, scp, &req);
1984
1985     cm_ReleaseSCache(scp);
1986
1987     return code;
1988 }
1989
1990
1991