NTSTATUS LsarpLookupPrivilegeDisplayName(PRPC_UNICODE_STRING Name, USHORT ClientLanguage, USHORT ClientSystemDefaultLanguage, PRPC_UNICODE_STRING *DisplayName, USHORT *LanguageReturned) { PRPC_UNICODE_STRING DisplayNameBuffer; UNIMPLEMENTED; /* For now, description is equal to privilege name */ DisplayNameBuffer = MIDL_user_allocate(sizeof(RPC_UNICODE_STRING)); if (DisplayNameBuffer == NULL) { return STATUS_NO_MEMORY; } DisplayNameBuffer->Length = Name->Length; DisplayNameBuffer->MaximumLength = Name->MaximumLength; DisplayNameBuffer->Buffer = MIDL_user_allocate(DisplayNameBuffer->MaximumLength); if (DisplayNameBuffer->Buffer == NULL) { MIDL_user_free(DisplayNameBuffer); return STATUS_NO_MEMORY; } wcscpy(DisplayNameBuffer->Buffer, Name->Buffer); *DisplayName = DisplayNameBuffer; return STATUS_SUCCESS; }
NTSTATUS LsapLookupAccountRightName(ULONG RightValue, PRPC_UNICODE_STRING *Name) { PRPC_UNICODE_STRING NameBuffer; ULONG i; for (i = 0; i < ARRAYSIZE(WellKnownRights); i++) { if (WellKnownRights[i].Flag == RightValue) { NameBuffer = MIDL_user_allocate(sizeof(RPC_UNICODE_STRING)); if (NameBuffer == NULL) return STATUS_NO_MEMORY; NameBuffer->Length = wcslen(WellKnownRights[i].Name) * sizeof(WCHAR); NameBuffer->MaximumLength = NameBuffer->Length + sizeof(WCHAR); NameBuffer->Buffer = MIDL_user_allocate(NameBuffer->MaximumLength); if (NameBuffer->Buffer == NULL) { MIDL_user_free(NameBuffer); return STATUS_INSUFFICIENT_RESOURCES; } wcscpy(NameBuffer->Buffer, WellKnownRights[i].Name); *Name = NameBuffer; return STATUS_SUCCESS; } } return STATUS_NO_SUCH_PRIVILEGE; }
NTSTATUS LsapLookupSids(PLSAPR_SID_ENUM_BUFFER SidEnumBuffer, PLSAPR_TRANSLATED_NAME OutputNames) { static const UNICODE_STRING UserName = RTL_CONSTANT_STRING(L"Administrator"); PWELL_KNOWN_SID ptr; ULONG Mapped = 0; ULONG i; NTSTATUS Status; PSID *Sids = (PSID *) SidEnumBuffer->SidInfo; TRACE("LsapLookupSids(%p, %p)\n", SidEnumBuffer, OutputNames); TRACE("SidEnumBuffer->Entries: %lu\n", SidEnumBuffer->Entries); TRACE("SidEnumBuffer->SidInfo: %p\n", SidEnumBuffer->SidInfo); for (i = 0; i < SidEnumBuffer->Entries; i++) { TRACE("i: %lu\n", i); ptr = LsapLookupWellKnownSid(Sids[i]); if (ptr != NULL) { OutputNames[i].Use = ptr->NameUse; OutputNames[i].DomainIndex = i; /* Fixme */ OutputNames[i].Name.Buffer = MIDL_user_allocate(ptr->Name.MaximumLength); OutputNames[i].Name.Length = ptr->Name.Length; OutputNames[i].Name.MaximumLength = ptr->Name.MaximumLength; RtlCopyMemory(OutputNames[i].Name.Buffer, ptr->Name.Buffer, ptr->Name.MaximumLength); Mapped++; } else { OutputNames[i].Use = SidTypeWellKnownGroup; OutputNames[i].DomainIndex = i; OutputNames[i].Name.Buffer = MIDL_user_allocate(UserName.MaximumLength); OutputNames[i].Name.Length = UserName.Length; OutputNames[i].Name.MaximumLength = UserName.MaximumLength; RtlCopyMemory(OutputNames[i].Name.Buffer, UserName.Buffer, UserName.MaximumLength); Mapped++; } } if (Mapped == 0) Status = STATUS_NONE_MAPPED; else if (Mapped < SidEnumBuffer->Entries) Status = STATUS_SOME_NOT_MAPPED; else Status = STATUS_SUCCESS; return Status; }
PVOID ElfpAllocateBuffer ( ULONG Size ) /*++ Routine Description: Allocate a buffer of the given size, and return the pointer in BufPtr. Arguments: Return Value: Pointer to allocated buffer (or NULL). Note: --*/ { PVOID BufPtr; #ifdef TAIL_CHECKING // // Keep the offset of the pattern (so we don't have to have internal // knowledge about the granularity of the heap block) and copy a // known pattern after the end of the user's block // BufPtr = (PVOID *) MIDL_user_allocate ( Size + CHECK_HEAP_TAIL_SIZE + sizeof(DWORD)); *((PDWORD)BufPtr) = Size + sizeof(DWORD); (PBYTE) BufPtr += sizeof(DWORD); RtlFillMemory((PBYTE)BufPtr + Size, CHECK_HEAP_TAIL_SIZE, CHECK_HEAP_TAIL_FILL); #else BufPtr = (PVOID *) MIDL_user_allocate ( Size ); #endif return (BufPtr); }
NTSTATUS LsarSetAuditFull(PLSA_DB_OBJECT PolicyObject, PPOLICY_AUDIT_FULL_QUERY_INFO Info) { PPOLICY_AUDIT_FULL_QUERY_INFO AuditFullInfo = NULL; ULONG AttributeSize; NTSTATUS Status; TRACE("(%p %p)\n", PolicyObject, Info); AttributeSize = sizeof(POLICY_AUDIT_FULL_QUERY_INFO); AuditFullInfo = MIDL_user_allocate(AttributeSize); if (AuditFullInfo == NULL) return STATUS_INSUFFICIENT_RESOURCES; Status = LsapGetObjectAttribute(PolicyObject, L"PolAdtFl", AuditFullInfo, &AttributeSize); if (!NT_SUCCESS(Status)) goto done; AuditFullInfo->ShutDownOnFull = Info->ShutDownOnFull; Status = LsapSetObjectAttribute(PolicyObject, L"PolAdtFl", AuditFullInfo, AttributeSize); done: if (AuditFullInfo != NULL) MIDL_user_free(AuditFullInfo); return Status; }
NTSTATUS LsarQueryAuditFull(PLSA_DB_OBJECT PolicyObject, PLSAPR_POLICY_INFORMATION *PolicyInformation) { PPOLICY_AUDIT_FULL_QUERY_INFO AuditFullInfo = NULL; ULONG AttributeSize; NTSTATUS Status; *PolicyInformation = NULL; AttributeSize = sizeof(POLICY_AUDIT_FULL_QUERY_INFO); AuditFullInfo = MIDL_user_allocate(AttributeSize); if (AuditFullInfo == NULL) return STATUS_INSUFFICIENT_RESOURCES; Status = LsapGetObjectAttribute(PolicyObject, L"PolAdtFl", AuditFullInfo, &AttributeSize); if (!NT_SUCCESS(Status)) { MIDL_user_free(AuditFullInfo); } else { *PolicyInformation = (PLSAPR_POLICY_INFORMATION)AuditFullInfo; } return Status; }
NTSTATUS LsarQueryModification(PLSA_DB_OBJECT PolicyObject, PLSAPR_POLICY_INFORMATION *PolicyInformation) { PPOLICY_MODIFICATION_INFO Info = NULL; ULONG AttributeSize; NTSTATUS Status; *PolicyInformation = NULL; AttributeSize = sizeof(POLICY_MODIFICATION_INFO); Info = MIDL_user_allocate(AttributeSize); if (Info == NULL) return STATUS_INSUFFICIENT_RESOURCES; Status = LsapGetObjectAttribute(PolicyObject, L"PolMod", Info, &AttributeSize); if (!NT_SUCCESS(Status)) { MIDL_user_free(Info); } else { *PolicyInformation = (PLSAPR_POLICY_INFORMATION)Info; } return Status; }
NTSTATUS LsarQueryDefaultQuota(PLSA_DB_OBJECT PolicyObject, PLSAPR_POLICY_INFORMATION *PolicyInformation) { PPOLICY_DEFAULT_QUOTA_INFO QuotaInfo = NULL; ULONG AttributeSize; NTSTATUS Status; *PolicyInformation = NULL; AttributeSize = sizeof(POLICY_DEFAULT_QUOTA_INFO); QuotaInfo = MIDL_user_allocate(AttributeSize); if (QuotaInfo == NULL) return STATUS_INSUFFICIENT_RESOURCES; Status = LsapGetObjectAttribute(PolicyObject, L"DefQuota", QuotaInfo, &AttributeSize); if (!NT_SUCCESS(Status)) { MIDL_user_free(QuotaInfo); } else { *PolicyInformation = (PLSAPR_POLICY_INFORMATION)QuotaInfo; } return Status; }
HRESULT __cdecl IrotRevoke( IrotHandle h, IrotCookie cookie, IrotContextHandle *ctxt_handle, PInterfaceData *obj, PInterfaceData *mk) { struct rot_entry *rot_entry; WINE_TRACE("%d\n", cookie); EnterCriticalSection(&csRunningObjectTable); LIST_FOR_EACH_ENTRY(rot_entry, &RunningObjectTable, struct rot_entry, entry) { if (rot_entry->cookie == cookie) { HRESULT hr = S_OK; list_remove(&rot_entry->entry); LeaveCriticalSection(&csRunningObjectTable); *obj = MIDL_user_allocate(FIELD_OFFSET(InterfaceData, abData[rot_entry->object->ulCntData])); *mk = MIDL_user_allocate(FIELD_OFFSET(InterfaceData, abData[rot_entry->moniker->ulCntData])); if (*obj && *mk) { (*obj)->ulCntData = rot_entry->object->ulCntData; memcpy((*obj)->abData, rot_entry->object->abData, (*obj)->ulCntData); (*mk)->ulCntData = rot_entry->moniker->ulCntData; memcpy((*mk)->abData, rot_entry->moniker->abData, (*mk)->ulCntData); } else { MIDL_user_free(*obj); MIDL_user_free(*mk); hr = E_OUTOFMEMORY; } rot_entry_release(rot_entry); *ctxt_handle = NULL; return hr; } } LeaveCriticalSection(&csRunningObjectTable); return E_INVALIDARG; }
void s_make_pyramid_doub_carr(unsigned char n, doub_carr_t **dc) { doub_carr_t *t; int i, j; t = MIDL_user_allocate(FIELD_OFFSET(doub_carr_t, a[n])); t->n = n; for (i = 0; i < n; ++i) { int v = i + 1; t->a[i] = MIDL_user_allocate(FIELD_OFFSET(doub_carr_1_t, a[v])); t->a[i]->n = v; for (j = 0; j < v; ++j) t->a[i]->a[j] = j + 1; } *dc = t; }
s123_t * s_get_s123(void) { s123_t *s = MIDL_user_allocate(sizeof *s); s->f1 = 1; s->f2 = 2; s->f3 = 3; return s; }
NTSTATUS LsarpLookupPrivilegeName(PLUID Value, PRPC_UNICODE_STRING *Name) { PRPC_UNICODE_STRING NameBuffer; ULONG Priv; if (Value->HighPart != 0 || (Value->LowPart < SE_MIN_WELL_KNOWN_PRIVILEGE || Value->LowPart > SE_MAX_WELL_KNOWN_PRIVILEGE)) { return STATUS_NO_SUCH_PRIVILEGE; } for (Priv = 0; Priv < ARRAYSIZE(WellKnownPrivileges); Priv++) { if (Value->LowPart == WellKnownPrivileges[Priv].Luid.LowPart && Value->HighPart == WellKnownPrivileges[Priv].Luid.HighPart) { NameBuffer = MIDL_user_allocate(sizeof(RPC_UNICODE_STRING)); if (NameBuffer == NULL) return STATUS_NO_MEMORY; NameBuffer->Length = wcslen(WellKnownPrivileges[Priv].Name) * sizeof(WCHAR); NameBuffer->MaximumLength = NameBuffer->Length + sizeof(WCHAR); NameBuffer->Buffer = MIDL_user_allocate(NameBuffer->MaximumLength); if (NameBuffer->Buffer == NULL) { MIDL_user_free(NameBuffer); return STATUS_NO_MEMORY; } wcscpy(NameBuffer->Buffer, WellKnownPrivileges[Priv].Name); *Name = NameBuffer; return STATUS_SUCCESS; } } return STATUS_NO_SUCH_PRIVILEGE; }
NET_API_STATUS NET_API_FUNCTION NetApiBufferAllocate( IN DWORD ByteCount, OUT LPVOID * Buffer ) /*++ Routine Description: NetApiBufferAllocate is an internal function that allocates buffers which the APIs will return to the application. (Usually these are for get-info operations.) Arguments: ByteCount - Supplies the size (in bytes) that must be allocated for this buffer. This may be zero, in which case a non-null pointer is passed-back and NO_ERROR is returned. Buffer - On return a pointer to the allocated area is returned in the address pointed to by Buffer. (This is set to NULL on error.) The allocated area is guaranteed to be worst-case aligned for any use whatsoever. Return Value: NET_API_STATUS - NO_ERROR if size is zero or memory was allocated. ERROR_NOT_ENOUGH_MEMORY if memory is not available. ERROR_INVALID_PARAMETER if a parameter is in error. --*/ { if (Buffer == NULL) { return (ERROR_INVALID_PARAMETER); } // // Allocate the space. Note that MIDL_user_allocate must allow zero // bytes to be allocated. // *Buffer = MIDL_user_allocate(ByteCount); if (*Buffer == NULL) { return (ERROR_NOT_ENOUGH_MEMORY); } NetpAssert( POINTER_IS_ALIGNED( *Buffer, ALIGN_WORST) ); return (NO_ERROR); } // NetApiBufferAllocate
HRESULT __cdecl IrotEnumRunning( IrotHandle h, PInterfaceList *list) { const struct rot_entry *rot_entry; HRESULT hr = S_OK; ULONG moniker_count = 0; ULONG i = 0; WINE_TRACE("\n"); EnterCriticalSection(&csRunningObjectTable); LIST_FOR_EACH_ENTRY( rot_entry, &RunningObjectTable, const struct rot_entry, entry ) moniker_count++; *list = MIDL_user_allocate(FIELD_OFFSET(InterfaceList, interfaces[moniker_count])); if (*list) { (*list)->size = moniker_count; LIST_FOR_EACH_ENTRY( rot_entry, &RunningObjectTable, const struct rot_entry, entry ) { (*list)->interfaces[i] = MIDL_user_allocate(FIELD_OFFSET(InterfaceData, abData[rot_entry->moniker->ulCntData])); if (!(*list)->interfaces[i]) { ULONG end = i - 1; for (i = 0; i < end; i++) MIDL_user_free((*list)->interfaces[i]); MIDL_user_free(*list); hr = E_OUTOFMEMORY; break; } (*list)->interfaces[i]->ulCntData = rot_entry->moniker->ulCntData; memcpy((*list)->interfaces[i]->abData, rot_entry->moniker->abData, rot_entry->moniker->ulCntData); i++; } } else
BOOL kull_m_rpc_drsr_ProcessGetNCChangesReply_decrypt(ATTRVAL *val) { BOOL status = FALSE; PENCRYPTED_PAYLOAD encrypted; MD5_CTX md5ctx; CRYPTO_BUFFER cryptoKey = {MD5_DIGEST_LENGTH, MD5_DIGEST_LENGTH, NULL}, cryptoData; DWORD realLen, calcChecksum; PVOID toFree; if(kull_m_rpc_drsr_g_sKey.SessionKey && kull_m_rpc_drsr_g_sKey.SessionKeyLength) { if((val->valLen >= (ULONG) FIELD_OFFSET(ENCRYPTED_PAYLOAD, EncryptedData)) && val->pVal) { encrypted = (PENCRYPTED_PAYLOAD) val->pVal; MD5Init(&md5ctx); MD5Update(&md5ctx, kull_m_rpc_drsr_g_sKey.SessionKey, kull_m_rpc_drsr_g_sKey.SessionKeyLength); MD5Update(&md5ctx, encrypted->Salt, sizeof(encrypted->Salt)); MD5Final(&md5ctx); cryptoKey.Buffer = md5ctx.digest; cryptoData.Length = cryptoData.MaximumLength = val->valLen - FIELD_OFFSET(ENCRYPTED_PAYLOAD, CheckSum); cryptoData.Buffer = (PBYTE) &encrypted->CheckSum; if(NT_SUCCESS(RtlEncryptDecryptRC4(&cryptoData, &cryptoKey))) { realLen = val->valLen - FIELD_OFFSET(ENCRYPTED_PAYLOAD, EncryptedData); if(kull_m_crypto_hash(CALG_CRC32, encrypted->EncryptedData, realLen, &calcChecksum, sizeof(calcChecksum))) { if(calcChecksum == encrypted->CheckSum) { toFree = val->pVal; if(val->pVal = (UCHAR *) MIDL_user_allocate(realLen)) { RtlCopyMemory(val->pVal, encrypted->EncryptedData, realLen); val->valLen = realLen; status = TRUE; MIDL_user_free(toFree); } } else PRINT_ERROR(L"Checksums don\'t match (C:0x%08x - R:0x%08x)\n", calcChecksum, encrypted->CheckSum); } else PRINT_ERROR(L"Unable to calculate CRC32\n"); } else PRINT_ERROR(L"RtlEncryptDecryptRC4\n"); } else PRINT_ERROR(L"No valid data\n"); } else PRINT_ERROR(L"No Session Key\n"); return status; }
DWORD VendorGetInfo( IN PRPL_SESSION pSession, IN LPWSTR VendorName, IN DWORD Level, OUT LPVOID Buffer, IN OUT PINT pSpaceLeft ) { DWORD Error; LPRPL_VENDOR_INFO_1 Info = Buffer; switch( Level) { case 1: Error = VendorGetField( pSession, VENDOR_Flags, (LPVOID *)&Info->Flags, pSpaceLeft); if ( Error != NO_ERROR) { return( Error); } NOTHING; // fall through case 0: Error = VendorGetField( pSession, VENDOR_VendorComment, &Info->VendorComment, pSpaceLeft); if ( Error != NO_ERROR) { return( Error); } if ( VendorName == NULL) { Error = VendorGetField( pSession, VENDOR_VendorName, &Info->VendorName, pSpaceLeft); if ( Error != NO_ERROR) { return( Error); } } else { DWORD DataSize = (wcslen( VendorName) + 1) * sizeof(WCHAR); Info->VendorName = MIDL_user_allocate( DataSize); if ( Info->VendorName == NULL) { return( ERROR_NOT_ENOUGH_MEMORY); } RplDump( RG_DebugLevel & RPL_DEBUG_VENDOR, ( "VendorName=0x%x", Info->VendorName)); memcpy( Info->VendorName, VendorName, DataSize); *pSpaceLeft -= DataSize; } break; default: return( ERROR_INVALID_LEVEL); break; } return( NO_ERROR); }
NTSTATUS LsarQueryPdAccount(PLSA_DB_OBJECT PolicyObject, PLSAPR_POLICY_INFORMATION *PolicyInformation) { PLSAPR_POLICY_PD_ACCOUNT_INFO PdAccountInfo = NULL; *PolicyInformation = NULL; PdAccountInfo = MIDL_user_allocate(sizeof(LSAPR_POLICY_PD_ACCOUNT_INFO)); if (PdAccountInfo == NULL) return STATUS_INSUFFICIENT_RESOURCES; PdAccountInfo->Name.Length = 0; PdAccountInfo->Name.MaximumLength = 0; PdAccountInfo->Name.Buffer = NULL; *PolicyInformation = (PLSAPR_POLICY_INFORMATION)PdAccountInfo; return STATUS_SUCCESS; }
HRESULT __cdecl IrotGetObject( IrotHandle h, const MonikerComparisonData *moniker_data, PInterfaceData *obj, IrotCookie *cookie) { const struct rot_entry *rot_entry; WINE_TRACE("%p\n", moniker_data); *cookie = 0; EnterCriticalSection(&csRunningObjectTable); LIST_FOR_EACH_ENTRY(rot_entry, &RunningObjectTable, const struct rot_entry, entry) { HRESULT hr = S_OK; if ((rot_entry->moniker_data->ulCntData == moniker_data->ulCntData) && !memcmp(&moniker_data->abData, &rot_entry->moniker_data->abData, moniker_data->ulCntData)) { *obj = MIDL_user_allocate(FIELD_OFFSET(InterfaceData, abData[rot_entry->object->ulCntData])); if (*obj) { (*obj)->ulCntData = rot_entry->object->ulCntData; memcpy((*obj)->abData, rot_entry->object->abData, (*obj)->ulCntData); *cookie = rot_entry->cookie; } else hr = E_OUTOFMEMORY; LeaveCriticalSection(&csRunningObjectTable); return hr; } } LeaveCriticalSection(&csRunningObjectTable); return MK_E_UNAVAILABLE; }
NTSTATUS LsarQueryServerRole(PLSA_DB_OBJECT PolicyObject, PLSAPR_POLICY_INFORMATION *PolicyInformation) { PPOLICY_LSA_SERVER_ROLE_INFO ServerRoleInfo = NULL; ULONG AttributeSize; NTSTATUS Status; *PolicyInformation = NULL; AttributeSize = sizeof(POLICY_LSA_SERVER_ROLE_INFO); ServerRoleInfo = MIDL_user_allocate(AttributeSize); if (ServerRoleInfo == NULL) return STATUS_INSUFFICIENT_RESOURCES; Status = LsapGetObjectAttribute(PolicyObject, L"PolSrvRo", ServerRoleInfo, &AttributeSize); if (Status == STATUS_OBJECT_NAME_NOT_FOUND) { ServerRoleInfo->LsaServerRole = PolicyServerRolePrimary; Status = STATUS_SUCCESS; } if (!NT_SUCCESS(Status)) { MIDL_user_free(ServerRoleInfo); } else { *PolicyInformation = (PLSAPR_POLICY_INFORMATION)ServerRoleInfo; } return Status; }
VOID GetMasterAnnouncementCompletion ( IN PVOID Ctx ) /*++ Routine Description: This function is the completion routine for a master announcement. It is called whenever a master announcement is received for a particular network. Arguments: Ctx - Context block for request. Return Value: None. --*/ { PVOID ServerList = NULL; ULONG EntriesRead; ULONG TotalEntries; NET_API_STATUS Status = NERR_Success; PBROWSERASYNCCONTEXT Context = Ctx; PLMDR_REQUEST_PACKET MasterAnnouncement = Context->RequestPacket; PNETWORK Network = Context->Network; LPTSTR RemoteMasterName = NULL; BOOLEAN NetLocked = FALSE; if (!LOCK_NETWORK(Network)) { MIDL_user_free(Context->RequestPacket); MIDL_user_free(Context); return; } NetLocked = TRUE; try { Network->Flags &= ~NETWORK_GET_MASTER_ANNOUNCE_POSTED; // // The request failed for some reason - just return immediately. // if (!NT_SUCCESS(Context->IoStatusBlock.Status)) { try_return(NOTHING); } Status = PostGetMasterAnnouncement(Network, NULL); if (Status != NERR_Success) { InternalError(("Unable to re-issue GetMasterAnnouncement request: %lx\n", Status)); try_return(NOTHING); } RemoteMasterName = MIDL_user_allocate(MasterAnnouncement->Parameters.WaitForMasterAnnouncement.MasterNameLength+3*sizeof(TCHAR)); if (RemoteMasterName == NULL) { try_return(NOTHING); } RemoteMasterName[0] = TEXT('\\'); RemoteMasterName[1] = TEXT('\\'); STRNCPY(&RemoteMasterName[2], MasterAnnouncement->Parameters.WaitForMasterAnnouncement.Name, MasterAnnouncement->Parameters.WaitForMasterAnnouncement.MasterNameLength/sizeof(TCHAR)); RemoteMasterName[(MasterAnnouncement->Parameters.WaitForMasterAnnouncement.MasterNameLength/sizeof(TCHAR))+2] = UNICODE_NULL; dprintf(MASTER, ("GetMasterAnnouncement: Got a master browser announcement from %ws\n", RemoteMasterName)); UNLOCK_NETWORK(Network); NetLocked = FALSE; // // Remote the api and pull the browse list from the remote server. // Status = RxNetServerEnum(RemoteMasterName, Network->NetworkName.Buffer, 101, (LPBYTE *)&ServerList, 0xffffffff, &EntriesRead, &TotalEntries, SV_TYPE_LOCAL_LIST_ONLY, NULL, NULL ); if ((Status == NERR_Success) || (Status == ERROR_MORE_DATA)) { if (!LOCK_NETWORK(Network)) { try_return(NOTHING); } NetLocked = TRUE; Status = MergeServerList(&Network->BrowseTable, 101, ServerList, EntriesRead, TotalEntries ); UNLOCK_NETWORK(Network); NetLocked = FALSE; (void) NetApiBufferFree( ServerList ); ServerList = NULL; } // // Remote the api and pull the browse list from the remote server. // Status = RxNetServerEnum(RemoteMasterName, Network->NetworkName.Buffer, 101, (LPBYTE *)&ServerList, 0xffffffff, &EntriesRead, &TotalEntries, SV_TYPE_LOCAL_LIST_ONLY | SV_TYPE_DOMAIN_ENUM, NULL, NULL ); if ((Status == NERR_Success) || (Status == ERROR_MORE_DATA)) { if (!LOCK_NETWORK(Network)) { try_return(NOTHING); } NetLocked = TRUE; Status = MergeServerList(&Network->DomainList, 101, ServerList, EntriesRead, TotalEntries ); } try_exit: NOTHING; } finally { if (NetLocked) { UNLOCK_NETWORK(Network); } if (RemoteMasterName != NULL) { MIDL_user_free(RemoteMasterName); } MIDL_user_free(Context->RequestPacket); MIDL_user_free(Context); if ( ServerList != NULL ) { (void) NetApiBufferFree( ServerList ); } } return; }
NET_API_STATUS BrCreateNetwork( PUNICODE_STRING TransportName, IN BOOLEAN Wannish, IN BOOLEAN Ras, IN PUNICODE_STRING AlternateTransportName OPTIONAL ) /*++ Routine Description: This routine allocates memory to hold a network structure, and initializes all of its associated data structures. Arguments: TransportName - The name of the transport to add. Return Value: Status of operation (mostly status of allocations). --*/ { NET_API_STATUS Status; PNETWORK Network; BOOLEAN NetworkLockInitialized = FALSE; BOOLEAN MasterFlagsInitialized = FALSE; BOOLEAN BackupBrowserTimerCreated = FALSE; BOOLEAN MasterBrowserTimerCreated =FALSE; BOOLEAN AnnouncementTimerCreated = FALSE; BOOLEAN ResponseCacheLockInitialized = FALSE; // // Check to see if the transport already exists. // if ((Network = BrFindNetwork(TransportName)) != NULL) { return NERR_AlreadyExists; } // // If this transport is explicitly on our list of transports to unbind, // simply ignore the transport. // if (BrInfo.UnboundBindings != NULL) { LPTSTR_ARRAY TStrArray = BrInfo.UnboundBindings; while (!NetpIsTStrArrayEmpty(TStrArray)) { LPWSTR NewTransportName; #define NAME_PREFIX L"\\Device\\" #define NAME_PREFIX_LENGTH 8 // // The transport name in the registry is only optionally prefixed with \device\ // if ( _wcsnicmp( NAME_PREFIX, TStrArray, NAME_PREFIX_LENGTH) == 0 ) { NewTransportName = TransportName->Buffer; } else { NewTransportName = TransportName->Buffer + NAME_PREFIX_LENGTH; } if ( _wcsicmp( TStrArray, NewTransportName ) == 0 ) { dprintf(INIT, ("Binding is marked as unbound: %s (Silently ignoring)\n", TransportName->Buffer )); return NERR_Success; } TStrArray = NetpNextTStrArrayEntry(TStrArray); } } // // If this transport isn't bound to the SMB server, // don't create the transport here. // we do announcments through the SMB server. // Status = I_NetServerSetServiceBits(NULL, TransportName->Buffer, 0, TRUE); if (Status == ERROR_PATH_NOT_FOUND ) { dprintf(INIT, ("SMB Server doesn't have this transport: %s (Silently unbinding)\n", TransportName->Buffer )); return NERR_Success; } // // Create the transport. // try { Network = MIDL_user_allocate(sizeof(NETWORK)); if (Network == NULL) { try_return(Status = ERROR_NOT_ENOUGH_MEMORY); } RtlInitializeResource(&Network->Lock); NetworkLockInitialized = TRUE; Network->LockCount = 0; Network->ReferenceCount = 1; Network->Role = BrDefaultRole; Network->NumberOfFailedBackupTimers = 0; Network->NumberOfFailedPromotions = 0; Network->NumberOfPromotionEventsLogged = 0; Network->LastBackupBrowserReturned = 0; Network->LastDomainControllerBrowserReturned = 0; Network->TimeStoppedBackup = 0; Network->BackupServerList = NULL; Network->BackupDomainList = NULL; Network->TotalBackupServerListEntries = 0; Network->TotalBackupDomainListEntries = 0; Network->NetworkName.Buffer = MIDL_user_allocate(TransportName->MaximumLength); if (Network->NetworkName.Buffer == NULL) { try_return(Status = ERROR_NOT_ENOUGH_MEMORY); } Network->NetworkName.MaximumLength = TransportName->MaximumLength; RtlCopyUnicodeString(&Network->NetworkName, TransportName); Network->Flags = 0; if (ARGUMENT_PRESENT(AlternateTransportName)) { PNETWORK AlternateNetwork = BrFindNetwork(AlternateTransportName); // // If we didn't find an alternate network, or if that network // already has an alternate network, return an error. // if (AlternateNetwork == NULL || AlternateNetwork->AlternateNetwork != NULL) { try_return(Status = NERR_InternalError); } Network->Flags |= NETWORK_IPX; // // Link the two networks together. // Network->AlternateNetwork = AlternateNetwork; AlternateNetwork->AlternateNetwork = Network; } else { Network->AlternateNetwork = NULL; } // // Null terminate the network name buffer. // Network->NetworkName.Buffer[Network->NetworkName.Length/sizeof(WCHAR)] = UNICODE_NULL; RtlInitUnicodeString(&Network->MasterBrowserName, NULL); if (Wannish) { Network->Flags |= NETWORK_WANNISH; } if (Ras) { Network->Flags |= NETWORK_RAS; } Network->LastBowserServerQueried = 0; RtlInitializeCriticalSection(&Network->MasterFlagsLock); MasterFlagsInitialized = TRUE; Network->MasterFlags = 0; InitializeInterimServerList(&Network->BrowseTable, BrBrowseTableInsertRoutine, BrBrowseTableUpdateRoutine, BrBrowseTableDeleteRoutine, BrBrowseTableAgeRoutine); Network->LastBowserDomainQueried = 0; InitializeInterimServerList(&Network->DomainList, BrDomainTableInsertRoutine, BrDomainTableUpdateRoutine, BrDomainTableDeleteRoutine, BrDomainTableAgeRoutine); InitializeListHead(&Network->OtherDomainsList); Status = BrCreateTimer(&Network->BackupBrowserTimer); if (Status != NERR_Success) { try_return(Status); } BackupBrowserTimerCreated = TRUE; Status = BrCreateTimer(&Network->MasterBrowserTimer); if (Status != NERR_Success) { try_return(Status); } MasterBrowserTimerCreated = TRUE; Status = BrCreateTimer(&Network->MasterBrowserAnnouncementTimer); if (Status != NERR_Success) { try_return(Status); } AnnouncementTimerCreated = TRUE; InitializeCriticalSection(&Network->ResponseCacheLock); ResponseCacheLockInitialized = TRUE; InitializeListHead(&Network->ResponseCache); Network->TimeCacheFlushed = 0; Network->NumberOfCachedResponses = 0; Status = RtlEnterCriticalSection(&NetworkLock); if (!NT_SUCCESS(Status)) { try_return(Status = BrMapStatus(Status)); } InsertHeadList(&ServicedNetworks, &Network->NextNet); Status = RtlLeaveCriticalSection(&NetworkLock); if (!NT_SUCCESS(Status)) { InternalError(("Unable to release browser critical section\n")); } try_exit:NOTHING; } finally { if (Status != NERR_Success) { if (Network != NULL) { if (ResponseCacheLockInitialized) { DeleteCriticalSection(&Network->ResponseCacheLock); } if (MasterFlagsInitialized) { RtlDeleteCriticalSection(&Network->MasterFlagsLock); } if (NetworkLockInitialized) { RtlDeleteResource(&Network->Lock); } if (AnnouncementTimerCreated) { BrDestroyTimer(&Network->MasterBrowserAnnouncementTimer); } if (MasterBrowserTimerCreated) { BrDestroyTimer(&Network->MasterBrowserTimer); } if (BackupBrowserTimerCreated) { BrDestroyTimer(&Network->BackupBrowserTimer); } if (Network->NetworkName.Buffer != NULL) { MIDL_user_free(Network->NetworkName.Buffer); } MIDL_user_free(Network); } } } return Status; }
VOID SampBuildDummyAccounts( IN DOMAIN_DISPLAY_INFORMATION DisplayInformation, IN ULONG Index, OUT PULONG TotalAvailable, OUT PULONG TotalReturned, OUT PULONG ReturnedEntryCount, OUT PVOID *SortedBuffer ) { ULONG AccountCount, Account1, Account2; ULONG i, j, BeginIndex, EndIndex; ULONG ReturnStructSize, ArrayLength, StringLengths; PCHAR NextByte; UNICODE_STRING Us; ASSERT (SAMP_TEMP_USER1 != 0); ASSERT (SAMP_TEMP_USER2 != 0); ASSERT (SAMP_TEMP_MACHINE1 != 0); ASSERT (SAMP_TEMP_MACHINE2 != 0); if (DisplayInformation == DomainDisplayUser) { ReturnStructSize = sizeof(DOMAIN_DISPLAY_USER); Account1 = SAMP_TEMP_USER1; Account2 = SAMP_TEMP_USER2; AccountCount = SAMP_TEMP_USER_COUNT; } else { ReturnStructSize = sizeof(DOMAIN_DISPLAY_MACHINE); Account1 = SAMP_TEMP_MACHINE1; Account2 = SAMP_TEMP_MACHINE2; AccountCount = SAMP_TEMP_MACHINE_COUNT; } // // Build up a number of dummy accounts in a single buffer. // if (Index < Account1) { // // Give the first group of accounts // ArrayLength = ReturnStructSize * Account1; BeginIndex = 0; EndIndex = Account1; } else { // // Give the second group of accounts // ArrayLength = ReturnStructSize * Account2; BeginIndex = Account1; EndIndex = AccountCount; } // // Figure out how large a buffer is needed. // StringLengths = 0; for (i=BeginIndex; i<EndIndex; i++) { if (DisplayInformation == DomainDisplayUser) { RtlInitUnicodeString( &Us, DummyUsers[i].LogonName); StringLengths += Us.Length; RtlInitUnicodeString( &Us, DummyUsers[i].FullName); StringLengths += Us.Length; RtlInitUnicodeString( &Us, DummyUsers[i].AdminComment); StringLengths += Us.Length; } else { RtlInitUnicodeString( &Us, DummyMachines[i].Machine); StringLengths += Us.Length; RtlInitUnicodeString( &Us, DummyMachines[i].Comment); StringLengths += Us.Length; } } (*SortedBuffer) = MIDL_user_allocate( ArrayLength + StringLengths ); ASSERT(SortedBuffer != NULL); // // First free byte in the return buffer // NextByte = (PCHAR)((ULONG)(*SortedBuffer) + (ULONG)ArrayLength); // // Now copy the structures if (DisplayInformation == DomainDisplayUser) { PDOMAIN_DISPLAY_USER r; r = (PDOMAIN_DISPLAY_USER)(*SortedBuffer); j=0; for (i=BeginIndex; i<EndIndex; i++) { r[j].AccountControl = USER_NORMAL_ACCOUNT; r[j].Index = i; r[j].Rid = DummyUsers[i].Rid; // // copy the logon name // RtlInitUnicodeString( &Us, DummyUsers[i].LogonName); r[j].LogonName.MaximumLength = Us.Length; r[j].LogonName.Length = Us.Length; r[j].LogonName.Buffer = (PWSTR)NextByte; RtlMoveMemory(NextByte, Us.Buffer, r[j].LogonName.Length); NextByte += r[j].LogonName.Length; // // copy the full name // RtlInitUnicodeString( &Us, DummyUsers[i].FullName); r[j].FullName.MaximumLength = Us.Length; r[j].FullName.Length = Us.Length; r[j].FullName.Buffer = (PWSTR)NextByte; RtlMoveMemory(NextByte, Us.Buffer, r[j].FullName.Length); NextByte += r[j].FullName.Length; // // copy the admin comment // RtlInitUnicodeString( &Us, DummyUsers[i].AdminComment); r[j].AdminComment.MaximumLength = Us.Length; r[j].AdminComment.Length = Us.Length; r[j].AdminComment.Buffer = (PWSTR)NextByte; RtlMoveMemory(NextByte, Us.Buffer, r[j].AdminComment.Length); NextByte += r[j].AdminComment.Length; j++; } } else { PDOMAIN_DISPLAY_MACHINE r; r = (PDOMAIN_DISPLAY_MACHINE)(*SortedBuffer); j=0; for (i=BeginIndex; i<EndIndex; i++) { r[j].AccountControl = USER_WORKSTATION_TRUST_ACCOUNT; r[j].Index = i; r[j].Rid = DummyMachines[i].Rid; // // copy the logon name // RtlInitUnicodeString( &Us, DummyMachines[i].Machine); r[j].Machine.MaximumLength = Us.Length; r[j].Machine.Length = Us.Length; r[j].Machine.Buffer = (PWSTR)NextByte; RtlMoveMemory(NextByte, Us.Buffer, r[j].Machine.Length); NextByte += r[j].Machine.Length; // // copy the admin comment // RtlInitUnicodeString( &Us, DummyMachines[i].Comment); r[j].Comment.MaximumLength = Us.Length; r[j].Comment.Length = Us.Length; r[j].Comment.Buffer = (PWSTR)NextByte; RtlMoveMemory(NextByte, Us.Buffer, r[j].Comment.Length); NextByte += r[j].Comment.Length; j++; } } (*TotalAvailable) = 6*1024; // A lie, but just a little lie. (*TotalReturned) = ArrayLength + StringLengths; (*ReturnedEntryCount) = EndIndex - BeginIndex; return; }
NTSTATUS LsapCrServerGetSessionKey( IN LSAPR_HANDLE ObjectHandle, OUT PLSAP_CR_CIPHER_KEY *SessionKey ) /*++ Routine Description: This function obtains the Session Key, allocates an Cipher Key structure and returns the key. Arguments: ObjectHandle - Handle from an LsaOpen<ObjectType> call. SessionKey - Receives a pointer to a structure containing the Session Key in which the memory has been allocated via MIDL_user_allocate(). Return Value: NTSTATUS - Standard Nt Result Code STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources (e.g memory) to complete the call. --*/ { NTSTATUS Status = STATUS_SUCCESS; PLSAP_CR_CIPHER_KEY OutputSessionKey = NULL; ULONG OutputSessionKeyBufferLength; // // Allocate memory for the Session Key buffer and LSAP_CR_CIPHER_KEY // structure. // OutputSessionKeyBufferLength = sizeof (USER_SESSION_KEY); Status = STATUS_INSUFFICIENT_RESOURCES; OutputSessionKey = MIDL_user_allocate( OutputSessionKeyBufferLength + sizeof (LSAP_CR_CIPHER_KEY) ); if (OutputSessionKey == NULL) { goto ServerGetSessionKeyError; } // // Fill in the Cipher key structure, making the buffer point to // just beyond the header. // OutputSessionKey->Length = OutputSessionKeyBufferLength; OutputSessionKey->MaximumLength = OutputSessionKeyBufferLength; OutputSessionKey->Buffer = (PUCHAR) (OutputSessionKey + 1); Status = RtlGetUserSessionKeyServer( ObjectHandle, (PUSER_SESSION_KEY) OutputSessionKey->Buffer ); if (!NT_SUCCESS(Status)) { goto ServerGetSessionKeyError; } OutputSessionKey->Length = OutputSessionKey->MaximumLength = OutputSessionKeyBufferLength; ServerGetSessionKeyFinish: *SessionKey = OutputSessionKey; return(Status); ServerGetSessionKeyError: goto ServerGetSessionKeyFinish; }
// // FUNCTION: DoTimings // // PURPOSE: Calls and times various RPC calls. // (Avoid cluttering up main()) // // PARAMETERS: // Binding - Binding to the server. // iIterations - Number of times to make each call. // // RETURN VALUE: // n/a // // void DoTimings(RPC_BINDING_HANDLE Binding, UINT iIterations) { ULONG mseconds; UINT i; RPC_STATUS status; byte bBuffer[4096]; ULONG lBufferLength; ULONG lBufferSize; // Time Pings() (void calls) StartTime(); for(i = iIterations; i; i--) { status = Ping(Binding); if (status != RPC_S_OK) goto Cleanup; } mseconds = EndTime(); printf("%4d calls in %8d milliseconds - void calls.\n", iIterations, mseconds); // Time [in] buffer's // lBufferLength = BUFFER_SIZE; lBufferSize = BUFFER_SIZE; StartTime(); for(i = iIterations; i; i--) { status = BufferIn1(Binding, bBuffer, lBufferLength, lBufferSize); if (status != RPC_S_OK) { goto Cleanup; } } mseconds = EndTime(); printf("%4d calls in %8d milliseconds - 100 byte buffer in (1).\n", iIterations, mseconds); lBufferLength = BUFFER_SIZE; StartTime(); for(i = iIterations; i; i--) { status = BufferIn3(Binding, bBuffer, lBufferLength); if (status != RPC_S_OK) { goto Cleanup; } } mseconds = EndTime(); printf("%4d calls in %8d milliseconds - 100 byte buffer in (2).\n", iIterations, mseconds); lBufferLength = BUFFER_SIZE; StartTime(); for(i = iIterations; i; i--) { status = BufferIn3(Binding, bBuffer, lBufferLength); if (status != RPC_S_OK) { goto Cleanup; } } mseconds = EndTime(); printf("%4d calls in %8d milliseconds - 100 byte buffer in (3).\n", iIterations, mseconds); // Time [out] buffer's lBufferLength = BUFFER_SIZE; StartTime(); for(i = iIterations; i; i--) { status = BufferOut1(Binding, bBuffer, &lBufferLength); if (status != RPC_S_OK) { goto Cleanup; } } mseconds = EndTime(); printf("%4d calls in %8d milliseconds - 100 byte buffer out (1).\n", iIterations, mseconds); lBufferLength = BUFFER_SIZE; lBufferSize = BUFFER_SIZE; StartTime(); for(i = iIterations; i; i--) { status = BufferOut2(Binding, bBuffer, lBufferSize, &lBufferLength); if (status != RPC_S_OK) { goto Cleanup; } } mseconds = EndTime(); printf("%4d calls in %8d milliseconds - 100 byte buffer out (2).\n", iIterations, mseconds); StartTime(); for(i = iIterations; i; i--) { BUFFER Buffer; Buffer.BufferLength = 0; Buffer.Buffer = 0; status = BufferOut3(Binding, &Buffer); if (status != RPC_S_OK) { goto Cleanup; } MIDL_user_free(Buffer.Buffer); } mseconds = EndTime(); printf("%4d calls in %8d milliseconds - 100 byte buffer out (3).\n", iIterations, mseconds); lBufferLength = BUFFER_SIZE; StartTime(); for(i = iIterations; i; i--) { status = BufferOut4(Binding, bBuffer, &lBufferLength); if (status != RPC_S_OK) { goto Cleanup; } } mseconds = EndTime(); printf("%4d calls in %8d milliseconds - 100 byte buffer out (4).\n", iIterations, mseconds); // Time arrays of structures { struct BAD1 abad1[50]; struct BAD2 abad2[50]; struct GOOD agood[50]; for (i = 0; i < 50; i++) { abad2[i].e = (BAD_ENUM)i % 4 + 1; agood[i].e = (GOOD_ENUM)i % 4 + 5; } StartTime(); for(i = iIterations; i; i--) { status = StructsIn1(Binding, &abad1[0]); if (status != RPC_S_OK) { goto Cleanup; } } mseconds = EndTime(); printf("%4d calls in %8d milliseconds - 2 mod 4 aligned structs.\n", iIterations, mseconds); StartTime(); for(i = iIterations; i; i--) { status = StructsIn2(Binding, &abad2[0]); if (status != RPC_S_OK) { goto Cleanup; } } mseconds = EndTime(); printf("%4d calls in %8d milliseconds - structs with an enum.\n", iIterations, mseconds); StartTime(); for(i = iIterations; i; i--) { status = StructsIn3(Binding, &agood[0]); if (status != RPC_S_OK) { goto Cleanup; } } mseconds = EndTime(); printf("%4d calls in %8d milliseconds - structs with v1_enum.\n", iIterations, mseconds); } // Linked lists { LIST list; PLIST plist = &list; for (i = 0; i < LIST_SIZE - 1; i++) { plist->pNext = MIDL_user_allocate(sizeof(LIST)); plist->data = i; if (plist->pNext == 0) { status = RPC_S_OUT_OF_MEMORY; goto Cleanup; } plist = plist->pNext; } plist->data = i; plist->pNext = 0; StartTime(); for(i = iIterations; i; i--) { status = ListIn(Binding, &list); if (status != RPC_S_OK) { goto Cleanup; } } mseconds = EndTime(); printf("%4d calls in %8d milliseconds - [in] linked list.\n", iIterations, mseconds); StartTime(); for(i = iIterations; i; i--) { status = ListOut1(Binding, &list); if (status != RPC_S_OK) { goto Cleanup; } // Freeing the list here would cause all the elements // to be allocated again on the next call. } mseconds = EndTime(); printf("%4d calls in %8d milliseconds - [out] linked list (1).\n", iIterations, mseconds); StartTime(); for(i = iIterations; i; i--) { status = ListOut2(Binding, &list); if (status != RPC_S_OK) { goto Cleanup; } // Freeing the list here would cause all the elements // to be allocated again on the next call. } mseconds = EndTime(); printf("%4d calls in %8d milliseconds - [out] linked list (2).\n", iIterations, mseconds); // Free allocated elements of the list. plist = list.pNext; while(plist) { PLIST tmp = plist; plist = plist->pNext; MIDL_user_free(tmp); } } // Unions { BAD_UNION badunionArray[UNION_ARRAY_LEN]; GOOD_UNION goodunion; ARM_ONE armone; ULONG ulArray[UNION_ARRAY_LEN]; goodunion.Tag = 1; goodunion.u.pOne = &armone; armone.DataLength = UNION_ARRAY_LEN; armone.Data = ulArray; for(i = 0; i < UNION_ARRAY_LEN; i++) { ulArray[i] = i; badunionArray[i].Tag = 1; badunionArray[i].u.ulData = i; } StartTime(); for(i = iIterations; i; i--) { status = UnionCall1(Binding, UNION_ARRAY_LEN, badunionArray); if (status != RPC_S_OK) { goto Cleanup; } } mseconds = EndTime(); printf("%4d calls in %8d milliseconds - [in] array of unions.\n", iIterations, mseconds); StartTime(); for(i = iIterations; i; i--) { status = UnionCall2(Binding, &goodunion); if (status != RPC_S_OK) { goto Cleanup; } } mseconds = EndTime(); printf("%4d calls in %8d milliseconds - [in] union of arrays.\n", iIterations, mseconds); } // Time pings() (null calls) which impersonate the client. StartTime(); for(i = iIterations; i; i--) { status = CheckSecurity(Binding); if (status != RPC_S_OK) { if (status == RPC_S_ACCESS_DENIED) { printf("Access denied, try -s 2 or higher.\n"); return; } goto Cleanup; } } mseconds = EndTime(); printf("%4d calls in %8d milliseconds - void call w/ impersonation\n", iIterations, mseconds); Cleanup: if (status != RPC_S_OK) { printf("Call failed - %d\n", status); } return; }
NTSTATUS timesvc_RemoteTimeOfDay( OUT LPTIME_OF_DAY_INFO *lpTimeOfDayInfo ) /*++ Routine Description: This routine calls the Win32 and NT base timer APIs to get the relevant time/date information. It also calls the Rtl routine to convert the time elapsed since 1-1-1970. The routine allocates a buffer to contain the time of day information and returns a pointer to that buffer to the caller. Arguments: lpTimeOfDayInfo - Location of where to place pointer to buffer. Return Value: NTSTATUS - STATUS_SUCCESS or reason for failure. --*/ { SYSTEMTIME SystemTime; LARGE_INTEGER Time; DWORD TickCount; LPTIME_OF_DAY_INFO lpTimeOfDay; LONG LocalTimeZoneOffsetSecs; // offset (+ for West of GMT, etc). if (lpTimeOfDayInfo == NULL) { return (STATUS_INVALID_PARAMETER); } // // Call the appropriate routines to collect the time information // GetSystemTime(&SystemTime); // // Get number of seconds from UTC. Positive values for west of Greenwich, // negative values for east of Greenwich. // LocalTimeZoneOffsetSecs = NetpLocalTimeZoneOffset(); // // Allocate a TimeOfDay_INFO structure that is to be returned to the // caller and fill it with the relevant data. // *lpTimeOfDayInfo = (TIME_OF_DAY_INFO *) MIDL_user_allocate( sizeof (struct _TIME_OF_DAY_INFO) ); if (*lpTimeOfDayInfo == NULL) { SS_PRINT(( "SRVSVC: timesvc_RemoteTimeOfDay" "got NULL from MIDL_user_allocate!\n" )); return(STATUS_NO_MEMORY); } lpTimeOfDay = (LPTIME_OF_DAY_INFO)(*lpTimeOfDayInfo); lpTimeOfDay->tod_hours = SystemTime.wHour; lpTimeOfDay->tod_mins = SystemTime.wMinute; lpTimeOfDay->tod_secs = SystemTime.wSecond; lpTimeOfDay->tod_hunds = SystemTime.wMilliseconds/10; lpTimeOfDay->tod_tinterval = TOD_DEFAULT_INTERVAL; lpTimeOfDay->tod_day = SystemTime.wDay; lpTimeOfDay->tod_month = SystemTime.wMonth; lpTimeOfDay->tod_year = SystemTime.wYear; lpTimeOfDay->tod_weekday = SystemTime.wDayOfWeek; // tod_timezone is + for west of GMT, - for east of it. // tod_timezone is in minutes. lpTimeOfDay->tod_timezone = LocalTimeZoneOffsetSecs / 60; // Get the 64-bit system time. // Convert the system time to the number of miliseconds // since 1-1-1970. // NtQuerySystemTime(&Time); RtlTimeToSecondsSince1970(&Time, &(lpTimeOfDay->tod_elapsedt) ); // Get the free running counter value // TickCount = GetTickCount(); lpTimeOfDay->tod_msecs = TickCount; return(STATUS_SUCCESS); } // timesvc_RemoteTimeOfDay
NTSTATUS LsapDbQueryValueSecret( IN LSAPR_HANDLE SecretHandle, IN PUNICODE_STRING ValueName, IN OPTIONAL PLSAP_CR_CIPHER_KEY SessionKey, OUT PLSAP_CR_CIPHER_VALUE *CipherValue ) /*++ Routine Description: This function queries the specified value of a Secret Object. If the caller is non-trusted, the value returned will have been two-way encrypted with the Session Key. If the caller is trusted, no encryption is done since the caller is calling us directly. Arguments: SecretHandle - Handle to Secret Object. ValueName - Unicode name of the Secret Value to be queried. This name is either "Currval" (for the Current Value) or "OldVal" (for the Old Value. SessionKey - Pointer to Session Key to be used for two-way encryption of the value to be returned. This pointer must be non-NULL except for Trusted Clients, where it must be NULL. CipherValue - Receives 32-bit counted string pointer to Secret Value queried. For non-trusted clients, the value will be encrypted. WARNING - Note that CipherValue is defined to RPC as "allocate(all_nodes)". This means that it is returned in one contiguous block of memory rather than two, as it would appear by the structure definition. Return Values: NTSTATUS - Standard Nt Result Code. STATUS_SUCCESS - The call completed successfully. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources, such as memory, to complete the call. --*/ { NTSTATUS Status; ULONG DbCipherValueLength; PLSAP_CR_CLEAR_VALUE ClearValue = NULL; PLSAP_CR_CIPHER_VALUE DbCipherValue = NULL; PLSAP_CR_CIPHER_VALUE OutputCipherValue = NULL; LSAP_DB_HANDLE InternalHandle = (LSAP_DB_HANDLE) SecretHandle; // // Get length of the specified Value attribute of the Secret object. // DbCipherValueLength = 0; Status = LsapDbReadAttributeObject( SecretHandle, ValueName, NULL, &DbCipherValueLength ); if (!NT_SUCCESS(Status)) { if (Status != STATUS_OBJECT_NAME_NOT_FOUND) { goto QueryValueSecretError; } Status = STATUS_SUCCESS; *CipherValue = NULL; return(Status); } // // We successfully read the length of the stored Secret Object value // plus header from the Policy Database. Verify that the Secret // Object value is either at least as long as a Cipher Value // structure header, or is of length 0. // if (DbCipherValueLength < sizeof (LSAP_CR_CIPHER_VALUE)) { if (DbCipherValueLength == 0) { goto QueryValueSecretFinish; } Status = STATUS_INTERNAL_DB_ERROR; goto QueryValueSecretError; } // // Allocate memory for reading the specified Value of the Secret object. // This value is stored in the Policy Database in the form of a // Self-Relative Value structure. The Value Buffer part is encrypted. // Status = STATUS_INSUFFICIENT_RESOURCES; DbCipherValue = MIDL_user_allocate(DbCipherValueLength); if (DbCipherValue == NULL) { goto QueryValueSecretError; } // // Read the specified Policy-database-encrypted Value attribute. // Status = LsapDbReadAttributeObject( SecretHandle, ValueName, DbCipherValue, &DbCipherValueLength ); if (!NT_SUCCESS(Status)) { goto QueryValueSecretError; } // // Verify that Lengths in returned header are consistent // and also match returned data length - header size. // Status = STATUS_INTERNAL_DB_ERROR; if (DbCipherValue->Length > DbCipherValue->MaximumLength) { goto QueryValueSecretError; } if ((DbCipherValue->Length + (ULONG) sizeof(LSAP_CR_CIPHER_VALUE)) != DbCipherValueLength) { goto QueryValueSecretError; } // // If the size of the Value structure is less than its header size, // something is wrong. // if (DbCipherValueLength < sizeof(LSAP_CR_CIPHER_VALUE)) { goto QueryValueSecretError; } // // If the string length is 0, something is wrong. // if (DbCipherValue->Length == 0) { goto QueryValueSecretError; } // // Store pointer to Value buffer in the Value structure. This pointer // points just after the header. Then decrypt the Value using the // LSA Database Cipher Key and encrypt the result using the Session Key. // DbCipherValue->Buffer = (PUCHAR)(DbCipherValue + 1); Status = LsapCrDecryptValue( DbCipherValue, LsapDbCipherKey, &ClearValue ); if (!NT_SUCCESS(Status)) { goto QueryValueSecretError; } // // If the client is non-Trusted, encrypt the value with the Session // Key, otherwise, leave it unchanged. // if (!InternalHandle->Trusted) { Status = LsapCrEncryptValue( ClearValue, SessionKey, &OutputCipherValue ); if (!NT_SUCCESS(Status)) { goto QueryValueSecretError; } } else { // // Trusted clients get a clear-text block back. // The block contains both the header and the text. // OutputCipherValue = (PLSAP_CR_CIPHER_VALUE)(ClearValue); } QueryValueSecretFinish: // // If necessary, free memory allocated for the Db-encrypted Secret // object Value read from the Policy Database. // if (DbCipherValue != NULL) { LsapCrFreeMemoryValue( DbCipherValue ); } // // If necessary, free memory allocated for the Decrypted Value. // Trusted client's get a pointer to ClearValue back, so don't // free it in this case. // if (!InternalHandle->Trusted && ClearValue != NULL) { LsapCrFreeMemoryValue( ClearValue ); } // // Return pointer to Cipher Value (Clear Value for trusted clients) or // NULL. // *CipherValue = OutputCipherValue; return(Status); QueryValueSecretError: // // If necessary, free memory allocated for the Secret object value // after re-encryption for return to the Client. // if (OutputCipherValue != NULL) { LsapCrFreeMemoryValue( OutputCipherValue ); } goto QueryValueSecretFinish; }
NTSTATUS LsarpEnumeratePrivileges(DWORD *EnumerationContext, PLSAPR_PRIVILEGE_ENUM_BUFFER EnumerationBuffer, DWORD PreferedMaximumLength) { PLSAPR_POLICY_PRIVILEGE_DEF Privileges = NULL; ULONG EnumIndex; ULONG EnumCount = 0; ULONG RequiredLength = 0; ULONG i; BOOLEAN MoreEntries = FALSE; NTSTATUS Status = STATUS_SUCCESS; EnumIndex = *EnumerationContext; for (; EnumIndex < ARRAYSIZE(WellKnownPrivileges); EnumIndex++) { TRACE("EnumIndex: %lu\n", EnumIndex); TRACE("Privilege Name: %S\n", WellKnownPrivileges[EnumIndex].Name); TRACE("Name Length: %lu\n", wcslen(WellKnownPrivileges[EnumIndex].Name)); if ((RequiredLength + wcslen(WellKnownPrivileges[EnumIndex].Name) * sizeof(WCHAR) + sizeof(UNICODE_NULL) + sizeof(LSAPR_POLICY_PRIVILEGE_DEF)) > PreferedMaximumLength) { MoreEntries = TRUE; break; } RequiredLength += (wcslen(WellKnownPrivileges[EnumIndex].Name) * sizeof(WCHAR) + sizeof(UNICODE_NULL) + sizeof(LSAPR_POLICY_PRIVILEGE_DEF)); EnumCount++; } TRACE("EnumCount: %lu\n", EnumCount); TRACE("RequiredLength: %lu\n", RequiredLength); if (EnumCount == 0) goto done; Privileges = MIDL_user_allocate(EnumCount * sizeof(LSAPR_POLICY_PRIVILEGE_DEF)); if (Privileges == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto done; } EnumIndex = *EnumerationContext; for (i = 0; i < EnumCount; i++, EnumIndex++) { Privileges[i].LocalValue = WellKnownPrivileges[EnumIndex].Luid; Privileges[i].Name.Length = (USHORT)wcslen(WellKnownPrivileges[EnumIndex].Name) * sizeof(WCHAR); Privileges[i].Name.MaximumLength = (USHORT)Privileges[i].Name.Length + sizeof(UNICODE_NULL); Privileges[i].Name.Buffer = MIDL_user_allocate(Privileges[i].Name.MaximumLength); if (Privileges[i].Name.Buffer == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto done; } memcpy(Privileges[i].Name.Buffer, WellKnownPrivileges[EnumIndex].Name, Privileges[i].Name.Length); } done: if (NT_SUCCESS(Status)) { EnumerationBuffer->Entries = EnumCount; EnumerationBuffer->Privileges = Privileges; *EnumerationContext += EnumCount; } else { if (Privileges != NULL) { for (i = 0; i < EnumCount; i++) { if (Privileges[i].Name.Buffer != NULL) MIDL_user_free(Privileges[i].Name.Buffer); } MIDL_user_free(Privileges); } } if ((Status == STATUS_SUCCESS) && (MoreEntries == TRUE)) Status = STATUS_MORE_ENTRIES; return Status; }
DWORD VendorGetField( IN PRPL_SESSION pSession, IN DWORD FieldIndex, OUT LPVOID * pData, IN OUT LPINT pSpaceLeft ) { BYTE LocalBuffer[ 300]; PBYTE Buffer; DWORD DataSize; DWORD BufferSize; JET_ERR JetError; switch( FieldIndex) { case VENDOR_Flags: Buffer = (PBYTE)pData; BufferSize = sizeof( DWORD); break; default: Buffer = LocalBuffer; BufferSize = sizeof( LocalBuffer); break; } JetError = JetRetrieveColumn( pSession->SesId, pSession->VendorTableId, VendorTable[ FieldIndex].ColumnId, Buffer, BufferSize, &DataSize, 0, NULL); if ( JetError < 0) { RplDump( ++RG_Assert, ("JetError=%d", JetError)); return( NERR_RplVendorInfoCorrupted); } if ( Buffer != LocalBuffer) { if ( BufferSize == DataSize) { return( NO_ERROR); } else { RplDump( ++RG_Assert, ("Bad DataSize=0x%x", DataSize)); return( NERR_RplVendorInfoCorrupted); } } // // We have done with fixed data. From here on we deal with unicode // strings only. // if ( DataSize > sizeof( LocalBuffer)) { RplDump( ++RG_Assert, ( "Too big DataSize=0x%x", DataSize)); return( NERR_RplVendorInfoCorrupted); } if ( DataSize == 0) { if ( JetError != JET_wrnColumnNull) { RplDump( ++RG_Assert, ( "JetError=%d", JetError)); return( NERR_RplVendorInfoCorrupted); } else { *pData = NULL; // so RPC rpcrt4!_tree_size_ndr() does not bomb here return( NO_ERROR); } } if ( DataSize & 1 != 0 || wcslen((PWCHAR)LocalBuffer) + 1 != DataSize/2) { RplDump( ++RG_Assert, ("LocalBuffer=0x%x, DataSize=0x%x", LocalBuffer, DataSize)); return( NERR_RplVendorInfoCorrupted); } *pData = MIDL_user_allocate( DataSize); if ( *pData == NULL) { RplDump( ++RG_Assert, ( "Error=%d", GetLastError())); return( ERROR_NOT_ENOUGH_MEMORY); } memcpy( *pData, LocalBuffer, DataSize); *pSpaceLeft -= DataSize; return( NO_ERROR); }
NET_API_STATUS NET_API_FUNCTION NetrRplVendorEnum( IN RPL_RPC_HANDLE ServerHandle, IN OUT LPRPL_VENDOR_ENUM VendorEnum, IN DWORD PrefMaxLength, OUT LPDWORD TotalEntries, IN OUT LPDWORD pResumeHandle OPTIONAL ) /*++ Routine Description: Arguments: pServerHandle - ptr to RPL_HANDLE InfoStruct - Pointer to a structure that contains the information that RPC needs about the returned data. This structure contains the following information: Level - The desired information level - indicates how to interpret the structure of the returned buffer. EntriesRead - Indicates how many elements are returned in the array of structures that are returned. BufferPointer - Location for the pointer to the array of structures that are being returned. PrefMaxLen - Indicates a maximum size limit that the caller will allow for (the return buffer. TotalEntries - Pointer to a value that upon return indicates the total number of entries in the "active" database. pResumeHandle - Inidcates where to restart the enumeration. This is an optional parameter and can be NULL. Return Value: NO_ERROR if success. --*/ { LPBYTE Buffer; DWORD TypicalSize; DWORD CoreSize; DWORD Error; INT SpaceLeft; DWORD ArrayLength; DWORD EntriesRead; BOOL InfoError; BOOL TableEnd; PRPL_SESSION pSession = &RG_ApiSession; switch( VendorEnum->Level) { case 1: TypicalSize = CoreSize = sizeof( RPL_VENDOR_INFO_1); NOTHING; // fall through case 0: if ( VendorEnum->Level == 0) { TypicalSize = CoreSize = sizeof( RPL_VENDOR_INFO_0); } TypicalSize += 20 * sizeof( WCHAR); // typical size of VendorComment TypicalSize += 8 * sizeof( WCHAR); // typical size of VendorName break; default: return( ERROR_INVALID_LEVEL); break; } if ( PrefMaxLength == -1) { // // If the caller has not specified a size, calculate a size // that will hold the entire enumeration. // SpaceLeft = DEFAULT_BUFFER_SIZE; } else { SpaceLeft = PrefMaxLength; } // // Buffer space is shared by the array and by strings pointed at // by the elements in this array. We need to decide up front how much // space is allocated for array and how much for the strings. // ArrayLength = SpaceLeft / TypicalSize; if ( ArrayLength == 0) { ArrayLength = 1; // try to return at least one element } // // Note that MIDL_user_allocate() returns memory which is NOT initialized // to zero. Since we do NOT use allocate all nodes, this means that all // fields, especially pointers, in array elements must be properly set. // Buffer = MIDL_user_allocate( ArrayLength * CoreSize); if ( Buffer == NULL) { return( ERROR_NOT_ENOUGH_MEMORY); } RplDump( RG_DebugLevel & RPL_DEBUG_VENDOR, ( "VendorEnum: Buffer=0x%x, ArrayLength=0x%x", Buffer, ArrayLength)); VendorEnum->VendorInfo.Level0->Buffer = (LPRPL_VENDOR_INFO_0)Buffer; EntriesRead = 0; InfoError = FALSE; Error = NO_ERROR; EnterCriticalSection( &RG_ProtectDatabase); Call( JetBeginTransaction( pSession->SesId)); if ( !RplFilterFirst( pSession, VENDOR_TABLE_TAG, NULL, pResumeHandle, &TableEnd)) { Error = NERR_RplCannotEnum; goto cleanup; } if ( TableEnd == TRUE) { goto cleanup; } for ( ; ; ) { memset( Buffer, 0, CoreSize); // for cleanup to work properly Error = VendorGetInfo( pSession, NULL, VendorEnum->Level, Buffer, &SpaceLeft); if ( Error != NO_ERROR) { InfoError = TRUE; // clean things up without holding crit sec break; } EntriesRead++; Buffer += CoreSize; SpaceLeft -= CoreSize; if ( !RplFilterNext( pSession, pSession->VendorTableId, NULL, &TableEnd)) { Error = NERR_RplCannotEnum; goto cleanup; } if ( TableEnd == TRUE) { goto cleanup; } if ( SpaceLeft <= 0) { Error = ERROR_MORE_DATA; break; } if ( EntriesRead >= ArrayLength) { // // We have space available but allocated array is not big enough. // This should NOT happen often as our intent (see above) is to // overestimate array length. When it happens we can still try // to reallocate array to a larger size here. This is not done // for now (too cumbersome) & we just stop the enumeration. // Error = ERROR_MORE_DATA; break; } } cleanup: Call( JetCommitTransaction( pSession->SesId, 0)); LeaveCriticalSection( &RG_ProtectDatabase); if ( InfoError == TRUE) { VendorGetInfoCleanup( VendorEnum->Level, Buffer); } if ( Error == NO_ERROR) { *TotalEntries = EntriesRead; } else if ( Error == ERROR_MORE_DATA) { *TotalEntries = EntriesRead * 2; // we cheat here } else { // // Cleanup in case of "bad" errors. // while ( EntriesRead > 0) { EntriesRead--; Buffer -= CoreSize; VendorGetInfoCleanup( VendorEnum->Level, Buffer); } MIDL_user_free( Buffer); } RplDump( RG_DebugLevel & RPL_DEBUG_VENDOR, ("VendorEnum: EntriesRead = 0x%x", EntriesRead)); VendorEnum->VendorInfo.Level0->EntriesRead = EntriesRead; if ( EntriesRead == 0) { VendorEnum->VendorInfo.Level0->Buffer = NULL; } if ( ARGUMENT_PRESENT( pResumeHandle)) { if ( Error == ERROR_MORE_DATA && EntriesRead > 0) { EnterCriticalSection( &RG_ProtectDatabase); Call( JetBeginTransaction( pSession->SesId)); RplFilterSave( pSession, (DWORD)ServerHandle, NULL, ((LPRPL_VENDOR_INFO_0)(Buffer-CoreSize))->VendorName, pResumeHandle); Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush)); LeaveCriticalSection( &RG_ProtectDatabase); } else { *pResumeHandle = 0; // resume from beginning } } return( Error); }
VOID ReplicationManager ( IN PVOID ThreadParameter ) /*++ Routine Description: Arguments: ThreadParameter - Not used. Return Value: This thread never exits. --*/ { BOOL DoReplication = FALSE; NTSTATUS Status; LLS_REPL_HANDLE ReplHandle = NULL; LLS_HANDLE LlsHandle = NULL; PLLS_CONNECT_INFO_0 pConnectInfo; PREPL_REQUEST pReplInfo; TCHAR ReplicateTo[MAX_COMPUTERNAME_LENGTH + 3]; DWORD LastReplicated; LPTSTR pReplicateTo = ReplicateTo; TCHAR LastFailedConnectionDownlevelReplicateTo[MAX_COMPUTERNAME_LENGTH + 3] = TEXT(""); #if DBG if (TraceFlags & (TRACE_FUNCTION_TRACE | TRACE_REPLICATION)) dprintf(TEXT("LLS TRACE: ReplicationManager\n")); #endif // // Loop forever waiting to be given the opportunity to serve the // greater good. // for ( ; ; ) { // // Wait to be notified that there is work to be done // Status = NtWaitForSingleObject( ReplicationEvent, TRUE, NULL ); // // So they said, go replicate my son... Yeah, but first we must ask // the master for permission. // // // Construct our repl record // pReplInfo = MIDL_user_allocate(sizeof(REPL_REQUEST)); ASSERT(pReplInfo != NULL); if (pReplInfo != NULL) { RtlEnterCriticalSection(&ConfigInfoLock); lstrcpy(ReplicateTo, ConfigInfo.ReplicateTo); pReplInfo->EnterpriseServerDate = 0; lstrcpy(pReplInfo->EnterpriseServer, ConfigInfo.EnterpriseServer); pReplInfo->EnterpriseServerDate = ConfigInfo.EnterpriseServerDate; pReplInfo->LastReplicated = ConfigInfo.LastReplicatedSeconds; pReplInfo->CurrentTime = LastUsedTime; pReplInfo->NumberServices = 0; pReplInfo->NumberUsers = 0; pReplInfo->ReplSize = MAX_REPL_SIZE; pReplInfo->Backoff = 0; RtlLeaveCriticalSection(&ConfigInfoLock); #if DBG if (TraceFlags & TRACE_REPLICATION) dprintf(TEXT("LLS Starting Replication to: %s @ %s\n"), ReplicateTo, TimeToString(pReplInfo->CurrentTime)); #endif Status = (*pLlsReplConnect) ( ReplicateTo, &ReplHandle, 0, (LPBYTE *) &pConnectInfo ); if ( STATUS_SUCCESS != Status ) { #if DBG dprintf(TEXT("LLS Error: LlsReplConnect failed: 0x%lX\n"), Status); #endif ReplHandle = NULL; } else { Status = (*pLlsConnectW)( ReplicateTo, &LlsHandle ); if ( STATUS_SUCCESS != Status ) { #if DBG dprintf(TEXT("LLS Error: LlsConnectW failed: 0x%lX\n"), Status); #endif LlsHandle = NULL; } } if (Status != STATUS_SUCCESS) { DWORD dwWinError; DWORD dwBuildNumber; dwWinError = WinNtBuildNumberGet( ReplicateTo, &dwBuildNumber ); if ( ( ERROR_SUCCESS == dwWinError ) && ( dwBuildNumber < 1057L ) ) { // the ReplicateTo machine does not support the license service if ( lstrcmpi( ReplicateTo, LastFailedConnectionDownlevelReplicateTo ) ) { lstrcpy( LastFailedConnectionDownlevelReplicateTo, ReplicateTo ); LogEvent( LLS_EVENT_REPL_DOWNLEVEL_TARGET, 1, &pReplicateTo, Status ); } } else { // the ReplicateTo machine should be running the license service *LastFailedConnectionDownlevelReplicateTo = TEXT( '\0' ); LogEvent( LLS_EVENT_REPL_NO_CONNECTION, 1, &pReplicateTo, Status ); } } else { *LastFailedConnectionDownlevelReplicateTo = TEXT( '\0' ); Status = (*pLlsReplicationRequestW) ( ReplHandle, REPL_VERSION, pReplInfo ); if (Status != STATUS_SUCCESS) { LogEvent( LLS_EVENT_REPL_REQUEST_FAILED, 1, &pReplicateTo, Status ); } else { RtlEnterCriticalSection(&ConfigInfoLock); lstrcpy(ConfigInfo.EnterpriseServer, pReplInfo->EnterpriseServer); ConfigInfo.EnterpriseServerDate = pReplInfo->EnterpriseServerDate; ConfigInfo.IsReplicating = TRUE; LastReplicated = pReplInfo->LastReplicated; RtlLeaveCriticalSection(&ConfigInfoLock); // // And lo, thou may proceed... // if (pReplInfo->Backoff == 0) { if ( ConfigInfo.LogLevel ) { LogEvent( LLS_EVENT_REPL_START, 1, &pReplicateTo, ERROR_SUCCESS ); } Status = ReplicationDo( LlsHandle, ReplHandle, LastReplicated ); if ( STATUS_SUCCESS != Status ) { LogEvent( LLS_EVENT_REPL_FAILED, 1, &pReplicateTo, Status ); } else if ( ConfigInfo.LogLevel ) { LogEvent( LLS_EVENT_REPL_END, 1, &pReplicateTo, ERROR_SUCCESS ); } RtlEnterCriticalSection(&ConfigInfoLock); // // Need to update when next we should replicate // ConfigInfo.LastReplicatedSeconds = DateSystemGet(); GetLocalTime(&ConfigInfo.LastReplicated); ReplicationTimeSet(); } else { LogEvent( LLS_EVENT_REPL_BACKOFF, 1, &pReplicateTo, ERROR_SUCCESS ); RtlEnterCriticalSection(&ConfigInfoLock); } ConfigInfo.IsReplicating = FALSE; RtlLeaveCriticalSection(&ConfigInfoLock); } } // // Disconnect from Master Server // if ( NULL != LlsHandle ) { (*pLlsClose)( LlsHandle ); LlsHandle = NULL; } if ( NULL != ReplHandle ) { Status = (*pLlsReplClose) ( &ReplHandle ); try { RpcSmDestroyClientContext( &ReplHandle ); } except (TRUE) { Status = I_RpcMapWin32Status(RpcExceptionCode()); #if DBG dprintf(TEXT("ERROR LLSSRV.EXE (Repl): RPC Exception: 0x%lX\n"), Status); #endif } ReplHandle = NULL; } MIDL_user_free( pReplInfo ); }