Windows: store data verification mode
authorJeffrey Altman <jaltman@your-file-system.com>
Sun, 22 Jan 2012 23:42:32 +0000 (18:42 -0500)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Mon, 23 Jan 2012 05:25:09 +0000 (21:25 -0800)
Over the lifetime of OpenAFS a number of bugs have been discovered
that can result in data corruption.  This new mode (Windows only)
will double check that the data received by the file server does
in fact match the data that was written by the cache manager.

After a successful StoreData and status merge but before the BIOD
is released, a fetchdata is issued to read the data written by the
cache manager.  If the data fails to match, the StoreData operation
is repeated.

Data verification mode can be queried with "fs getverify" and set
with "fs setverify {on, off}".  The default value can be set with
the TransarcAFSDaemon\Parameters DWORD "VerifyData" registry value.

By default verification is disabled.

Change-Id: Ic99c1692e6e78790e65ae600c3e428a79df59370
Reviewed-on: http://gerrit.openafs.org/6601
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Jeffrey Altman <jaltman@secure-endpoints.com>
Tested-by: Jeffrey Altman <jaltman@secure-endpoints.com>

12 files changed:
src/WINNT/afsd/afsd.h
src/WINNT/afsd/afsd_init.c
src/WINNT/afsd/cm_dcache.c
src/WINNT/afsd/cm_dcache.h
src/WINNT/afsd/cm_ioctl.c
src/WINNT/afsd/cm_ioctl.h
src/WINNT/afsd/fs.c
src/WINNT/afsd/smb_iocons.h
src/WINNT/afsd/smb_ioctl.c
src/WINNT/afsd/smb_ioctl.h
src/WINNT/afsrdr/user/RDRIoctl.c
src/WINNT/afsrdr/user/RDRIoctl.h

index 516e22c..65f2d18 100644 (file)
@@ -124,6 +124,8 @@ extern afs_uint32 smb_Enabled;
 
 extern int cm_virtualCache;
 
+extern afs_int32 cm_verifyData;
+
 #define DFS_SUPPORT 1
 #define LOG_PACKET 1
 #undef  NOTSERVICE
index 8d195bf..e6d9da2 100644 (file)
@@ -76,6 +76,7 @@ int cm_readonlyVolumeVersioning = 0;
 int cm_logChunkSize;
 int cm_chunkSize;
 int cm_virtualCache = 0;
+afs_int32 cm_verifyData = 0;
 
 int smb_UseV3 = 1;
 afs_uint32 smb_Enabled = 1;
@@ -1020,7 +1021,12 @@ afsd_InitCM(char **reasonP)
     else
        LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_CRYPT_OFF);
 
-    dummyLen = sizeof(cryptall);
+    dummyLen = sizeof(cm_verifyData);
+    code = RegQueryValueEx(parmKey, "VerifyData", NULL, NULL,
+                           (BYTE *) &cm_verifyData, &dummyLen);
+    afsi_log("VerifyData is %s", cm_verifyData?"on":"off");
+
+    dummyLen = sizeof(cm_anonvldb);
     code = RegQueryValueEx(parmKey, "ForceAnonVLDB", NULL, NULL,
                             (BYTE *) &cm_anonvldb, &dummyLen);
     afsi_log("CM ForceAnonVLDB is %s", cm_anonvldb ? "on" : "off");
