Windows: fs getcalleraccess
[openafs.git] / src / WINNT / afsd / smb_ioctl.c
index e4e5982..71e5e27 100644 (file)
@@ -1,16 +1,20 @@
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
  */
 
+#include <afsconfig.h>
 #include <afs/param.h>
+#include <roken.h>
+
 #include <afs/stds.h>
 
 #include <windows.h>
+#include <sddl.h>
 #include <stdlib.h>
 #include <malloc.h>
 #include <string.h>
@@ -30,7 +34,7 @@
 
 smb_ioctlProc_t *smb_ioctlProcsp[SMB_IOCTL_MAXPROCS];
 
-void 
+void
 smb_InitIoctl(void)
 {
     int i;
@@ -87,10 +91,18 @@ smb_InitIoctl(void)
     smb_ioctlProcsp[VIOC_GETFILETYPE] = smb_IoctlGetFileType;
     smb_ioctlProcsp[VIOC_VOLSTAT_TEST] = smb_IoctlVolStatTest;
     smb_ioctlProcsp[VIOC_UNICODECTL] = smb_IoctlUnicodeControl;
-}       
+    smb_ioctlProcsp[VIOC_SETOWNER] = smb_IoctlSetOwner;
+    smb_ioctlProcsp[VIOC_SETGROUP] = smb_IoctlSetGroup;
+    smb_ioctlProcsp[VIOCNEWCELL2] = smb_IoctlNewCell2;
+    smb_ioctlProcsp[VIOC_SETUNIXMODE] = smb_IoctlSetUnixMode;
+    smb_ioctlProcsp[VIOC_GETUNIXMODE] = smb_IoctlGetUnixMode;
+    smb_ioctlProcsp[VIOC_SETVERIFYDATA] = smb_IoctlSetVerifyData;
+    smb_ioctlProcsp[VIOC_GETVERIFYDATA] = smb_IoctlGetVerifyData;
+    smb_ioctlProcsp[VIOC_GETCALLERACCESS] = smb_IoctlGetCallerAccess;
+}
 
 /* called to make a fid structure into an IOCTL fid structure */
-void 
+void
 smb_SetupIoctlFid(smb_fid_t *fidp, cm_space_t *prefix)
 {
     smb_ioctl_t *iop;
@@ -108,7 +120,7 @@ smb_SetupIoctlFid(smb_fid_t *fidp, cm_space_t *prefix)
     }
     if (prefix) {
         copyPrefix = cm_GetSpace();
-        StringCbCopy(copyPrefix->data, CM_UTILS_SPACESIZE, prefix->data);
+        memcpy(copyPrefix->data, prefix->data, CM_UTILS_SPACESIZE);
         fidp->ioctlp->prefix = copyPrefix;
     }
     lock_ReleaseMutex(&fidp->mx);
@@ -119,7 +131,7 @@ smb_SetupIoctlFid(smb_fid_t *fidp, cm_space_t *prefix)
  * call to the ioctl code.
  */
 afs_int32
-smb_IoctlPrepareRead(struct smb_fid *fidp, smb_ioctl_t *ioctlp, cm_user_t *userp)
+smb_IoctlPrepareRead(struct smb_fid *fidp, smb_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags)
 {
     afs_int32 opcode;
     smb_ioctlProc_t *procp = NULL;
@@ -127,35 +139,41 @@ smb_IoctlPrepareRead(struct smb_fid *fidp, smb_ioctl_t *ioctlp, cm_user_t *userp
 
     if (ioctlp->ioctl.flags & CM_IOCTLFLAG_DATAIN) {
         ioctlp->ioctl.flags &= ~CM_IOCTLFLAG_DATAIN;
+        ioctlp->ioctl.flags |= CM_IOCTLFLAG_DATAOUT;
 
         /* do the call now, or fail if we didn't get an opcode, or
          * enough of an opcode.
          */
-        if (ioctlp->ioctl.inCopied < sizeof(afs_int32)) 
+        if (ioctlp->ioctl.inCopied < sizeof(afs_int32))
             return CM_ERROR_INVAL;
         memcpy(&opcode, ioctlp->ioctl.inDatap, sizeof(afs_int32));
         ioctlp->ioctl.inDatap += sizeof(afs_int32);
 
-        osi_Log1(afsd_logp, "Ioctl opcode 0x%x", opcode);
-
+        osi_Log1(afsd_logp, "smb_IoctlPrepareRead opcode 0x%x", opcode);
         /* check for opcode out of bounds */
-        if (opcode < 0 || opcode >= SMB_IOCTL_MAXPROCS)
+        if (opcode < 0 || opcode >= SMB_IOCTL_MAXPROCS) {
+            osi_Log0(afsd_logp, "smb_IoctlPrepareRead - invalid opcode");
             return CM_ERROR_TOOBIG;
+        }
 
         /* check for no such proc */
        procp = smb_ioctlProcsp[opcode];
-        if (procp == NULL) 
-            return CM_ERROR_BADOP;
-
+        if (procp == NULL) {
+            osi_Log0(afsd_logp, "smb_IoctlPrepareRead - unassigned opcode");
+            return CM_ERROR_INVAL;
+        }
         /* otherwise, make the call */
         ioctlp->ioctl.outDatap += sizeof(afs_int32); /* reserve room for return code */
-        code = (*procp)(ioctlp, userp);
-
-        osi_Log1(afsd_logp, "Ioctl return code 0x%x", code);
+        code = (*procp)(ioctlp, userp, pflags);
+        osi_Log1(afsd_logp, "smb_IoctlPrepareRead operation returns code 0x%x", code);
 
         /* copy in return code */
         memcpy(ioctlp->ioctl.outAllocp, &code, sizeof(afs_int32));
+    } else if (!(ioctlp->ioctl.flags & CM_IOCTLFLAG_DATAOUT)) {
+        osi_Log0(afsd_logp, "Ioctl invalid state - dataout expected");
+        return CM_ERROR_INVAL;
     }
+
     return 0;
 }
 
@@ -163,11 +181,11 @@ smb_IoctlPrepareRead(struct smb_fid *fidp, smb_ioctl_t *ioctlp, cm_user_t *userp
  * a series of reads (or the very first call), then we start a new call.
  * We also ensure that things are properly initialized for the start of a call.
  */
-void 
+void
 smb_IoctlPrepareWrite(smb_fid_t *fidp, smb_ioctl_t *ioctlp)
 {
     /* make sure the buffer(s) are allocated */
-    if (!ioctlp->ioctl.inAllocp) 
+    if (!ioctlp->ioctl.inAllocp)
         ioctlp->ioctl.inAllocp = malloc(SMB_IOCTL_MAXDATA);
     if (!ioctlp->ioctl.outAllocp)
         ioctlp->ioctl.outAllocp = malloc(SMB_IOCTL_MAXDATA);
@@ -183,8 +201,9 @@ smb_IoctlPrepareWrite(smb_fid_t *fidp, smb_ioctl_t *ioctlp)
         ioctlp->ioctl.inDatap = ioctlp->ioctl.inAllocp;
         ioctlp->ioctl.outDatap = ioctlp->ioctl.outAllocp;
         ioctlp->ioctl.flags |= CM_IOCTLFLAG_DATAIN;
+        ioctlp->ioctl.flags &= ~CM_IOCTLFLAG_DATAOUT;
     }
-}       
+}
 
 /* called from smb_ReceiveCoreRead when we receive a read on the ioctl fid */
 afs_int32
