#include #include #include #include // _alloca #include // def'n of OBJREF //------------------------------------------------------------------------- // convenient mappings #define ORCST(objref) objref.u_objref.u_custom #define ORSTD(objref) objref.u_objref.u_standard #define ORHDL(objref) objref.u_objref.u_handler // bits that must be zero in the flags fields #define OBJREF_RSRVD_MBZ ~(OBJREF_STANDARD | OBJREF_HANDLER | OBJREF_CUSTOM) #define SORF_RSRVD_MBZ ~(SORF_NOPING | SORF_OXRES1 | SORF_OXRES2 | \ SORF_OXRES3 | SORF_OXRES4 | SORF_OXRES5 | \ SORF_OXRES6 | SORF_OXRES7 | SORF_OXRES8) // Internal Uses of the reserved SORF_OXRES flags. // SORF_TBLWEAK is needed so that RMD works correctly on TABLEWEAK // marshaling, so it is ignored by unmarshalers. Therefore, we use one of // the bits reserved for the object exporter that must be ignored by // unmarshalers. // // SORF_WEAKREF is needed for container weak references, when handling // an IRemUnknown::RemQueryInterface on a weak interface. This is a strictly // local (windows) machine protocol, so we use a reserved bit. // // SORF_NONNDR is needed for interop of 16bit custom (non-NDR) marshalers // with 32bit, since the 32bit guys want to use MIDL (NDR) to talk to other // 32bit processes and remote processes, but the custom (non-NDR) format to // talk to local 16bit guys. In particular, this is to support OLE Automation. // // SORF_FREETHREADED is needed when we create a proxy to the SCM interface // in the apartment model. All apartments can use the same proxy so we avoid // the test for calling on the correct thread. #define SORF_TBLWEAK SORF_OXRES1 // (table) weak reference #define SORF_WEAKREF SORF_OXRES2 // (normal) weak reference #define SORF_NONNDR SORF_OXRES3 // stub does not use NDR marshaling #define SORF_FREETHREADED SORF_OXRES4 // proxy may be used on any thread // definition to simplify coding const DWORD MSHLFLAGS_TABLE = MSHLFLAGS_TABLESTRONG | MSHLFLAGS_TABLEWEAK; const DWORD MSHLFLAGS_USER_MASK = MSHLFLAGS_NORMAL | MSHLFLAGS_TABLE | MSHLFLAGS_NOPING; // return codes #define INVALID_SORFFLAG 90000001 #define INVALID_REFCNT 90000002 #define INVALID_MSHLFLAG 90000003 //------------------------------------------------------------------------- //+------------------------------------------------------------------------- // // Function: StRead // // Synopsis: Stream read that only succeeds if all requested bytes read // // Arguments: [pStm] -- source stream // [pvBuffer] -- destination buffer // [ulcb] -- bytes to read // // Returns: S_OK if successful, else error code // //-------------------------------------------------------------------------- HRESULT StRead(IStream *pStm, void *pvBuffer, ULONG ulcb) { ULONG cbRead; HRESULT hr = pStm->Read(pvBuffer, ulcb, &cbRead); if (SUCCEEDED(hr)) { if (ulcb != cbRead) { hr = STG_E_READFAULT; } } return hr; } void DbgDumpSTD(STDOBJREF *pStd) { } //+------------------------------------------------------------------------- // // Function: ReadObjRef // // Synopsis: Reads an OBJREF from the stream // // Arguments: [pStm] -- source stream // [objref] -- destination buffer // // Returns: S_OK if successful, else error code // //-------------------------------------------------------------------------- HRESULT ReadObjRef(IStream *pStm, OBJREF &objref, STDOBJREF **ppStd) { HRESULT hr = StRead(pStm, &objref, 2*sizeof(ULONG)+sizeof(IID)); if (SUCCEEDED(hr)) { if ((objref.signature != OBJREF_SIGNATURE) || (objref.flags & OBJREF_RSRVD_MBZ) || (objref.flags == 0)) { // the objref signature is bad, or one of the reserved // bits in the flags is set, or none of the required bits // in the flags is set. the objref cant be interpreted so // fail the call. return E_UNEXPECTED; // BUGBUG: } // compute the size of the remainder of the objref and // include the size fields for the resolver string array STDOBJREF *pStd = &ORSTD(objref).std; DUALSTRINGARRAY *psa; ULONG cbToRead; if (objref.flags & OBJREF_STANDARD) { cbToRead = sizeof(STDOBJREF) + sizeof(ULONG); psa = &ORSTD(objref).saResAddr; } else if (objref.flags & OBJREF_HANDLER) { cbToRead = sizeof(STDOBJREF) + sizeof(CLSID) + sizeof(ULONG); psa = &ORHDL(objref).saResAddr; } else if (objref.flags & OBJREF_CUSTOM) { cbToRead = sizeof(CLSID) + sizeof(DWORD); // clsid + data size psa = NULL; } // return ptr to STDOBJREF *ppStd = pStd; // read the rest of the (fixed sized) objref from the stream hr = StRead(pStm, pStd, cbToRead); if (SUCCEEDED(hr) && psa) { // Non custom interface. Make sure the resolver string array // has some sensible values. if (psa->wSecurityOffset >= psa->wNumEntries) { hr = E_UNEXPECTED; // BUGBUG: correct return code } } if (SUCCEEDED(hr) && psa) { // Non custom interface. The data that follows is a variable // sized string array. Allocate memory for it and then read it. DbgDumpSTD(pStd); cbToRead = psa->wNumEntries * sizeof(WCHAR); DUALSTRINGARRAY *psaNew = (DUALSTRINGARRAY *) _alloca(cbToRead + sizeof(ULONG)); if (psaNew != NULL) { // update the size fields and read in the rest of the data psaNew->wSecurityOffset = psa->wSecurityOffset; psaNew->wNumEntries = psa->wNumEntries; hr = StRead(pStm, psaNew->aStringArray, cbToRead); } else { psa->wNumEntries = 0; psa->wSecurityOffset = 0; hr = E_OUTOFMEMORY; // seek the stream past what we should have read, ignore // seek errors, since the OOM takes precedence. LARGE_INTEGER libMove; libMove.LowPart = cbToRead; libMove.HighPart = 0; pStm->Seek(libMove, STREAM_SEEK_CUR, 0); } } } return hr; } //+------------------------------------------------------------------------- // // Function: VerifyOBJREFFormat // // Synopsis: Checks the format of the marshal packet // // Arguments: [pStm] -- source stream // [mshlflags] -- destination buffer // // Returns: S_OK if successful, else error code // //-------------------------------------------------------------------------- HRESULT VerifyOBJREFFormat(IStream *pStm, DWORD mshlflags) { OBJREF objref; STDOBJREF *pStd; HRESULT hr = ReadObjRef(pStm, objref, &pStd); // now verify the format if (SUCCEEDED(hr)) { if (mshlflags & MSHLFLAGS_NOPING) { // SORF_NOPING should be set (unless previously marshaled PING) if (!(pStd->flags & SORF_NOPING)) return INVALID_SORFFLAG; } if ((mshlflags & MSHLFLAGS_TABLE) == MSHLFLAGS_NORMAL) { // refcnt should be non-zero if (pStd->cPublicRefs == 0) return INVALID_REFCNT; // table flags should not be set if (pStd->flags & (SORF_WEAKREF | SORF_TBLWEAK)) return INVALID_SORFFLAG; } else if ((mshlflags & MSHLFLAGS_TABLE) == MSHLFLAGS_TABLESTRONG) { // refcnt should be zero if (pStd->cPublicRefs != 0) return INVALID_REFCNT; } else if ((mshlflags & MSHLFLAGS_TABLE) == MSHLFLAGS_TABLEWEAK) { // refcnt should be zero if (pStd->cPublicRefs != 0) return INVALID_REFCNT; // SORF_TBLWEAK should be set if (!(pStd->flags & SORF_TBLWEAK)) return INVALID_SORFFLAG; } else { // unknown flags return INVALID_MSHLFLAG; } } return hr; }