index 79fe80b..96e5dd6 100644 (file)
@@ -54,6 +54,7 @@ long cm_BufWrite(void *vscp, osi_hyper_t *offsetp, long length, long flags,
     cm_scache_t *scp = vscp;
     afs_int32 nbytes;
     afs_int32 save_nbytes;
+    cm_scache_t save_scache;
     long temp;
     AFSFetchStatus outStatus;
     AFSStoreStatus inStatus;
@@ -152,11 +153,14 @@ long cm_BufWrite(void *vscp, osi_hyper_t *offsetp, long length, long flags,
         require_64bit_ops = 1;
     }
 
+    /* now we're ready to do the store operation */
+  retry_rpc:
     InterlockedIncrement(&scp->activeRPCs);
     lock_ReleaseWrite(&scp->rw);
 
-    /* now we're ready to do the store operation */
     save_nbytes = nbytes;
+    save_scache = *scp;
+
     do {
         code = cm_ConnFromFID(&scp->fid, userp, reqp, &connp);
         if (code)
@@ -423,6 +427,15 @@ long cm_BufWrite(void *vscp, osi_hyper_t *offsetp, long length, long flags,
             _InterlockedOr(&scp->flags, CM_SCACHEFLAG_OVERQUOTA);
     }
 
+    if ( cm_verifyData )
+    {
+        if (!cm_VerifyStoreData(&biod, &save_scache)) {
+            /* file server content doesn't match what we sent. */
+            nbytes = save_nbytes;
+            goto retry_rpc;
+        }
+    }
+
     cm_ReleaseBIOD(&biod, 1, code, 1);
 
   exit_storedata_excl:
@@ -1009,6 +1022,7 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
     /* clear things out */
     biop->scp = scp;                   /* do not hold; held by caller */
     biop->userp = userp;                /* do not hold; held by caller */
+    biop->reqp = reqp;
     biop->offset = *inOffsetp;
     biop->length = 0;
     biop->bufListp = NULL;
@@ -1080,6 +1094,10 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
     /* put this element in the list */
     qdp = osi_QDAlloc();
     osi_SetQData(qdp, bufp);
+
+    if ( cm_verifyData )
+        buf_ComputeCheckSum(bufp);
+
     /* don't have to hold bufp, since held by buf_Find above */
     osi_QAddH((osi_queue_t **) &biop->bufListp,
               (osi_queue_t **) &biop->bufListEndp,
@@ -1145,6 +1163,10 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
          */
         qdp = osi_QDAlloc();
         osi_SetQData(qdp, bufp);
+
+        if ( cm_verifyData )
+            buf_ComputeCheckSum(bufp);
+
         /* no buf_hold necessary, since we have it held from buf_Find */
         osi_QAddT((osi_queue_t **) &biop->bufListp,
                   (osi_queue_t **) &biop->bufListEndp,
@@ -1205,6 +1227,10 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
          */
         qdp = osi_QDAlloc();
         osi_SetQData(qdp, bufp);
+
+        if ( cm_verifyData )
+            buf_ComputeCheckSum(bufp);
+
         /* no buf_hold necessary, since we have it held from buf_Find */
         osi_QAddH((osi_queue_t **) &biop->bufListp,
                   (osi_queue_t **) &biop->bufListEndp,
@@ -2509,3 +2535,269 @@ long cm_GetData(cm_scache_t *scp, osi_hyper_t *offsetp, char *datap, int data_le
 
     return code;
 }
+
+/*
+ * cm_VerifyStoreData.   Function passed a rw locked cm_scache_t and a store data biod.
+ *
+ * Return 1 if the data verifies; 0 if not.
+ */
+
+long
+cm_VerifyStoreData(cm_bulkIO_t *biod, cm_scache_t *savedScp)
+{
+    long code=0, code1=0;
+    afs_uint32 nbytes;                 /* bytes in transfer */
+    afs_uint32 nbytes_hi = 0;           /* high-order 32 bits of bytes in transfer */
+    afs_uint64 length_found = 0;
+    long rbytes;                       /* bytes in rx_Read call */
+    long temp;
+    AFSFetchStatus afsStatus;
+    AFSCallBack callback;
+    AFSVolSync volSync;
+    AFSFid tfid;
+    struct rx_call *rxcallp;
+    struct rx_connection *rxconnp;
+    cm_conn_t *connp;
+    int require_64bit_ops = 0;
+    int call_was_64bit = 0;
+    int fs_fetchdata_offset_bug = 0;
+    int first_read = 1;
+    int scp_locked = 1;
+    char * bufferp = malloc(biod->length);
+    long verified = 0;
+    cm_scache_t *scp = biod->scp;
+    cm_user_t *userp = biod->userp;
+    cm_req_t *reqp = biod->reqp;
+    afs_uint64 dataVersion = scp->dataVersion;
+
+    memset(&volSync, 0, sizeof(volSync));
+    memset(bufferp, 0, biod->length);
+
+    cm_AFSFidFromFid(&tfid, &scp->fid);
+
+    if (LargeIntegerGreaterThan(LargeIntegerAdd(biod->offset,
+                                                ConvertLongToLargeInteger(biod->length)),
+                                ConvertLongToLargeInteger(LONG_MAX))) {
+        require_64bit_ops = 1;
+    }
+
+    InterlockedIncrement(&scp->activeRPCs);
+    osi_Log2(afsd_logp, "cm_VerifyStoreData: fetching data scp %p DV 0x%x", scp, scp->dataVersion);
+
+    if (scp_locked) {
+        lock_ReleaseWrite(&scp->rw);
+        scp_locked = 0;
+    }
+
+    /* now make the call */
+    do {
+        code = cm_ConnFromFID(&scp->fid, userp, reqp, &connp);
+        if (code)
+            continue;
+
+        rxconnp = cm_GetRxConn(connp);
+        rxcallp = rx_NewCall(rxconnp);
+        rx_PutConnection(rxconnp);
+
+        nbytes = nbytes_hi = 0;
+
+        if (SERVERHAS64BIT(connp)) {
+            call_was_64bit = 1;
+
+            osi_Log4(afsd_logp, "CALL FetchData64 scp 0x%p, off 0x%x:%08x, size 0x%x",
+                     scp, biod->offset.HighPart, biod->offset.LowPart, biod->length);
+
+            code = StartRXAFS_FetchData64(rxcallp, &tfid, biod->offset.QuadPart, biod->length);
+
+            if (code == 0) {
+                temp = rx_Read32(rxcallp, &nbytes_hi);
+                if (temp == sizeof(afs_int32)) {
+                    nbytes_hi = ntohl(nbytes_hi);
+                } else {
+                    nbytes_hi = 0;
+                   code = rx_Error(rxcallp);
+                    code1 = rx_EndCall(rxcallp, code);
+                    rxcallp = NULL;
+                }
+            }
+        } else {
+            call_was_64bit = 0;
+        }
+
+        if (code == RXGEN_OPCODE || !SERVERHAS64BIT(connp)) {
+            if (require_64bit_ops) {
+                osi_Log0(afsd_logp, "Skipping FetchData.  Operation requires FetchData64");
+                code = CM_ERROR_TOOBIG;
+            } else {
+                if (!rxcallp) {
+                    rxconnp = cm_GetRxConn(connp);
+                    rxcallp = rx_NewCall(rxconnp);
+                    rx_PutConnection(rxconnp);
+                }
+
+                osi_Log3(afsd_logp, "CALL FetchData scp 0x%p, off 0x%x, size 0x%x",
+                         scp, biod->offset.LowPart, biod->length);
+
+                code = StartRXAFS_FetchData(rxcallp, &tfid, biod->offset.LowPart, biod->length);
+
+                SET_SERVERHASNO64BIT(connp);
+            }
+        }
+
+        if (code == 0) {
+            temp  = rx_Read32(rxcallp, &nbytes);
+            if (temp == sizeof(afs_int32)) {
+                nbytes = ntohl(nbytes);
+                FillInt64(length_found, nbytes_hi, nbytes);
+                if (length_found > biod->length) {
+                    /*
+                     * prior to 1.4.12 and 1.5.65 the file server would return
+                     * (filesize - offset) if the requested offset was greater than
+                     * the filesize.  The correct return value would have been zero.
+                     * Force a retry by returning an RX_PROTOCOL_ERROR.  If the cause
+                     * is a race between two RPCs issues by this cache manager, the
+                     * correct thing will happen the second time.
+                     */
+                    osi_Log0(afsd_logp, "cm_GetData length_found > biod.length");
+                    fs_fetchdata_offset_bug = 1;
+                }
+            } else {
+                osi_Log1(afsd_logp, "cm_GetData rx_Read32 returns %d != 4", temp);
+                code = (rx_Error(rxcallp) < 0) ? rx_Error(rxcallp) : RX_PROTOCOL_ERROR;
+            }
+        }
+        /* for the moment, nbytes_hi will always be 0 if code == 0
+           because data_length is a 32-bit quantity. */
+
+        if (code == 0) {
+            /* fill length_found of data from the pipe into the pages.
+             * When we stop, qdp will point at the last page we're
+             * dealing with, and bufferp will tell us where we
+             * stopped.  We'll need this info below when we clear
+             * the remainder of the last page out (and potentially
+             * clear later pages out, if we fetch past EOF).
+             */
+            while (length_found > 0) {
+                /* assert that there are still more buffers;
+                 * our check above for length_found being less than
+                 * data_length should ensure this.
+                 */
+                osi_assertx(bufferp != NULL, "null cm_buf_t");
+
+                /* read rbytes of data */
+                rbytes = (afs_uint32)(length_found > biod->length ? biod->length : length_found);
+                temp = rx_Read(rxcallp, bufferp, rbytes);
+                if (temp < rbytes) {
+                    /*
+                     * If the file server returned (filesize - offset),
+                     * then the first rx_Read will return zero octets of data.
+                     * If it does, do not treat it as an error.  Correct the
+                     * length_found and continue as if the file server said
+                     * it was sending us zero octets of data.
+                     */
+                    if (fs_fetchdata_offset_bug && first_read)
+                        length_found = 0;
+                    else
+                        code = (rx_Error(rxcallp) < 0) ? rx_Error(rxcallp) : RX_PROTOCOL_ERROR;
+                    break;
+                }
+                first_read = 0;
+
+                /* and adjust counters */
+                length_found -= temp;
+            }
+        }
+
+        if (code == 0) {
+            if (call_was_64bit)
+                code = EndRXAFS_FetchData64(rxcallp, &afsStatus, &callback, &volSync);
+            else
+                code = EndRXAFS_FetchData(rxcallp, &afsStatus, &callback, &volSync);
+        } else {
+            if (call_was_64bit)
+                osi_Log1(afsd_logp, "CALL EndRXAFS_FetchData64 skipped due to error %d", code);
+            else
+                osi_Log1(afsd_logp, "CALL EndRXAFS_FetchData skipped due to error %d", code);
+        }
+
+        if (rxcallp)
+            code1 = rx_EndCall(rxcallp, code);
+
+        if (code1 == RXKADUNKNOWNKEY)
+            osi_Log0(afsd_logp, "CALL EndCall returns RXKADUNKNOWNKEY");
+
+        /* If we are avoiding a file server bug, ignore the error state */
+        if (fs_fetchdata_offset_bug && first_read && length_found == 0 && code == -451) {
+            /* Clone the current status info and clear the error state */
+            scp_locked = cm_CloneStatus(scp, userp, scp_locked, &afsStatus, &volSync);
+            if (scp_locked) {
+                lock_ReleaseWrite(&scp->rw);
+                scp_locked = 0;
+            }
+            code = 0;
+        /* Prefer the error value from FetchData over rx_EndCall */
+        } else if (code == 0 && code1 != 0)
+            code = code1;
+        osi_Log0(afsd_logp, "CALL FetchData DONE");
+
+    } while (cm_Analyze(connp, userp, reqp, &scp->fid, 0, &volSync, NULL, NULL, code));
+
+  fetchingcompleted:
+    code = cm_MapRPCError(code, reqp);
+
+    if (!scp_locked)
+        lock_ObtainWrite(&scp->rw);
+
+    if (code == 0)
+        cm_MergeStatus(NULL, scp, &afsStatus, &volSync, userp, reqp, CM_MERGEFLAG_FETCHDATA);
+    else
+        InterlockedDecrement(&scp->activeRPCs);
+
+    if (code == 0)
+    {
+        if (dataVersion == scp->dataVersion)
+        {
+            osi_queueData_t *qdp = NULL;
+            cm_buf_t *bufp;
+            afs_uint32 buf_offset;
+            afs_uint32 bytes_compared = 0;
+            afs_uint32 cmp_length;
+            int md5_match = 1;
+
+            verified = 1;
+
+            while ( bytes_compared < biod->length )
+            {
+                if (qdp == NULL) {
+                    qdp = biod->bufListEndp;
+                    buf_offset = biod->offset.LowPart % cm_data.buf_blockSize;
+                } else {
+                    qdp = (osi_queueData_t *) osi_QPrev(&qdp->q);
+                    buf_offset = 0;
+                }
+                cmp_length =  cm_data.buf_blockSize - buf_offset;
+
+                osi_assertx(qdp != NULL, "null osi_queueData_t");
+                bufp = osi_GetQData(qdp);
+
+                if (memcmp(bufferp+bytes_compared, bufp->datap+buf_offset, cmp_length) != 0)
+                {
+                    verified = 0;
+                    md5_match = buf_ValidateCheckSum(bufp);
+
+                    osi_Log5(afsd_logp, "cm_VerifyDataStore verification failed scp 0x%p bufp 0x%p offset 0x%x:%08x md5 %s",
+                             scp, bufp, bufp->offset.HighPart, bufp->offset.LowPart, md5_match ? "match" : "no-match");
+                }
+                bytes_compared += cmp_length;
+            }
+        } else {
+            osi_Log4(afsd_logp, "cm_VerifyStoreData unable to verify due to data version change scp 0x%p, off 0x%x:%08x, size 0x%x",
+                     scp, biod->offset.HighPart, biod->offset.LowPart, biod->length);
+        }
+    }
+
+    if (bufferp)
+        free(bufferp);
+
+    return verified;
+}
index dbe7539..5fea183 100644 (file)
@@ -65,4 +65,6 @@ extern long cm_ShutdownDCache(void);
 extern long cm_BufWrite(void *vscp, osi_hyper_t *offsetp, long length, long flags,
                  cm_user_t *userp, cm_req_t *reqp);
 
+extern long cm_VerifyStoreData(cm_bulkIO_t *biod, cm_scache_t *scp);
+
 #endif /*  OPENAFS_WINNT_AFSD_CM_DCACHE_H */
index c5ea701..078ef6a 100644 (file)
@@ -3564,3 +3564,31 @@ cm_IoctlSetUnixMode(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t
     }
     return code;
 }
+
+/*
+ * VIOC_GETVERIFYDATA internals.
+ *
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32
+cm_IoctlGetVerifyData(cm_ioctl_t *ioctlp)
+{
+    memcpy(ioctlp->outDatap, &cm_verifyData, sizeof(cm_verifyData));
+    ioctlp->outDatap += sizeof(cm_verifyData);
+
+    return 0;
+}
+
+/*
+ * VIOC_SETVERIFYDATA internals.
+ *
+ * Assumes that pioctl path has been parsed or skipped.
+ */
+afs_int32
+cm_IoctlSetVerifyData(cm_ioctl_t *ioctlp)
+{
+    memcpy(&cm_verifyData, ioctlp->inDatap, sizeof(cm_verifyData));
+
+    return 0;
+}
+
index 605f5e7..3ddbc1d 100644 (file)
@@ -286,6 +286,10 @@ extern afs_int32 cm_IoctlGetUnixMode(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_sc
 
 extern afs_int32 cm_IoctlSetUnixMode(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
 
+extern afs_int32 cm_IoctlGetVerifyData(cm_ioctl_t *ioctlp);
+
+extern afs_int32 cm_IoctlSetVerifyData(cm_ioctl_t *ioctlp);
+
 #endif /* __CM_IOCTL_INTERFACES_ONLY__ */
 
 #endif /*  OPENAFS_WINNT_AFSD_CM_IOCTL_H */
index e3a17cf..be1e3c4 100644 (file)
@@ -5007,6 +5007,77 @@ ChModCmd(struct cmd_syndesc *as, void *arock)
     return error;
 }
 
+static afs_int32
+SetDataVerifyCmd(struct cmd_syndesc *as, void *arock)
+{
+    afs_int32 code = 0, flag;
+    struct ViceIoctl blob;
+    char *tp;
+
+#ifdef WIN32
+    if ( !fs_IsAdmin() ) {
+        fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
+        return EACCES;
+    }
+#endif /* WIN32 */
+
+    tp = as->parms[0].items->data;
+    if (strcmp(tp, "on") == 0)
+      flag = 1;
+    else if (strcmp(tp, "off") == 0)
+      flag = 0;
+    else {
+      fprintf (stderr, "%s: %s must be \"on\" or \"off\".\n", pn, tp);
+      return EINVAL;
+    }
+
+    blob.in = (char *) &flag;
+    blob.in_size = sizeof(flag);
+    blob.out_size = 0;
+    code = pioctl_utf8(0, VIOC_SETVERIFYDATA, &blob, 1);
+    if (code)
+        fs_Die(code, NULL);
+    return 0;
+}
+
+static afs_int32
+GetDataVerifyCmd(struct cmd_syndesc *as, void *arock)
+{
+    afs_int32 code = 0, flag;
+    struct ViceIoctl blob;
+    char *tp;
+    errno_t err;
+
+    blob.in = NULL;
+    blob.in_size = 0;
+    blob.out_size = sizeof(flag);
+    blob.out = space;
+
+    code = pioctl_utf8(0, VIOC_GETVERIFYDATA, &blob, 1);
+
+    if (code || blob.out_size != sizeof(flag))
+        fs_Die(code, NULL);
+    else {
+        tp = space;
+#if _MSC_VER < 1400
+        memcpy(&flag, tp, sizeof(afs_int32));
+#else
+        err = memcpy_s(&flag, sizeof(flag), tp, sizeof(afs_int32));
+        if ( err ) {
+            fprintf (stderr, "memcpy_s failure on flag");
+            exit(1);
+        }
+#endif
+
+      printf("Data verify mode is currently ");
+      if (flag == 1)
+        printf("on.\n");
+      else
+        printf("off.\n");
+    }
+    return 0;
+}
+
 #ifndef WIN32
 #include "AFS_component_version_number.c"
 #endif
@@ -5341,6 +5412,11 @@ int wmain(int argc, wchar_t **wargv)
     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
     cmd_AddParm(ts, "-literal", CMD_FLAG, CMD_OPTIONAL, "literal evaluation of mountpoints and symlinks");
 
+    ts = cmd_CreateSyntax("setverify", SetDataVerifyCmd, NULL, "set cache manager data verify mode");
+    cmd_AddParm(ts, "-verify", CMD_SINGLE, 0, "on or off");
+
+    ts = cmd_CreateSyntax("getverify", GetDataVerifyCmd, NULL, "get cache manager data verify mode");
+
     code = cmd_Dispatch(argc, argv);
 
     if (rxInitDone)
index 3015aa6..b8b2c3c 100644 (file)
@@ -101,6 +101,8 @@ struct sbstruct {
 #define VIOCNEWCELL2                    0x37
 #define VIOC_GETUNIXMODE                0x38
 #define VIOC_SETUNIXMODE                0x39
+#define VIOC_GETVERIFYDATA              0x3A
+#define VIOC_SETVERIFYDATA              0x3B
 
 #define VIOC_VOLSTAT_TEST               0x3F
 
index e4a72f3..aa692ad 100644 (file)
@@ -96,6 +96,8 @@ smb_InitIoctl(void)
     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;
 }
 
 /* called to make a fid structure into an IOCTL fid structure */
@@ -2179,3 +2181,19 @@ smb_IoctlSetUnixMode(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32
     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);
+}
+
index 9defd83..4ba8f4b 100644 (file)
@@ -211,4 +211,8 @@ extern afs_int32 smb_IoctlGetUnixMode(struct smb_ioctl *ioctlp, struct cm_user *
 
 extern afs_int32 smb_IoctlSetUnixMode(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 flags);
 
+extern afs_int32 smb_IoctlGetVerifyData(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 flags);
+
+extern afs_int32 smb_IoctlSetVerifyData(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 flags);
+
 #endif /*  OPENAFS_WINNT_AFSD_SMB_IOCTL_H */
index 09c895b..89c3e67 100644 (file)
@@ -139,6 +139,8 @@ RDR_InitIoctl(void)
     RDR_ioctlProcsp[VIOCNEWCELL2] = RDR_IoctlNewCell2;
     RDR_ioctlProcsp[VIOC_GETUNIXMODE] = RDR_IoctlGetUnixMode;
     RDR_ioctlProcsp[VIOC_SETUNIXMODE] = RDR_IoctlSetUnixMode;
+    RDR_ioctlProcsp[VIOC_GETVERIFYDATA] = RDR_IoctlGetVerifyData;
+    RDR_ioctlProcsp[VIOC_SETVERIFYDATA] = RDR_IoctlSetVerifyData;
 }
 
 /* called to make a fid structure into an IOCTL fid structure */
@@ -1969,3 +1971,19 @@ RDR_IoctlSetUnixMode(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32
 
     return code;
 }
+
+afs_int32
+RDR_IoctlGetVerifyData(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlGetVerifyData(&ioctlp->ioctl);
+}
+
+afs_int32
+RDR_IoctlSetVerifyData(struct RDR_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pflags)
+{
+    cm_SkipIoctlPath(&ioctlp->ioctl);
+
+    return cm_IoctlSetVerifyData(&ioctlp->ioctl);
+}
index 9944627..821431e 100644 (file)
@@ -191,5 +191,9 @@ extern afs_int32 RDR_IoctlGetUnixMode(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs
 
 extern afs_int32 RDR_IoctlSetUnixMode(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
 
+extern afs_int32 RDR_IoctlGetVerifyData(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
+extern afs_int32 RDR_IoctlSetVerifyData(RDR_ioctl_t *ioctlp, cm_user_t *userp, afs_uint32 pflags);
+
 #endif