@@ -195,21 +214,56 @@ smb_IoctlRead(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
     afs_int32 leftToCopy;
     char *op;
     afs_int32 code;
-    cm_user_t *userp;
+    smb_user_t *uidp;
+    cm_user_t *userp = NULL;
+    smb_t *smbp;
+    int isSystem = 0;
 
     iop = fidp->ioctlp;
     count = smb_GetSMBParm(inp, 1);
-    userp = smb_GetUserFromVCP(vcp, inp);
+
+    /* Get the user and determine if it is the local machine account */
+    smbp = (smb_t *) inp;
+    uidp = smb_FindUID(vcp, smbp->uid, 0);
+    if (uidp) {
+        if (uidp->unp) {
+            osi_Log3(afsd_logp, "Ioctl uid %d user %x name %s",
+                      uidp->userID, userp,
+                      osi_LogSaveClientString(afsd_logp, uidp->unp->name));
+        } else {
+            osi_Log2(afsd_logp, "Ioctl uid %d user %x no name",
+                      uidp->userID, userp);
+        }
+        isSystem = smb_userIsLocalSystem(uidp);
+        userp = smb_GetUserFromUID(uidp);
+        if (uidp->unp) {
+            osi_Log3(afsd_logp, "smb_IoctlRead uid %d user %x name %s",
+                      uidp->userID, userp,
+                      osi_LogSaveClientString(afsd_logp, uidp->unp->name));
+        } else {
+            osi_Log2(afsd_logp, "smb_IoctlRead uid %d user %x no name",
+                      uidp->userID, userp);
+        }
+        smb_ReleaseUID(uidp);
+    } else {
+        osi_Log1(afsd_logp, "smb_IoctlRead no uid user %x no name", userp);
+        return CM_ERROR_BADSMB;
+    }
+
+    if (!userp) {
+        userp = cm_rootUserp;
+        cm_HoldUser(userp);
+    }
 
     /* Identify tree */
     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &iop->tidPathp);
-    if(code) {
+    if (code) {
         cm_ReleaseUser(userp);
         return CM_ERROR_NOSUCHPATH;
     }
 
     /* turn the connection around, if required */
-    code = smb_IoctlPrepareRead(fidp, iop, userp);
+    code = smb_IoctlPrepareRead(fidp, iop, userp, isSystem ? AFSCALL_FLAG_LOCAL_SYSTEM : 0);
 
     if (code) {
         cm_ReleaseUser(userp);
@@ -217,6 +271,11 @@ smb_IoctlRead(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
     }
 
     leftToCopy = (afs_int32)((iop->ioctl.outDatap - iop->ioctl.outAllocp) - iop->ioctl.outCopied);
+    if (leftToCopy < 0) {
+        osi_Log0(afsd_logp, "smb_IoctlRead leftToCopy went negative");
+        cm_ReleaseUser(userp);
+        return CM_ERROR_INVAL;
+    }
     if (count > leftToCopy)
         count = leftToCopy;
 
@@ -260,20 +319,20 @@ smb_IoctlWrite(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     code = 0;
     count = smb_GetSMBParm(inp, 1);
     iop = fidp->ioctlp;
-        
+
     smb_IoctlPrepareWrite(fidp, iop);
 
     op = smb_GetSMBData(inp, NULL);
     op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
-       
+
     if (count + iop->ioctl.inCopied > SMB_IOCTL_MAXDATA) {
         code = CM_ERROR_TOOBIG;
         goto done;
     }
-        
+
     /* copy data */
     memcpy(iop->ioctl.inDatap + iop->ioctl.inCopied, op, count);
-        
+
     /* adjust counts */
     iop->ioctl.inCopied += count;
 
@@ -285,7 +344,7 @@ smb_IoctlWrite(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     }
 
     return code;
-}       
+}
 
 /* called from smb_ReceiveV3WriteX when we receive a write call on the IOCTL
  * file descriptor.
@@ -312,7 +371,7 @@ smb_IoctlV3Write(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
         code = CM_ERROR_TOOBIG;
         goto done;
     }
-        
+
     /* copy data */
     memcpy(iop->ioctl.inDatap + iop->ioctl.inCopied, op, count);
 
@@ -330,7 +389,7 @@ smb_IoctlV3Write(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
     }
 
     return code;
-}       
+}
 
 
 /* called from V3 read to handle IOCTL descriptor reads */
@@ -338,33 +397,42 @@ afs_int32
 smb_IoctlV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     smb_ioctl_t *iop;
-    long count;
+    unsigned short count;
     afs_int32 code;
     long leftToCopy;
     char *op;
     cm_user_t *userp;
     smb_user_t *uidp;
+    int isSystem = 0;
 
     iop = fidp->ioctlp;
     count = smb_GetSMBParm(inp, 5);
-       
+
+    /* Get the user and determine if it is the local machine account */
     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
-    userp = smb_GetUserFromUID(uidp);
-    osi_assertx(userp != NULL, "null cm_user_t");
-    iop->uidp = uidp;
-    if (uidp && uidp->unp) {
-        osi_Log3(afsd_logp, "Ioctl uid %d user %x name %S",
-                  uidp->userID, userp,
-                  osi_LogSaveClientString(afsd_logp, uidp->unp->name));
-    } else {
-        if (uidp)
-           osi_Log2(afsd_logp, "Ioctl uid %d user %x no name",
-                     uidp->userID, userp);
-        else
-           osi_Log1(afsd_logp, "Ioctl no uid user %x no name",
-                    userp);
+    if (uidp) {
+        isSystem = smb_userIsLocalSystem(uidp);
+        userp = smb_GetUserFromUID(uidp);
+        if (uidp->unp) {
+            osi_Log3(afsd_logp, "smb_IoctlV3Read uid %d user %x name %s",
+                      uidp->userID, userp,
+                      osi_LogSaveClientString(afsd_logp, uidp->unp->name));
+        } else {
+            osi_Log2(afsd_logp, "smb_IoctlV3Read uid %d user %x no name",
+                      uidp->userID, userp);
+        }
+     } else {
+         osi_Log0(afsd_logp, "smb_IoctlV3Read no uid");
+         return CM_ERROR_BADSMB;
+     }
+
+    if (!userp) {
+        userp = cm_rootUserp;
+        cm_HoldUser(userp);
     }
 
+    iop->uidp = uidp;
+
     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &iop->tidPathp);
     if (code) {
        if (uidp)
@@ -373,7 +441,7 @@ smb_IoctlV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
         return CM_ERROR_NOSUCHPATH;
     }
 
