From dfd0c2acc103cd2881bbfecd923c05012001e12a Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Sun, 22 Jan 2012 18:42:32 -0500 Subject: [PATCH] Windows: store data verification mode 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 Reviewed-by: Jeffrey Altman Tested-by: Jeffrey Altman --- src/WINNT/afsd/afsd.h | 2 + src/WINNT/afsd/afsd_init.c | 8 +- src/WINNT/afsd/cm_dcache.c | 294 ++++++++++++++++++++++++++++++- src/WINNT/afsd/cm_dcache.h | 2 + src/WINNT/afsd/cm_ioctl.c | 28 +++ src/WINNT/afsd/cm_ioctl.h | 4 + src/WINNT/afsd/fs.c | 76 ++++++++ src/WINNT/afsd/smb_iocons.h | 2 + src/WINNT/afsd/smb_ioctl.c | 18 ++ src/WINNT/afsd/smb_ioctl.h | 4 + src/WINNT/afsrdr/user/RDRIoctl.c | 18 ++ src/WINNT/afsrdr/user/RDRIoctl.h | 4 + 12 files changed, 458 insertions(+), 2 deletions(-) diff --git a/src/WINNT/afsd/afsd.h b/src/WINNT/afsd/afsd.h index 516e22c8c..65f2d1811 100644 --- a/src/WINNT/afsd/afsd.h +++ b/src/WINNT/afsd/afsd.h @@ -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 diff --git a/src/WINNT/afsd/afsd_init.c b/src/WINNT/afsd/afsd_init.c index 8d195bf4c..e6d9da2da 100644 --- a/src/WINNT/afsd/afsd_init.c +++ b/src/WINNT/afsd/afsd_init.c @@ -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"); diff --git a/src/WINNT/afsd/cm_dcache.c b/src/WINNT/afsd/cm_dcache.c index 79fe80b6a..96e5dd6ac 100644 --- a/src/WINNT/afsd/cm_dcache.c +++ b/src/WINNT/afsd/cm_dcache.c @@ -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; +} diff --git a/src/WINNT/afsd/cm_dcache.h b/src/WINNT/afsd/cm_dcache.h index dbe753990..5fea18374 100644 --- a/src/WINNT/afsd/cm_dcache.h +++ b/src/WINNT/afsd/cm_dcache.h @@ -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 */ diff --git a/src/WINNT/afsd/cm_ioctl.c b/src/WINNT/afsd/cm_ioctl.c index c5ea70113..078ef6aee 100644 --- a/src/WINNT/afsd/cm_ioctl.c +++ b/src/WINNT/afsd/cm_ioctl.c @@ -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; +} + diff --git a/src/WINNT/afsd/cm_ioctl.h b/src/WINNT/afsd/cm_ioctl.h index 605f5e7f5..3ddbc1d28 100644 --- a/src/WINNT/afsd/cm_ioctl.h +++ b/src/WINNT/afsd/cm_ioctl.h @@ -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 */ diff --git a/src/WINNT/afsd/fs.c b/src/WINNT/afsd/fs.c index e3a17cf00..be1e3c492 100644 --- a/src/WINNT/afsd/fs.c +++ b/src/WINNT/afsd/fs.c @@ -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) diff --git a/src/WINNT/afsd/smb_iocons.h b/src/WINNT/afsd/smb_iocons.h index 3015aa695..b8b2c3c7f 100644 --- a/src/WINNT/afsd/smb_iocons.h +++ b/src/WINNT/afsd/smb_iocons.h @@ -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 diff --git a/src/WINNT/afsd/smb_ioctl.c b/src/WINNT/afsd/smb_ioctl.c index e4a72f364..aa692ade1 100644 --- a/src/WINNT/afsd/smb_ioctl.c +++ b/src/WINNT/afsd/smb_ioctl.c @@ -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); +} + diff --git a/src/WINNT/afsd/smb_ioctl.h b/src/WINNT/afsd/smb_ioctl.h index 9defd83b6..4ba8f4b3d 100644 --- a/src/WINNT/afsd/smb_ioctl.h +++ b/src/WINNT/afsd/smb_ioctl.h @@ -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 */ diff --git a/src/WINNT/afsrdr/user/RDRIoctl.c b/src/WINNT/afsrdr/user/RDRIoctl.c index 09c895bfd..89c3e67a5 100644 --- a/src/WINNT/afsrdr/user/RDRIoctl.c +++ b/src/WINNT/afsrdr/user/RDRIoctl.c @@ -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); +} diff --git a/src/WINNT/afsrdr/user/RDRIoctl.h b/src/WINNT/afsrdr/user/RDRIoctl.h index 9944627e7..821431e91 100644 --- a/src/WINNT/afsrdr/user/RDRIoctl.h +++ b/src/WINNT/afsrdr/user/RDRIoctl.h @@ -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 -- 2.39.5