-    code = smb_IoctlPrepareRead(fidp, iop, userp);
+    code = smb_IoctlPrepareRead(fidp, iop, userp, isSystem ? AFSCALL_FLAG_LOCAL_SYSTEM : 0);
     if (uidp) {
         iop->uidp = 0;
         smb_ReleaseUID(uidp);
@@ -384,9 +452,14 @@ smb_IoctlV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
     }
 
     leftToCopy = (long)((iop->ioctl.outDatap - iop->ioctl.outAllocp) - iop->ioctl.outCopied);
-    if (count > leftToCopy) 
-        count = leftToCopy;
-        
+    if (leftToCopy < 0) {
+        osi_Log0(afsd_logp, "smb_IoctlV3Read leftToCopy went negative");
+        cm_ReleaseUser(userp);
+        return CM_ERROR_INVAL;
+    }
+    if (count > leftToCopy)
+        count = (unsigned short)leftToCopy;
+
     /* 0 and 1 are reserved for request chaining, were setup by our caller,
      * and will be further filled in after we return.
      */
@@ -405,13 +478,13 @@ smb_IoctlV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
      * know where the data really is.
      */
     op = smb_GetSMBData(outp, NULL);
-        
+
     /* now fill in offset from start of SMB header to first data byte (to op) */
     smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
 
     /* set the packet data length the count of the # of bytes */
     smb_SetSMBDataLength(outp, count);
-        
+
     /* now copy the data into the response packet */
     memcpy(op, iop->ioctl.outCopied + iop->ioctl.outAllocp, count);
 
@@ -422,7 +495,7 @@ smb_IoctlV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
     cm_ReleaseUser(userp);
 
     return 0;
-}      
+}
 
 /* called from Read Raw to handle IOCTL descriptor reads */
 afs_int32
@@ -435,26 +508,32 @@ smb_IoctlReadRaw(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp,
     afs_int32 code;
     cm_user_t *userp;
     smb_user_t *uidp;
+    int isSystem = 0;
 
     iop = fidp->ioctlp;
 
-    userp = smb_GetUserFromVCP(vcp, inp);
-
-    /* Log the user */
+    /* Get the user and determine if it is the local machine account */
     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
-    if (uidp && uidp->unp) {
-        osi_Log3(afsd_logp, "Ioctl uid %d user %x name %s",
-                 uidp->userID, userp,
-                 osi_LogSaveClientString(afsd_logp, uidp->unp->name));
-    } else if (uidp) {
-        osi_Log2(afsd_logp, "Ioctl uid %d user %x no name",
-                 uidp->userID, userp);
+    if (uidp) {
+        isSystem = smb_userIsLocalSystem(uidp);
+        userp = smb_GetUserFromUID(uidp);
+        if (uidp->unp) {
+            osi_Log3(afsd_logp, "smb_IoctlRawRead uid %d user %x name %s",
+                      uidp->userID, userp,
+                      osi_LogSaveClientString(afsd_logp, uidp->unp->name));
+        } else {
+            osi_Log2(afsd_logp, "smb_IoctlRawRead uid %d user %x no name",
+                      uidp->userID, userp);
+        }
+        smb_ReleaseUID(uidp);
     } else {
-        osi_Log1(afsd_logp, "Ioctl no uid user %x no name",
-                  userp);
+        osi_Log0(afsd_logp, "smb_IoctlRawRead no uid");
+    }
+
+    if (!userp) {
+        userp = cm_rootUserp;
+        cm_HoldUser(userp);
     }
-    if (uidp) 
-        smb_ReleaseUID(uidp);
 
     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &iop->tidPathp);
     if (code) {
@@ -462,15 +541,20 @@ smb_IoctlReadRaw(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp,
         goto done;
     }
 
-    code = smb_IoctlPrepareRead(fidp, iop, userp);
+    code = smb_IoctlPrepareRead(fidp, iop, userp, isSystem ? AFSCALL_FLAG_LOCAL_SYSTEM : 0);
     if (code) {
         goto done;
     }
 
     leftToCopy = (long)((iop->ioctl.outDatap - iop->ioctl.outAllocp) - iop->ioctl.outCopied);
+    if (leftToCopy < 0) {
+        osi_Log0(afsd_logp, "smb_IoctlReadRaw leftToCopy went negative");
+        code = CM_ERROR_INVAL;
+        goto done;
+    }
 
     ncbp = outp->ncbp;
-    memset((char *)ncbp, 0, sizeof(NCB));
+    memset(ncbp, 0, sizeof(NCB));
 
     ncbp->ncb_length = (unsigned short) leftToCopy;
     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
@@ -570,15 +654,15 @@ smb_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
     }
 
     if (relativePath[0] == relativePath[1] &&
-        relativePath[1] == '\\' && 
+        relativePath[1] == '\\' &&
         !cm_ClientStrCmpNI(cm_NetbiosNameC, relativePath+2,
-                           cm_ClientStrLen(cm_NetbiosNameC))) 
+                           (int)cm_ClientStrLen(cm_NetbiosNameC)))
     {
         clientchar_t shareName[256];
         clientchar_t *sharePath;
         int shareFound, i;
 
-        /* We may have found a UNC path. 
+        /* We may have found a UNC path.
          * If the first component is the NetbiosName,
          * then throw out the second component (the submount)
          * since it had better expand into the value of ioctl->tidPathp
@@ -597,7 +681,7 @@ smb_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
         shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
         if ( shareFound ) {
             /* we found a sharename, therefore use the resulting path */
-            code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->wdata,
+            code = cm_NameI(cm_RootSCachep(userp, reqp), ioctlp->prefix->wdata,
                             CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
                             userp, sharePath, reqp, &substRootp);
             free(sharePath);
@@ -634,7 +718,7 @@ smb_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
            }
         } else {
             /* otherwise, treat the name as a cellname mounted off the afs root.
-             * This requires that we reconstruct the shareName string with 
+             * This requires that we reconstruct the shareName string with
              * leading and trailing slashes.
              */
             p = relativePath + 2 + cm_ClientStrLen(cm_NetbiosNameC) + 1;
@@ -650,7 +734,7 @@ smb_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
             shareName[i] = 0;       /* terminate string */
 
 
-            code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->wdata,
+            code = cm_NameI(cm_RootSCachep(userp, reqp), ioctlp->prefix->wdata,
                             CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
                             userp, shareName, reqp, &substRootp);
             if (code) {
@@ -687,7 +771,7 @@ smb_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
            }
         }
     } else {
-        code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->wdata,
+        code = cm_NameI(cm_RootSCachep(userp, reqp), ioctlp->prefix->wdata,
                          CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
                          userp, ioctlp->tidPathp, reqp, &substRootp);
         if (code) {
@@ -696,7 +780,7 @@ smb_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
                 free(relativePath);
             return code;
        }
-        
+
        lastComponent = cm_ClientStrRChr(relativePath,  '\\');
        if (lastComponent && (lastComponent - relativePath) > 1 &&
             cm_ClientStrLen(lastComponent) > 1) {
@@ -726,11 +810,19 @@ smb_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
     if (substRootp)
        cm_ReleaseSCache(substRootp);
 
-    /* and return success */
-    osi_Log1(afsd_logp,"cm_ParseIoctlPath [8] code 0x%x", code);
-
     if (relativePath)
         free(relativePath);
+
+    /* Ensure that the status object is up to date */
+    lock_ObtainWrite(&(*scpp)->rw);
+    code = cm_SyncOp( *scpp, NULL, userp, reqp, 0,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code == 0)
+        cm_SyncOpDone( *scpp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    lock_ReleaseWrite(&(*scpp)->rw);
+
+    /* and return success */
+    osi_Log1(afsd_logp,"cm_ParseIoctlPath [8] code 0x%x", code);
     return 0;
 }
 
@@ -805,7 +897,7 @@ smb_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
     }
     else {
         *tp = 0;
-        if (leafp) 
+        if (leafp)
             cm_ClientStrCpy(leafp, LEAF_SIZE, tp+1);
     }
 
@@ -813,15 +905,15 @@ smb_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
     inpathp = NULL;             /* We don't need this from this point on */
 
     if (tbuffer[0] == tbuffer[1] &&
-        tbuffer[1] == '\\' && 
+        tbuffer[1] == '\\' &&
         !cm_ClientStrCmpNI(cm_NetbiosNameC, tbuffer+2,
-                           cm_ClientStrLen(cm_NetbiosNameC))) 
+                           (int)cm_ClientStrLen(cm_NetbiosNameC)))
     {
         clientchar_t shareName[256];
         clientchar_t *sharePath;
         int shareFound, i;
 
-        /* We may have found a UNC path. 
+        /* We may have found a UNC path.
          * If the first component is the NetbiosName,
          * then throw out the second component (the submount)
          * since it had better expand into the value of ioctl->tidPathp
@@ -840,7 +932,7 @@ smb_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
         shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
         if ( shareFound ) {
             /* we found a sharename, therefore use the resulting path */
-            code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->wdata,
+            code = cm_NameI(cm_RootSCachep(userp, reqp), ioctlp->prefix->wdata,
                             CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
                             userp, sharePath, reqp, &substRootp);
             free(sharePath);
@@ -852,7 +944,7 @@ smb_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
             if (code) return code;
         } else {
             /* otherwise, treat the name as a cellname mounted off the afs root.
-             * This requires that we reconstruct the shareName string with 
+             * This requires that we reconstruct the shareName string with
              * leading and trailing slashes.
              */
             p = tbuffer + 2 + cm_ClientStrLen(cm_NetbiosNameC) + 1;
@@ -867,7 +959,7 @@ smb_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
             shareName[i++] = '/';      /* add trailing slash */
             shareName[i] = 0;       /* terminate string */
 
-            code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->wdata,
+            code = cm_NameI(cm_RootSCachep(userp, reqp), ioctlp->prefix->wdata,
                             CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
                             userp, shareName, reqp, &substRootp);
             if (code) return code;
@@ -878,7 +970,7 @@ smb_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
             if (code) return code;
         }
     } else {
-        code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->wdata,
+        code = cm_NameI(cm_RootSCachep(userp, reqp), ioctlp->prefix->wdata,
                         CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
                         userp, ioctlp->tidPathp, reqp, &substRootp);
         if (code) return code;
@@ -893,12 +985,20 @@ smb_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
     code = (long)strlen(ioctlp->ioctl.inDatap) + 1;
     ioctlp->ioctl.inDatap += code;
 
+    /* Ensure that the status object is up to date */
+    lock_ObtainWrite(&(*scpp)->rw);
+    code = cm_SyncOp( *scpp, NULL, userp, reqp, 0,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code == 0)
+        cm_SyncOpDone( *scpp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    lock_ReleaseWrite(&(*scpp)->rw);
+
     /* and return success */
     return 0;
 }
 
-afs_int32 
-smb_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     char *saveDataPtr;
     char *tp;
@@ -915,6 +1015,7 @@ smb_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
     clientchar_t *uname = NULL;
     clientchar_t *smbname = NULL;
     clientchar_t *wdir = NULL;
+    clientchar_t *rpc_sid = NULL;
     afs_int32 code = 0;
 
     saveDataPtr = ioctlp->ioctl.inDatap;
@@ -976,37 +1077,116 @@ smb_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
         if (flags & PIOCTL_LOGON) {
             /* SMB user name with which to associate tokens */
             smbname = cm_ParseIoctlStringAlloc(&ioctlp->ioctl, tp);
-            osi_Log2(smb_logp,"cm_IoctlSetToken for user [%S] smbname [%S]",
+            osi_Log2(smb_logp,"smb_IoctlSetToken for user [%S] smbname [%S]",
                      osi_LogSaveClientString(smb_logp,uname),
                      osi_LogSaveClientString(smb_logp,smbname));
             fprintf(stderr, "SMB name = %S\n", smbname);
             tp += strlen(tp) + 1;
         } else {
-            osi_Log1(smb_logp,"cm_IoctlSetToken for user [%S]",
+            osi_Log1(smb_logp,"smb_IoctlSetToken for user [%S]",
                      osi_LogSaveClientString(smb_logp, uname));
         }
 
         /* uuid */
         memcpy(&uuid, tp, sizeof(uuid));
-        if (!cm_FindTokenEvent(uuid, sessionKey)) {
+        if (!cm_FindTokenEvent(uuid, sessionKey, &rpc_sid)) {
             code = CM_ERROR_INVAL;
             goto done;
         }
+
+        if (rpc_sid) {
+            if (!(pflags & AFSCALL_FLAG_LOCAL_SYSTEM)) {
+                osi_Log1(smb_logp,"smb_IoctlSetToken Rpc Sid [%S]",
+                         osi_LogSaveClientString(smb_logp, rpc_sid));
+                if (!cm_ClientStrCmp(NTSID_LOCAL_SYSTEM, rpc_sid))
+                    pflags |= AFSCALL_FLAG_LOCAL_SYSTEM;
+            }
+            LocalFree(rpc_sid);
+        }
+
+        if (!(pflags & AFSCALL_FLAG_LOCAL_SYSTEM) && (flags & PIOCTL_LOGON)) {
+            code = CM_ERROR_NOACCESS;
+            goto done;
+        }
     } else {
         cellp = cm_data.rootCellp;
-        osi_Log0(smb_logp,"cm_IoctlSetToken - no name specified");
+        osi_Log0(smb_logp,"smb_IoctlSetToken - no name specified");
     }
 
-    if (flags & PIOCTL_LOGON) {
-        userp = smb_FindCMUserByName(smbname, ioctlp->fidp->vcp->rname,
-                                    SMB_FLAG_CREATE|SMB_FLAG_AFSLOGON);
-       release_userp = 1;
+    if ((pflags & AFSCALL_FLAG_LOCAL_SYSTEM) && (flags & PIOCTL_LOGON)) {
+        PSID pSid = NULL;
+        DWORD dwSize1 = 0, dwSize2 = 0;
+        wchar_t *pszRefDomain = NULL;
+        SID_NAME_USE snu = SidTypeGroup;
+        clientchar_t * secSidString = NULL;
+        DWORD gle;
+
+        /*
+         * The specified smbname is may not be a SID for the user.
+         * See if we can obtain the SID for the specified name.
+         * If we can, use that instead of the name provided.
+         */
+
+        LookupAccountNameW( NULL /* System Name to begin Search */,
+                            smbname,
+                            NULL, &dwSize1,
+                            NULL, &dwSize2,
+                            &snu);
+        gle = GetLastError();
+        if (gle == ERROR_INSUFFICIENT_BUFFER) {
+            pSid = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, dwSize1);
+            /*
+             * Although dwSize2 is supposed to include the terminating
+             * NUL character, on Win7 it does not.
+             */
+            pszRefDomain = malloc((dwSize2 + 1) * sizeof(wchar_t));
+        }
+
+        if ( pSid && pszRefDomain ) {
+            if (LookupAccountNameW( NULL /* System Name to begin Search */,
+                                    smbname,
+                                    pSid, &dwSize1,
+                                    pszRefDomain, &dwSize2,
+                                    &snu))
+                ConvertSidToStringSidW(pSid, &secSidString);
+        }
+
+        if (secSidString) {
+            userp = smb_FindCMUserBySID( secSidString, ioctlp->fidp->vcp->rname,
+                                         SMB_FLAG_CREATE|SMB_FLAG_AFSLOGON);
+            LocalFree(secSidString);
+        } else {
+            /* Free the SID so we can reuse the variable */
+            if (pSid) {
+                LocalFree(pSid);
+                pSid = NULL;
+            }
+
+            /*
+             * If the SID for the name could not be found,
+             * perhaps it already is a SID
+             */
+            if (!ConvertStringSidToSidW( smbname, &pSid)) {
+                userp = smb_FindCMUserBySID( smbname, ioctlp->fidp->vcp->rname,
+                                             SMB_FLAG_CREATE|SMB_FLAG_AFSLOGON);
+            } else {
+                userp = smb_FindCMUserByName( smbname, ioctlp->fidp->vcp->rname,
+                                              SMB_FLAG_CREATE|SMB_FLAG_AFSLOGON);
+            }
+        }
+
+        if (pSid)
+            LocalFree(pSid);
+        if (pszRefDomain)
+            free(pszRefDomain);
+
+        release_userp = 1;
     }
 
     /* store the token */
     lock_ObtainMutex(&userp->mx);
     ucellp = cm_GetUCell(userp, cellp);
-    osi_Log1(smb_logp,"cm_IoctlSetToken ucellp %lx", ucellp);
+    osi_Log1(smb_logp,"smb_IoctlSetToken ucellp %lx", ucellp);
     ucellp->ticketLen = ticketLen;
     if (ucellp->ticketp)
         free(ucellp->ticketp); /* Discard old token if any */
@@ -1031,16 +1211,18 @@ smb_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
        cm_UsernameToId(uname, ucellp, &ucellp->uid);
 #endif
     }
-    ucellp->flags |= CM_UCELLFLAG_RXKAD;
+    _InterlockedOr(&ucellp->flags, CM_UCELLFLAG_RXKAD);
     lock_ReleaseMutex(&userp->mx);
 
-    if (flags & PIOCTL_LOGON) {
+    if ((pflags & AFSCALL_FLAG_LOCAL_SYSTEM) && (flags & PIOCTL_LOGON)) {
         ioctlp->ioctl.flags |= CM_IOCTLFLAG_LOGON;
     }
 
-    cm_ResetACLCache(userp);
+    cm_ResetACLCache(cellp, userp);
 
   done:
+    SecureZeroMemory(sessionKey, sizeof(sessionKey));
+
     if (release_userp)
        cm_ReleaseUser(userp);
 
@@ -1056,7 +1238,7 @@ smb_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
 
 
 afs_int32
-smb_IoctlGetSMBName(smb_ioctl_t *ioctlp, cm_user_t *userp)
+smb_IoctlGetSMBName(smb_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags)
 {
     smb_user_t *uidp = ioctlp->uidp;
 
@@ -1064,10 +1246,9 @@ smb_IoctlGetSMBName(smb_ioctl_t *ioctlp, cm_user_t *userp)
         int cch;
 
         cch = cm_ClientStringToUtf8(uidp->unp->name,
-                                    cm_ClientStrLen(uidp->unp->name),
-
+                                    -1,
                                     ioctlp->ioctl.outDatap,
-                                    (SMB_IOCTL_MAXDATA -
+                                    (int)(SMB_IOCTL_MAXDATA -
                                      (ioctlp->ioctl.outDatap - ioctlp->ioctl.outAllocp))
                                     / sizeof(cm_utf8char_t));
 
@@ -1077,8 +1258,8 @@ smb_IoctlGetSMBName(smb_ioctl_t *ioctlp, cm_user_t *userp)
     return 0;
 }
 
-afs_int32 
-smb_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
+afs_int32
+smb_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags)
 {
     cm_scache_t *scp;
     afs_int32 code;
@@ -1095,13 +1276,14 @@ smb_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
         cm_fid_t fid;
         cm_SkipIoctlPath(&ioctlp->ioctl);
-        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
                   optionsp->fid.vnode, optionsp->fid.unique);
-        code = cm_GetSCache(&fid, &scp, userp, &req);
+        code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
     } else {
         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
     }
-    if (code) 
+
+    if (code)
         return code;
 
     code = cm_IoctlGetACL(&ioctlp->ioctl, userp, scp, &req);
@@ -1110,19 +1292,18 @@ smb_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
     return code;
 }
 
-afs_int32 
-smb_IoctlSetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
+afs_int32
+smb_IoctlSetACL(smb_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags)
 {
     cm_scache_t *scp;
     afs_int32 code;
     cm_req_t req;
-    cm_ioctlQueryOptions_t *optionsp;
     afs_uint32 flags = 0;
 
     smb_InitReq(&req);
 
     code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
-    if (code) 
+    if (code)
         return code;
 
     code = cm_IoctlSetACL(&ioctlp->ioctl, userp, scp, &req);
@@ -1132,7 +1313,7 @@ smb_IoctlSetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
 }
 
 afs_int32
-smb_IoctlGetFileCellName(struct smb_ioctl *ioctlp, struct cm_user *userp)
+smb_IoctlGetFileCellName(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     afs_int32 code;
     cm_scache_t *scp;
@@ -1149,13 +1330,13 @@ smb_IoctlGetFileCellName(struct smb_ioctl *ioctlp, struct cm_user *userp)
     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
         cm_fid_t fid;
         cm_SkipIoctlPath(&ioctlp->ioctl);
-        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
                   optionsp->fid.vnode, optionsp->fid.unique);
-        code = cm_GetSCache(&fid, &scp, userp, &req);
+        code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
     } else {
         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
     }
-    if (code) 
+    if (code)
         return code;
 
     code = cm_IoctlGetFileCellName(&ioctlp->ioctl, userp, scp, &req);
@@ -1165,8 +1346,8 @@ smb_IoctlGetFileCellName(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return code;
 }
 
-afs_int32 
-smb_IoctlFlushAllVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlFlushAllVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_req_t req;
 
@@ -1177,8 +1358,8 @@ smb_IoctlFlushAllVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return cm_IoctlFlushAllVolumes(&ioctlp->ioctl, userp, &req);
 }
 
-afs_int32 
-smb_IoctlFlushVolume(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlFlushVolume(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     afs_int32 code;
     cm_scache_t *scp;
@@ -1195,13 +1376,13 @@ smb_IoctlFlushVolume(struct smb_ioctl *ioctlp, struct cm_user *userp)
     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
         cm_fid_t fid;
         cm_SkipIoctlPath(&ioctlp->ioctl);
-        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
                   optionsp->fid.vnode, optionsp->fid.unique);
-        code = cm_GetSCache(&fid, &scp, userp, &req);
+        code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
     } else {
         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
     }
-    if (code) 
+    if (code)
         return code;
 
     code = cm_IoctlFlushVolume(&ioctlp->ioctl, userp, scp, &req);
@@ -1211,8 +1392,8 @@ smb_IoctlFlushVolume(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return code;
 }
 
-afs_int32 
-smb_IoctlFlushFile(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlFlushFile(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     afs_int32 code;
     cm_scache_t *scp;
@@ -1231,11 +1412,11 @@ smb_IoctlFlushFile(struct smb_ioctl *ioctlp, struct cm_user *userp)
         cm_SkipIoctlPath(&ioctlp->ioctl);
        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
                   optionsp->fid.vnode, optionsp->fid.unique);
-        code = cm_GetSCache(&fid, &scp, userp, &req);
+        code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
     } else {
         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
     }
-    if (code) 
+    if (code)
         return code;
 
     code = cm_IoctlFlushFile(&ioctlp->ioctl, userp, scp, &req);
@@ -1244,8 +1425,8 @@ smb_IoctlFlushFile(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return code;
 }
 
-afs_int32 
-smb_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     afs_int32 code;
     cm_scache_t *scp;
@@ -1262,8 +1443,8 @@ smb_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return code;
 }
 
-afs_int32 
-smb_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     afs_int32 code;
     cm_scache_t *scp;
@@ -1280,13 +1461,13 @@ smb_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
         cm_fid_t fid;
         cm_SkipIoctlPath(&ioctlp->ioctl);
-        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
                   optionsp->fid.vnode, optionsp->fid.unique);
-        code = cm_GetSCache(&fid, &scp, userp, &req);
+        code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
     } else {
         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
     }
-    if (code) 
+    if (code)
         return code;
 
     code = cm_IoctlGetVolumeStatus(&ioctlp->ioctl, userp, scp, &req);
@@ -1296,8 +1477,8 @@ smb_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return code;
 }
 
-afs_int32 
-smb_IoctlGetFid(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlGetFid(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     afs_int32 code;
     cm_scache_t *scp;
@@ -1312,7 +1493,7 @@ smb_IoctlGetFid(struct smb_ioctl *ioctlp, struct cm_user *userp)
         flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
 
     code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
-    if (code) 
+    if (code)
         return code;
 
     code = cm_IoctlGetFid(&ioctlp->ioctl, userp, scp, &req);
@@ -1322,8 +1503,8 @@ smb_IoctlGetFid(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return code;
 }
 
-afs_int32 
-smb_IoctlGetFileType(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlGetFileType(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     afs_int32 code;
     cm_scache_t *scp;
@@ -1340,13 +1521,13 @@ smb_IoctlGetFileType(struct smb_ioctl *ioctlp, struct cm_user *userp)
     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
         cm_fid_t fid;
         cm_SkipIoctlPath(&ioctlp->ioctl);
-        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
                   optionsp->fid.vnode, optionsp->fid.unique);
-        code = cm_GetSCache(&fid, &scp, userp, &req);
+        code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
     } else {
         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
     }
-    if (code) 
+    if (code)
         return code;
 
     code = cm_IoctlGetFileType(&ioctlp->ioctl, userp, scp, &req);
@@ -1356,8 +1537,8 @@ smb_IoctlGetFileType(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return code;
 }
 
-afs_int32 
-smb_IoctlGetOwner(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlGetOwner(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     afs_int32 code;
     cm_scache_t *scp;
@@ -1376,11 +1557,11 @@ smb_IoctlGetOwner(struct smb_ioctl *ioctlp, struct cm_user *userp)
         cm_SkipIoctlPath(&ioctlp->ioctl);
         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
                   optionsp->fid.vnode, optionsp->fid.unique);
-        code = cm_GetSCache(&fid, &scp, userp, &req);
+        code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
     } else {
         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
     }
-    if (code) 
+    if (code)
         return code;
 
     code = cm_IoctlGetOwner(&ioctlp->ioctl, userp, scp, &req);
@@ -1390,8 +1571,8 @@ smb_IoctlGetOwner(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return code;
 }
 
-afs_int32 
-smb_IoctlWhereIs(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlWhereIs(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     afs_int32 code;
     cm_scache_t *scp;
@@ -1410,11 +1591,11 @@ smb_IoctlWhereIs(struct smb_ioctl *ioctlp, struct cm_user *userp)
         cm_SkipIoctlPath(&ioctlp->ioctl);
         cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
                   optionsp->fid.vnode, optionsp->fid.unique);
-        code = cm_GetSCache(&fid, &scp, userp, &req);
+        code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
     } else {
         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
     }
-    if (code) 
+    if (code)
         return code;
 
     code = cm_IoctlWhereIs(&ioctlp->ioctl, userp, scp, &req);
@@ -1425,8 +1606,8 @@ smb_IoctlWhereIs(struct smb_ioctl *ioctlp, struct cm_user *userp)
 }
 
 
-afs_int32 
-smb_IoctlStatMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlStatMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     afs_int32 code;
     cm_scache_t *dscp;
@@ -1445,8 +1626,8 @@ smb_IoctlStatMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return code;
 }
 
-afs_int32 
-smb_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     afs_int32 code;
     cm_scache_t *dscp;
@@ -1455,7 +1636,7 @@ smb_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
     smb_InitReq(&req);
 
     code = smb_ParseIoctlPath(ioctlp, userp, &req, &dscp, 0);
-    if (code) 
+    if (code)
         return code;
 
     code = cm_IoctlDeleteMountPoint(&ioctlp->ioctl, userp, dscp, &req);
@@ -1465,30 +1646,30 @@ smb_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return code;
 }
 
-afs_int32 
-smb_IoctlCheckServers(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlCheckServers(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);  /* we don't care about the path */
 
     return cm_IoctlCheckServers(&ioctlp->ioctl, userp);
 }
 
-afs_int32 
-smb_IoctlGag(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlGag(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     /* we don't print anything superfluous, so we don't support the gag call */
     return CM_ERROR_INVAL;
 }
 
-afs_int32 
-smb_IoctlCheckVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlCheckVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);
 
     return cm_IoctlCheckVolumes(&ioctlp->ioctl, userp);
 }
 
-afs_int32 smb_IoctlSetCacheSize(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32 smb_IoctlSetCacheSize(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);
 
@@ -1496,64 +1677,72 @@ afs_int32 smb_IoctlSetCacheSize(struct smb_ioctl *ioctlp, struct cm_user *userp)
 }
 
 
-afs_int32 
-smb_IoctlTraceControl(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlTraceControl(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);
-       
+
     return cm_IoctlTraceControl(&ioctlp->ioctl, userp);
 }
 
-afs_int32 
-smb_IoctlGetCacheParms(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlGetCacheParms(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);
-       
+
     return cm_IoctlGetCacheParms(&ioctlp->ioctl, userp);
 }
 
-afs_int32 
-smb_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);
 
     return cm_IoctlGetCell(&ioctlp->ioctl, userp);
 }
 
-afs_int32 
-smb_IoctlNewCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlNewCell(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);
 
     return cm_IoctlNewCell(&ioctlp->ioctl, userp);
 }
 
-afs_int32 
-smb_IoctlGetWsCell(smb_ioctl_t *ioctlp, cm_user_t *userp)
+afs_int32
+smb_IoctlNewCell2(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlNewCell2(&ioctlp->ioctl, userp);
+}
+
+afs_int32
+smb_IoctlGetWsCell(smb_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);
 
     return cm_IoctlGetWsCell(&ioctlp->ioctl, userp);
 }
 
-afs_int32 
-smb_IoctlSysName(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlSysName(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);
 
     return cm_IoctlSysName(&ioctlp->ioctl, userp);
 }
 
-afs_int32 
-smb_IoctlGetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlGetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);
 
     return cm_IoctlGetCellStatus(&ioctlp->ioctl, userp);
 }
 
-afs_int32 
-smb_IoctlSetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlSetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);
 
@@ -1561,7 +1750,7 @@ smb_IoctlSetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
 }
 
 afs_int32
-smb_IoctlSetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
+smb_IoctlSetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);
 
@@ -1569,7 +1758,7 @@ smb_IoctlSetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
 }
 
 afs_int32
-smb_IoctlGetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
+smb_IoctlGetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);
 
@@ -1577,16 +1766,16 @@ smb_IoctlGetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
 }
 
 afs_int32
-smb_IoctlStoreBehind(struct smb_ioctl *ioctlp, struct cm_user *userp)
+smb_IoctlStoreBehind(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     /* we ignore default asynchrony since we only have one way
      * of doing this today.
      */
     return 0;
-}       
+}
 
 afs_int32
-smb_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
+smb_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     afs_int32 code;
     cm_scache_t *dscp;
@@ -1594,7 +1783,7 @@ smb_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
     cm_req_t req;
 
     smb_InitReq(&req);
-        
+
     code = smb_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
     if (code)
         return code;
@@ -1606,7 +1795,7 @@ smb_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
 }
 
 afs_int32
-smb_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
+smb_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     afs_int32 code;
     cm_scache_t *dscp;
@@ -1625,8 +1814,8 @@ smb_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return code;
 }
 
-afs_int32 
-smb_IoctlListlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlListlink(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     afs_int32 code;
     cm_scache_t *dscp;
@@ -1643,8 +1832,8 @@ smb_IoctlListlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return code;
 }
 
-afs_int32 
-smb_IoctlIslink(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlIslink(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {/*CHECK FOR VALID SYMLINK*/
     afs_int32 code;
     cm_scache_t *dscp;
@@ -1662,8 +1851,8 @@ smb_IoctlIslink(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return code;
 }
 
-afs_int32 
-smb_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     afs_int32 code;
     cm_scache_t *dscp;
@@ -1681,8 +1870,8 @@ smb_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
     return code;
 }
 
-afs_int32 
-smb_IoctlGetTokenIter(struct smb_ioctl *ioctlp, struct cm_user *userp)
+afs_int32
+smb_IoctlGetTokenIter(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);
 
@@ -1690,7 +1879,7 @@ smb_IoctlGetTokenIter(struct smb_ioctl *ioctlp, struct cm_user *userp)
 }
 
 afs_int32
-smb_IoctlGetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
+smb_IoctlGetToken(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);
 
@@ -1699,7 +1888,7 @@ smb_IoctlGetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
 
 
 afs_int32
-smb_IoctlDelToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
+smb_IoctlDelToken(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);
 
@@ -1708,7 +1897,7 @@ smb_IoctlDelToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
 
 
 afs_int32
-smb_IoctlDelAllToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
+smb_IoctlDelAllToken(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);
 
@@ -1717,7 +1906,7 @@ smb_IoctlDelAllToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
 
 
 afs_int32
-smb_IoctlMakeSubmount(struct smb_ioctl *ioctlp, struct cm_user *userp)
+smb_IoctlMakeSubmount(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);
 
@@ -1725,7 +1914,7 @@ smb_IoctlMakeSubmount(struct smb_ioctl *ioctlp, struct cm_user *userp)
 }
 
 afs_int32
-smb_IoctlGetRxkcrypt(struct smb_ioctl *ioctlp, struct cm_user *userp)
+smb_IoctlGetRxkcrypt(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);
 
@@ -1733,7 +1922,7 @@ smb_IoctlGetRxkcrypt(struct smb_ioctl *ioctlp, struct cm_user *userp)
 }
 
 afs_int32
-smb_IoctlSetRxkcrypt(struct smb_ioctl *ioctlp, struct cm_user *userp)
+smb_IoctlSetRxkcrypt(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);
 
@@ -1741,7 +1930,7 @@ smb_IoctlSetRxkcrypt(struct smb_ioctl *ioctlp, struct cm_user *userp)
 }
 
 afs_int32
-smb_IoctlRxStatProcess(struct smb_ioctl *ioctlp, struct cm_user *userp)
+smb_IoctlRxStatProcess(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);
 
@@ -1750,7 +1939,7 @@ smb_IoctlRxStatProcess(struct smb_ioctl *ioctlp, struct cm_user *userp)
 
 
 afs_int32
-smb_IoctlRxStatPeer(struct smb_ioctl *ioctlp, struct cm_user *userp)
+smb_IoctlRxStatPeer(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);
 
@@ -1758,7 +1947,7 @@ smb_IoctlRxStatPeer(struct smb_ioctl *ioctlp, struct cm_user *userp)
 }
 
 afs_int32
-smb_IoctlUnicodeControl(struct smb_ioctl *ioctlp, struct cm_user *userp)
+smb_IoctlUnicodeControl(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);
 
@@ -1766,7 +1955,7 @@ smb_IoctlUnicodeControl(struct smb_ioctl *ioctlp, struct cm_user *userp)
 }
 
 afs_int32
-smb_IoctlUUIDControl(struct smb_ioctl *ioctlp, struct cm_user *userp)
+smb_IoctlUUIDControl(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);
 
@@ -1775,7 +1964,7 @@ smb_IoctlUUIDControl(struct smb_ioctl *ioctlp, struct cm_user *userp)
 
 
 afs_int32
-smb_IoctlMemoryDump(struct smb_ioctl *ioctlp, struct cm_user *userp)
+smb_IoctlMemoryDump(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_SkipIoctlPath(&ioctlp->ioctl);
 
@@ -1783,7 +1972,7 @@ smb_IoctlMemoryDump(struct smb_ioctl *ioctlp, struct cm_user *userp)
 }
 
 afs_int32
-smb_IoctlPathAvailability(struct smb_ioctl *ioctlp, struct cm_user *userp)
+smb_IoctlPathAvailability(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     afs_int32 code;
     cm_scache_t *scp;
@@ -1800,13 +1989,13 @@ smb_IoctlPathAvailability(struct smb_ioctl *ioctlp, struct cm_user *userp)
     if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
         cm_fid_t fid;
         cm_SkipIoctlPath(&ioctlp->ioctl);
-        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume, 
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
                   optionsp->fid.vnode, optionsp->fid.unique);
-        code = cm_GetSCache(&fid, &scp, userp, &req);
+        code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
     } else {
         code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
     }
-    if (code) 
+    if (code)
         return code;
 
     code = cm_IoctlPathAvailability(&ioctlp->ioctl, userp, scp, &req);
@@ -1815,7 +2004,7 @@ smb_IoctlPathAvailability(struct smb_ioctl *ioctlp, struct cm_user *userp)
 }
 
 afs_int32
-smb_IoctlVolStatTest(struct smb_ioctl *ioctlp, struct cm_user *userp)
+smb_IoctlVolStatTest(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
 {
     cm_req_t req;
 
@@ -1825,3 +2014,220 @@ smb_IoctlVolStatTest(struct smb_ioctl *ioctlp, struct cm_user *userp)
 
     return cm_IoctlVolStatTest(&ioctlp->ioctl, userp, &req);
 }
+
+/*
+ * VIOC_SETOWNER
+ *
+ * This pioctl requires the use of the cm_ioctlQueryOptions_t structure.
+ *
+ */
+afs_int32
+smb_IoctlSetOwner(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+
+    smb_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp) {
+        if (CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+            flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+        if (CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+            cm_fid_t fid;
+            cm_SkipIoctlPath(&ioctlp->ioctl);
+            cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
+                       optionsp->fid.vnode, optionsp->fid.unique);
+            code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
+        } else {
+            code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+        }
+        if (code)
+            return code;
+
+        cm_IoctlSkipQueryOptions(&ioctlp->ioctl, userp);
+    }
+
+    code = cm_IoctlSetOwner(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+
+    return code;
+}
+
+/*
+ * VIOC_SETGROUP
+ *
+ * This pioctl requires the use of the cm_ioctlQueryOptions_t structure.
+ *
+ */
+afs_int32
+smb_IoctlSetGroup(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+
+    smb_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp) {
+        if (CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+            flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+        if (CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+            cm_fid_t fid;
+            cm_SkipIoctlPath(&ioctlp->ioctl);
+            cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
+                       optionsp->fid.vnode, optionsp->fid.unique);
+            code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
+        } else {
+            code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+        }
+        if (code)
+            return code;
+
+        cm_IoctlSkipQueryOptions(&ioctlp->ioctl, userp);
+    }
+
+    code = cm_IoctlSetGroup(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+
+    return code;
+}
+
+
+afs_int32
+smb_IoctlGetUnixMode(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+
+    smb_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+        cm_fid_t fid;
+        cm_SkipIoctlPath(&ioctlp->ioctl);
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
+                  optionsp->fid.vnode, optionsp->fid.unique);
+        code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
+    } else {
+        code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    if (code)
+        return code;
+
+    code = cm_IoctlGetUnixMode(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+
+    return code;
+}
+
+
+/*
+ * VIOC_SETUNIXMODE
+ *
+ * This pioctl requires the use of the cm_ioctlQueryOptions_t structure.
+ */
+afs_int32
+smb_IoctlSetUnixMode(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t *optionsp;
+    afs_uint32 flags = 0;
+
+    smb_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp) {
+        if (CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+            flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+        if (CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+            cm_fid_t fid;
+            cm_SkipIoctlPath(&ioctlp->ioctl);
+            cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
+                       optionsp->fid.vnode, optionsp->fid.unique);
+            code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
+        } else {
+            code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+        }
+        if (code)
+            return code;
+
+        cm_IoctlSkipQueryOptions(&ioctlp->ioctl, userp);
+    }
+
+    code = cm_IoctlSetUnixMode(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+
+    return code;
+}
+
+afs_int32
+smb_IoctlGetVerifyData(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlGetVerifyData(&ioctlp->ioctl);
+}
+
+afs_int32
+smb_IoctlSetVerifyData(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlSetVerifyData(&ioctlp->ioctl);
+}
+
+afs_int32
+smb_IoctlGetCallerAccess(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    afs_int32 code;
+    cm_scache_t *scp;
+    cm_req_t req;
+    cm_ioctlQueryOptions_t * optionsp;
+    afs_uint32 flags = 0;
+
+    smb_InitReq(&req);
+
+    optionsp = cm_IoctlGetQueryOptions(&ioctlp->ioctl, userp);
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_LITERAL(optionsp))
+        flags |= (optionsp->literal ? CM_PARSE_FLAG_LITERAL : 0);
+
+    if (optionsp && CM_IOCTL_QOPTS_HAVE_FID(optionsp)) {
+        cm_fid_t fid;
+        cm_SkipIoctlPath(&ioctlp->ioctl);
+        cm_SetFid(&fid, optionsp->fid.cell, optionsp->fid.volume,
+                  optionsp->fid.vnode, optionsp->fid.unique);
+        code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
+    } else {
+        code = smb_ParseIoctlPath(ioctlp, userp, &req, &scp, flags);
+    }
+    if (code)
+        return code;
+
+    code = cm_IoctlGetCallerAccess(&ioctlp->ioctl, userp, scp, &req);
+
+    cm_ReleaseSCache(scp);
+
+    return code;
+}