/* Decompose a NetBIOS Second Layer name into an array of name components */ DWORD LWNetNbName2ToParts( PBYTE NbNameL2, PSTR **retNbNameParts, PDWORD retNbNamePartsLen) { DWORD dwError = 0; DWORD numParts = 0; DWORD len = 0; DWORD i = 0; UINT8 *ptr = NULL; PSTR *NBNameParts = NULL; /* Count number of parts in NetBIOS name */ ptr = NbNameL2; while (*ptr) { len = (int) *ptr++; ptr += len; numParts++; } len++; dwError = LWNetAllocateMemory((numParts+1) * sizeof(*NBNameParts), (PVOID*)&NBNameParts); BAIL_ON_LWNET_ERROR(dwError); /* Reset and allocate strings for the various parts */ ptr = NbNameL2; i = 0; while (*ptr) { len = (int) *ptr++; dwError = LWNetAllocateMemory((len + 1) * sizeof(char), (PVOID*)&NBNameParts[i]); BAIL_ON_LWNET_ERROR(dwError); strncat(NBNameParts[i++], (char *) ptr, len); ptr += len; } ptr++; *retNbNameParts = NBNameParts; *retNbNamePartsLen = ptr - NbNameL2; cleanup: return dwError; error: if (NBNameParts) { for (i=0; NBNameParts[i]; i++) { LWNET_SAFE_FREE_MEMORY(NBNameParts[i]); } LWNET_SAFE_FREE_MEMORY(NBNameParts); } goto cleanup; }
static DWORD LWNetFindServersInDomain( IN PDNS_SERVER_INFO pServerArray, IN DWORD dwServerCount, IN PCSTR pszDomainName, OUT PDNS_SERVER_INFO* ppServersInDomain, OUT PDWORD pdwServersInDomainCount ) { DWORD dwError = 0; DWORD i = 0; DWORD dwServersInDomainCount = 0; DWORD dwServerIndex = 0; PDNS_SERVER_INFO pServersInDomain = NULL; for (i = 0; i < dwServerCount; i++) { if (LWNetServerIsInDomain(&pServerArray[i], pszDomainName)) { dwServersInDomainCount++; } } if (dwServersInDomainCount) { dwError = LWNetAllocateMemory(dwServersInDomainCount * sizeof(*pServerArray), OUT_PPVOID(&pServersInDomain)); BAIL_ON_LWNET_ERROR(dwError); for (i = 0; i < dwServerCount; i++) { if (LWNetServerIsInDomain(&pServerArray[i], pszDomainName)) { pServersInDomain[dwServerIndex++] = pServerArray[i]; } } } *ppServersInDomain = pServersInDomain; *pdwServersInDomainCount = dwServersInDomainCount; cleanup: return dwError; error: *ppServersInDomain = NULL; *pdwServersInDomainCount = 0; LWNET_SAFE_FREE_MEMORY(pServersInDomain); goto cleanup; }
DWORD LWNetNbConstructNameQuery( IN PSTR pszNetBiosHost, IN UINT8 bBroadcast, IN UINT8 queryType, OUT UINT16 *RetTransactionId, OUT UINT8 *NetBiosQuery, OUT PDWORD NetBiosQueryLen) { DWORD dwError = 0; DWORD len = 0; DWORD NbNameLevel2Len = 0; UINT8 *NbNameLevel2 = NULL; UINT8 BuiltNBHeader[LWNB_NAME_MAX_LENGTH] = {0}; UINT16 TransactionId = 0; dwError = LWNetNbStrToNbName2( pszNetBiosHost, queryType, &NbNameLevel2, &NbNameLevel2Len); BAIL_ON_LWNET_ERROR(dwError); TransactionId = LWNetNbNextTransactionId(gpNbCtx); dwError = LWNetNbConstructNameQueryHeader( TransactionId, bBroadcast ? LWNB_QUERY_BROADCAST : LWNB_QUERY_WINS, LWNB_OPCODE_QUERY, 1, // QDCOUNT: Number of names being looked up sizeof(BuiltNBHeader), BuiltNBHeader); BAIL_ON_LWNET_ERROR(dwError); /* Assemble the complete marshaled NetBIOS query packet */ memcpy(&NetBiosQuery[len], BuiltNBHeader, LWNB_NAME_QUERY_HEADER_SIZE); len += LWNB_NAME_QUERY_HEADER_SIZE; memcpy(&NetBiosQuery[len], NbNameLevel2, NbNameLevel2Len); len += NbNameLevel2Len; memcpy(&NetBiosQuery[len], NetBiosQueryFooter, sizeof(NetBiosQueryFooter)); len += sizeof(NetBiosQueryFooter); *NetBiosQueryLen = len; *RetTransactionId = TransactionId; cleanup: LWNET_SAFE_FREE_MEMORY(NbNameLevel2); return dwError; error: goto cleanup; }
VOID LWNetSrvNetBiosCleanup( VOID ) { if (!gpNbCtx) { return; } pthread_mutex_destroy(&gpNbCtx->mutex); pthread_mutex_destroy(&gpNbCtx->mutexAck); pthread_cond_destroy(&gpNbCtx->cv); pthread_cond_destroy(&gpNbCtx->cvAck); LWNET_SAFE_FREE_MEMORY(gpNbCtx); }
DWORD LWNetDnsParseName( IN PDNS_RESPONSE_HEADER pHeader, IN PBYTE pData, OUT PDWORD pdwBytesToAdvance, OUT OPTIONAL PSTR* ppszName ) { DWORD dwError = 0; DWORD dwBytesToAdvance = 0; DWORD dwNameLen = 0; PSTR pszName = NULL; /* Figure out the size and how many bytes the parse will advance */ LWNetDnsParseNameWorker(pHeader, pData, &dwBytesToAdvance, &dwNameLen, NULL); if (ppszName) { /* Now allocate the memory, overallocating to ensure NULL termination in case the DNS packet does not termiante */ dwError = LWNetAllocateMemory((dwNameLen+3) * sizeof(CHAR), (PVOID*)&pszName); BAIL_ON_LWNET_ERROR(dwError); /* Fill in the name */ LWNetDnsParseNameWorker(pHeader, pData, NULL, NULL, pszName); /* Ensure NULL termination */ pszName[dwNameLen] = 0; } error: if (dwError) { LWNET_SAFE_FREE_MEMORY(pszName); } *pdwBytesToAdvance = dwBytesToAdvance; if (ppszName) { *ppszName = pszName; } return dwError; }
VOID LWNetNbAddressListFree( IN struct in_addr *retAddrs) { LWNET_SAFE_FREE_MEMORY(retAddrs); }
DWORD LWNetNbParseNameQueryResponse( IN PBYTE buf, IN DWORD len, IN UINT16 TransactionId, OUT UINT16 *retTransactionId, OUT PSTR *retNbName, OUT UINT32 *retTTL, OUT UINT8 *retFlags, OUT struct in_addr **retAddrs, OUT PDWORD retAddrsLen) { DWORD dwError = 0; DWORD i = 0; DWORD j = 0; UINT16 parseTransactionId = 0; UINT16 opCodeFlags = 0; UINT16 bResponse = 0; UINT16 nbQDCount = 0; UINT16 nbANCount = 0; UINT16 nbNSCount = 0; UINT16 nbARCount = 0; UINT16 nbNB = 0; UINT16 nbIN = 0; UINT32 nbTTL = 0; UINT16 nbNB_Flags = 0; UINT32 IpAddress = 0; UINT16 RDLength = 0; UINT8 queryType = 0; PSTR NetBiosName = NULL; PSTR NbName = NULL; DWORD numAddrs = 0; DWORD nbNameLen = 0; struct in_addr *addrs = NULL; memcpy(&parseTransactionId, &buf[i], sizeof(parseTransactionId)); i += sizeof(parseTransactionId); parseTransactionId = ntohs(parseTransactionId); if (retTransactionId) { *retTransactionId = parseTransactionId; } memcpy(&opCodeFlags, &buf[i], sizeof(opCodeFlags)); i += sizeof(opCodeFlags); opCodeFlags = ntohs(opCodeFlags); bResponse = opCodeFlags & (1 << LWNB_SHIFT_REQUEST_TYPE) ? 1 : 0; #if 0 /* Deal with other flags later... Not sure it matters at this point */ opCodeFlags |= (bBroadcast & 1) << LWNB_SHIFT_FLAG_BROADCAST; opCodeFlags |= 1 << LWNB_SHIFT_FLAG_RECURSION_DESIRED; opCodeFlags |= (opcode & 4) << LWNB_SHIFT_OPCODE; #endif if (bResponse != LWNB_OPCODE_RESPONSE) { /* Something is seriously wrong if this is not a NetBIOS response */ dwError = ERROR_BAD_NET_RESP; BAIL_ON_LWNET_ERROR(dwError); } memcpy(&nbQDCount, &buf[i], sizeof(nbQDCount)); i += sizeof(nbQDCount); nbQDCount = ntohs(nbQDCount); memcpy(&nbANCount, &buf[i], sizeof(nbANCount)); i += sizeof(nbANCount); nbANCount = ntohs(nbANCount); if (nbANCount != 1) { /* There must be exactly 1 answer to the sent query */ dwError = ERROR_BAD_NET_RESP; BAIL_ON_LWNET_ERROR(dwError); } memcpy(&nbNSCount, &buf[i], sizeof(nbNSCount)); i += sizeof(nbNSCount); nbNSCount = ntohs(nbNSCount); memcpy(&nbARCount, &buf[i], sizeof(nbARCount)); i += sizeof(nbARCount); nbARCount = ntohs(nbARCount); dwError = LWNetNbName2ToStr( &buf[i], &NetBiosName, &queryType, &nbNameLen); BAIL_ON_LWNET_ERROR(dwError); i += nbNameLen; memcpy(&nbNB, &buf[i], sizeof(nbNB)); i += sizeof(nbNB); nbNB = ntohs(nbNB); memcpy(&nbIN, &buf[i], sizeof(nbIN)); i += sizeof(nbIN); nbIN = ntohs(nbIN); if (nbNB != 0x0020 || nbIN != 0x0001) { /* RFC 1002 says these must be the values for these fields */ dwError = ERROR_BAD_NET_RESP; BAIL_ON_LWNET_ERROR(dwError); } memcpy(&nbTTL, &buf[i], sizeof(nbTTL)); i += sizeof(nbTTL); nbTTL = ntohl(nbTTL); if (retTTL) { *retTTL = nbTTL; } memcpy(&RDLength, &buf[i], sizeof(RDLength)); i += sizeof(RDLength); RDLength = ntohs(RDLength); numAddrs = RDLength / (sizeof(nbNB_Flags) + sizeof(IpAddress)); dwError = LWNetAllocateMemory( numAddrs * sizeof(struct in_addr), (PVOID*) &addrs); BAIL_ON_LWNET_ERROR(dwError); j = 0; do { memcpy(&nbNB_Flags, &buf[i], sizeof(nbNB_Flags)); i += sizeof(nbNB_Flags); nbNB_Flags = ntohs(nbNB_Flags); nbNB_Flags >>= 13; *retFlags = nbNB_Flags; memcpy(&IpAddress, &buf[i], sizeof(IpAddress)); i += sizeof(IpAddress); addrs[j++].s_addr = IpAddress; RDLength -= sizeof(nbNB_Flags) + sizeof(IpAddress); } while (RDLength > 0); *retNbName = NetBiosName; *retAddrs = addrs; *retAddrsLen = j; cleanup: return dwError; error: LWNET_SAFE_FREE_MEMORY(NetBiosName); LWNET_SAFE_FREE_MEMORY(NbName); LWNET_SAFE_FREE_MEMORY(addrs); goto cleanup; }
/* Convert NetBIOS level 2 encoded name to a string */ DWORD LWNetNbName2ToStr( IN PBYTE buf, OUT PSTR *ppNbName, OUT PUINT8 pSuffix, OUT PDWORD dwBytesConsumed) { DWORD dwError = 0; PSTR *NbNameParts2 = NULL; PSTR NbName = NULL; CHAR netBiosName[LWNB_NAME_MAX_LENGTH] = {0}; DWORD addrsLen = 0; DWORD nbNameOffset = 0; DWORD i = 0; dwError = LWNetNbName2ToParts(&buf[i], &NbNameParts2, &addrsLen); BAIL_ON_LWNET_ERROR(dwError); dwError = LWNetAllocateMemory( addrsLen * sizeof(char), (PVOID*) &NbName); BAIL_ON_LWNET_ERROR(dwError); nbNameOffset = 0; for (i=0; NbNameParts2[i]; i++) { if (i==0) { /* * Convert first part of name, which is in NetBIOS layer 1 encoding * to a null-terminated string. */ LWNetNbNameToStr((UINT8 *) NbNameParts2[i], netBiosName, pSuffix); strncat(NbName, netBiosName, addrsLen - nbNameOffset); nbNameOffset += strlen(netBiosName); } else { /* The rest of the name is just text, so copy it */ strncat(NbName, ".", addrsLen - nbNameOffset); nbNameOffset++; strncat(NbName, NbNameParts2[i], addrsLen - nbNameOffset); nbNameOffset += strlen(NbNameParts2[i]); } } *ppNbName = NbName; *dwBytesConsumed = addrsLen; cleanup: for (i=0; NbNameParts2[i]; i++) { LWNET_SAFE_FREE_MEMORY(NbNameParts2[i]); } LWNET_SAFE_FREE_MEMORY(NbNameParts2); return dwError; error: LW_SAFE_FREE_MEMORY(NbName); goto cleanup; }
static DWORD LWNetNbResolveNameUdp( PSTR pszHostName, PSTR winsServer, UINT8 queryType, OUT struct in_addr **retAddrs, OUT PDWORD retAddrsLen) { DWORD dwError = 0; UINT16 transactionId = 0; UINT8 *NetBiosQuery = NULL; DWORD NetBiosQueryLen = 0; struct sockaddr_in dgAddr; struct timespec cvTimeout = {0}; struct timeval tp = {0}; struct in_addr *resAddrs = NULL; struct in_addr *tmpResAddrs = NULL; int sts = 0; DWORD i = 0; DWORD resAddrsLen = 0; DWORD resAddrsAllocLen = 128; DWORD commType = 0; BOOLEAN bLocked = FALSE; dwError = LWNetAllocateMemory( LWNB_NETBIOS_UDP_MAX, (PVOID*) &NetBiosQuery); BAIL_ON_LWNET_ERROR(dwError); memset(&dgAddr, 0, sizeof(dgAddr)); dgAddr.sin_family = AF_INET; dgAddr.sin_port = htons(137); if (winsServer && *winsServer) { sts = inet_aton(winsServer, &dgAddr.sin_addr); if (sts == -1) { dwError = LwErrnoToWin32Error(ERROR_INCORRECT_ADDRESS); BAIL_ON_LWNET_ERROR(dwError); } commType = LWNB_QUERY_WINS; dwError = LWNetNbConstructNameQuery( pszHostName, commType, queryType, &transactionId, NetBiosQuery, &NetBiosQueryLen); BAIL_ON_LWNET_ERROR(dwError); } else { dgAddr.sin_addr.s_addr = htonl(INADDR_BROADCAST); commType = LWNB_QUERY_BROADCAST; dwError = LWNetNbConstructNameQuery( pszHostName, commType, queryType, &transactionId, NetBiosQuery, &NetBiosQueryLen); BAIL_ON_LWNET_ERROR(dwError); } // If this is not enough memory, realloc below fixes that dwError = LWNetAllocateMemory( resAddrsAllocLen * sizeof(struct in_addr), (PVOID*) &resAddrs); BAIL_ON_LWNET_ERROR(dwError); pthread_mutex_lock(&gpNbCtx->mutex); bLocked = TRUE; sts = sendto(gpNbCtx->sock, NetBiosQuery, NetBiosQueryLen, 0, /* flags */ (struct sockaddr *) &dgAddr, sizeof(dgAddr)); if (sts == -1) { dwError = ERROR_NET_WRITE_FAULT; BAIL_ON_LWNET_ERROR(dwError); } do { gettimeofday(&tp, NULL); cvTimeout.tv_sec = tp.tv_sec + gpNbCtx->udpTimeout; cvTimeout.tv_nsec = tp.tv_usec * 1000; do { sts = pthread_cond_timedwait( &gpNbCtx->cv, &gpNbCtx->mutex, &cvTimeout); } while (!gpNbCtx->bNbRepsponse && sts != ETIMEDOUT); if (sts == 0 && gpNbCtx->transactionId == transactionId) { gpNbCtx->bNbRepsponse = FALSE; if ((commType == LWNB_QUERY_WINS && gpNbCtx->respError == 0) || (commType == LWNB_QUERY_BROADCAST)) { if ((gpNbCtx->addrsLen + resAddrsLen) > resAddrsAllocLen) { resAddrsAllocLen = resAddrsAllocLen * 2 + gpNbCtx->addrsLen; tmpResAddrs = LwRtlMemoryRealloc( resAddrs, resAddrsAllocLen); if (!tmpResAddrs) { dwError = ERROR_NOT_ENOUGH_MEMORY; BAIL_ON_LWNET_ERROR(dwError); } resAddrs = tmpResAddrs; tmpResAddrs = NULL; } for (i=0; i<gpNbCtx->addrsLen; i++) { memcpy(&resAddrs[resAddrsLen++], &gpNbCtx->addrs[i], sizeof(struct in_addr)); } } pthread_mutex_lock(&gpNbCtx->mutexAck); gpNbCtx->bAck = TRUE; pthread_mutex_unlock(&gpNbCtx->mutexAck); pthread_cond_signal(&gpNbCtx->cvAck); if (commType == LWNB_QUERY_WINS && gpNbCtx->respError) { // Bail when WINS query fails to resolve the hostname dwError = gpNbCtx->respError; BAIL_ON_LWNET_ERROR(dwError); } } } while (commType == LWNB_QUERY_BROADCAST && sts != ETIMEDOUT); bLocked = FALSE; pthread_mutex_unlock(&gpNbCtx->mutex); if (resAddrsLen == 0) { dwError = ERROR_BAD_NET_NAME; BAIL_ON_LWNET_ERROR(dwError); } *retAddrs = resAddrs; *retAddrsLen = resAddrsLen; cleanup: if (bLocked) { pthread_mutex_unlock(&gpNbCtx->mutex); } LWNET_SAFE_FREE_MEMORY(NetBiosQuery); return dwError; error: LWNET_SAFE_FREE_MEMORY(resAddrs); goto cleanup; }
DWORD LWNetDnsBuildServerArray( IN PDLINKEDLIST pSrvRecordList, OUT PDNS_SERVER_INFO* ppServerArray, OUT PDWORD pdwServerCount ) { DWORD dwError = 0; DWORD dwServerCount = 0; PDNS_SERVER_INFO pServerArray = NULL; PDLINKEDLIST pListMember = NULL; PDNS_SRV_INFO_RECORD pSrvRecord = NULL; DWORD dwServerIndex = 0; DWORD dwStringSize = 0; DWORD dwRequiredSize = 0; PSTR pStringLocation = NULL; for (pListMember = pSrvRecordList; pListMember; pListMember = pListMember->pNext) { pSrvRecord = (PDNS_SRV_INFO_RECORD)pListMember->pItem; dwStringSize += strlen(pSrvRecord->pszAddress) + 1; dwStringSize += strlen(pSrvRecord->pszTarget) + 1; dwServerCount++; } if (dwServerCount < 1) { // nothing to do, so we are done dwError = 0; goto error; } dwRequiredSize = dwServerCount * sizeof(DNS_SERVER_INFO) + dwStringSize; dwError = LWNetAllocateMemory(dwRequiredSize, (PVOID*)&pServerArray); BAIL_ON_LWNET_ERROR(dwError); pStringLocation = CT_PTR_ADD(pServerArray, dwServerCount * sizeof(DNS_SERVER_INFO)); dwServerIndex = 0; for (pListMember = pSrvRecordList; pListMember; pListMember = pListMember->pNext) { PSTR source; pSrvRecord = (PDNS_SRV_INFO_RECORD)pListMember->pItem; // Copy the strings into the buffer pServerArray[dwServerIndex].pszAddress = pStringLocation; for (source = pSrvRecord->pszAddress; source[0]; source++) { pStringLocation[0] = source[0]; pStringLocation++; } pStringLocation[0] = source[0]; pStringLocation++; pServerArray[dwServerIndex].pszName = pStringLocation; for (source = pSrvRecord->pszTarget; source[0]; source++) { pStringLocation[0] = source[0]; pStringLocation++; } pStringLocation[0] = source[0]; pStringLocation++; dwServerIndex++; } // TODO: Turns this into ASSERT if (CT_PTR_OFFSET(pServerArray, pStringLocation) != dwRequiredSize) { LWNET_LOG_ERROR("ASSERT - potential buffer overflow"); } error: if (dwError) { LWNET_SAFE_FREE_MEMORY(pServerArray); dwServerCount = 0; } *ppServerArray = pServerArray; *pdwServerCount = dwServerCount; return dwError; }
static DWORD LWNetSrvGetDCNameDiscoverInternal( IN PCSTR pszDnsDomainName, IN OPTIONAL PCSTR pszSiteName, IN OPTIONAL PCSTR pszPrimaryDomain, IN DWORD dwDsFlags, IN DWORD dwBlackListCount, IN OPTIONAL PSTR* ppszAddressBlackList, IN PLWNET_DC_LIST_QUERY_METHOD pfnDCListQuery, OUT PLWNET_DC_INFO* ppDcInfo, OUT OPTIONAL PDNS_SERVER_INFO* ppServerArray, OUT OPTIONAL PDWORD pdwServerCount, OUT PBOOLEAN pbFailedFindWritable ) // // Algorithm: // // - DNS query for desired site & required DC type (pdc, kdc, gc). // - note that if no site is specified, use "un-sited" lookup. // - If no site specified: // - CLDAP to one DC to get actual site // - use new site info that to do DNS query for updated DC list // - CLDAP to DCs in parallel to find the first responder // (meeting any additional criteria -- writable, etc) // { DWORD dwError = 0; PLWNET_DC_INFO pDcInfo = NULL; PDNS_SERVER_INFO pServerArray = NULL; PDNS_SERVER_INFO pServersInPrimaryDomain = NULL; DWORD dwServersInPrimaryDomainCount = 0; DWORD dwServerCount = 0; PLWNET_DC_INFO pSiteDcInfo = NULL; PDNS_SERVER_INFO pSiteServerArray = NULL; DWORD dwSiteServerCount = 0; BOOLEAN bFailedFindWritable = FALSE; // Get server list dwError = pfnDCListQuery(pszDnsDomainName, pszSiteName, dwDsFlags, &pServerArray, &dwServerCount); BAIL_ON_LWNET_ERROR(dwError); LWNetFilterFromBlackList( dwBlackListCount, ppszAddressBlackList, &dwServerCount, pServerArray); if (!dwServerCount) { dwError = ERROR_DOMAIN_BLACKLISTED; BAIL_ON_LWNET_ERROR(dwError); } if (pszPrimaryDomain) { dwError = LWNetFindServersInDomain( pServerArray, dwServerCount, pszPrimaryDomain, &pServersInPrimaryDomain, &dwServersInPrimaryDomainCount); BAIL_ON_LWNET_ERROR(dwError); LWNetFilterFromBlackList( dwBlackListCount, ppszAddressBlackList, &dwServersInPrimaryDomainCount, pServersInPrimaryDomain); if (dwServersInPrimaryDomainCount > 0) { dwError = LWNetSrvPingCLdapArray(pszDnsDomainName, dwDsFlags, pServersInPrimaryDomain, dwServersInPrimaryDomainCount, 0, &pDcInfo, &bFailedFindWritable); } if (dwServersInPrimaryDomainCount == 0 || dwError == NERR_DCNotFound) { dwError = LWNetSrvPingCLdapArray(pszDnsDomainName, dwDsFlags, pServerArray, dwServerCount, 0, &pDcInfo, &bFailedFindWritable); BAIL_ON_LWNET_ERROR(dwError); } } else { // Do CLDAP dwError = LWNetSrvPingCLdapArray(pszDnsDomainName, dwDsFlags, pServerArray, dwServerCount, 0, &pDcInfo, &bFailedFindWritable); BAIL_ON_LWNET_ERROR(dwError); } // If there is no client site, then we are done (though we do not // expect this to ever happen). if (IsNullOrEmptyString(pDcInfo->pszClientSiteName)) { LWNET_LOG_ALWAYS("Missing client site name from " "DC response from %s (%s)", LWNET_SAFE_LOG_STRING(pDcInfo->pszDomainControllerName), LWNET_SAFE_LOG_STRING(pDcInfo->pszDomainControllerAddress)); goto cleanup; } // If a site was passed in, there is nothing more to do. if (!IsNullOrEmptyString(pszSiteName)) { goto cleanup; } // There was no site passed in, so we need to look at the // CLDAP response to get the client site. // If we got the correct site already, we are done. if (LWNetSrvIsInSameSite(pDcInfo)) { if (LWNetIsUpdateKrb5AffinityEnabled(dwDsFlags, pszSiteName, pDcInfo) && !pszSiteName && pDcInfo->pszClientSiteName) { dwError = pfnDCListQuery( pszDnsDomainName, pDcInfo->pszClientSiteName, dwDsFlags, &pSiteServerArray, &dwSiteServerCount); if (dwError == 0) { // Use the site-specific DC. LWNET_SAFE_FREE_MEMORY(pServerArray); dwServerCount = 0; LWNetFilterFromBlackList( dwBlackListCount, ppszAddressBlackList, &dwSiteServerCount, pSiteServerArray); if (!dwSiteServerCount) { dwError = DNS_ERROR_BAD_PACKET; BAIL_ON_LWNET_ERROR(dwError); } pServerArray = pSiteServerArray; dwServerCount = dwSiteServerCount; pSiteServerArray = NULL; dwSiteServerCount = 0; } } dwError = 0; goto cleanup; } // Now we need to use the client site to find a site-specific DC. dwError = LWNetSrvGetDCNameDiscover(pszDnsDomainName, pDcInfo->pszClientSiteName, pszPrimaryDomain, dwDsFlags, dwBlackListCount, ppszAddressBlackList, &pSiteDcInfo, &pSiteServerArray, &dwSiteServerCount, &bFailedFindWritable); if (NERR_DCNotFound == dwError) { if (bFailedFindWritable) { LWNET_LOG_WARNING("No writable DC in client site '%s' for domain '%s'", pDcInfo->pszClientSiteName, pszDnsDomainName); } // Count not find site-specific DC, so use the original DC. dwError = 0; goto cleanup; } BAIL_ON_LWNET_ERROR(dwError); // Use the site-specific DC. LWNET_SAFE_FREE_DC_INFO(pDcInfo); LWNET_SAFE_FREE_MEMORY(pServerArray); dwServerCount = 0; pDcInfo = pSiteDcInfo; pServerArray = pSiteServerArray; dwServerCount = dwSiteServerCount; pSiteDcInfo = NULL; pSiteServerArray = NULL; dwSiteServerCount = 0; error: cleanup: LWNET_SAFE_FREE_DC_INFO(pSiteDcInfo); LWNET_SAFE_FREE_MEMORY(pSiteServerArray); LWNET_SAFE_FREE_MEMORY(pServersInPrimaryDomain); dwSiteServerCount = 0; if (dwError) { LWNET_SAFE_FREE_DC_INFO(pDcInfo); LWNET_SAFE_FREE_MEMORY(pServerArray); dwServerCount = 0; } *ppDcInfo = pDcInfo; if (ppServerArray) { *ppServerArray = pServerArray; *pdwServerCount = dwServerCount; } else { LWNET_SAFE_FREE_MEMORY(pServerArray); } *pbFailedFindWritable = bFailedFindWritable; return dwError; }
static DWORD LWNetSrvPingCLdapProcess( IN PLWNET_CLDAP_CONNECTION_CONTEXT pContext, IN DWORD dwDsFlags, IN LWNET_UNIX_MS_TIME_T StopTime, OUT PLWNET_DC_INFO* ppDcInfo, OUT PBOOLEAN pbFailedFindWritable ) { DWORD dwError = 0; DWORD dwResultType = 0; LDAPMessage* pMessage = NULL; PBYTE pNetlogonAttributeValue = NULL; DWORD dwNetlogonAttributeSize = 0; PLWNET_DC_INFO pDcInfo = NULL; BOOLEAN bFailedFindWritable = FALSE; struct timeval timeout = {0}; LDAP *ld = NULL; ld = LwLdapGetSession(pContext->hDirectory); dwResultType = ldap_result( ld, pContext->msgid, 0, &timeout, &pMessage); if (dwResultType == 0) { // timed out goto error; } else if (dwResultType == -1) { // -1 = problem dwError = LDAP_NO_SUCH_OBJECT; LWNET_LOG_VERBOSE("Caught LDAP_NO_SUCH_OBJECT Error on ldap search"); } else { // returns result type if (dwResultType != LDAP_RES_SEARCH_ENTRY) { dwError = LDAP_NO_SUCH_OBJECT; LWNET_LOG_DEBUG("Caught incorrect result type on ldap search: %d", dwError); } } dwError = LwMapLdapErrorToLwError(dwError); BAIL_ON_LWNET_ERROR(dwError); dwError = LwLdapGetBytes( pContext->hDirectory, pMessage, NETLOGON_LDAP_ATTRIBUTE_NAME, &pNetlogonAttributeValue, &dwNetlogonAttributeSize); BAIL_ON_LWNET_ERROR(dwError); dwError = LWNetBuildDCInfo(pNetlogonAttributeValue, dwNetlogonAttributeSize, &pDcInfo); BAIL_ON_LWNET_ERROR(dwError); dwError = LWNetAllocateString(pContext->pServerInfo->pszAddress, &pDcInfo->pszDomainControllerAddress); BAIL_ON_LWNET_ERROR(dwError); pDcInfo->dwPingTime = (DWORD)(StopTime - pContext->StartTime); if (StopTime < pContext->StartTime) { LWNET_LOG_ERROR("Stop time is earlier than start time"); } if (!LWNetSrvIsMatchingDcInfo(pDcInfo, dwDsFlags)) { dwError = LW_ERROR_NO_SUCH_OBJECT; if (LWNetSrvIsMatchingDcInfo(pDcInfo, dwDsFlags & ~DS_WRITABLE_REQUIRED)) { // We found something, but it failed only because it did // not satisfy writability. bFailedFindWritable = TRUE; } } error: if (pMessage) { ldap_msgfree(pMessage); } LWNET_SAFE_FREE_MEMORY(pNetlogonAttributeValue); if (dwError) { LWNET_SAFE_FREE_DC_INFO(pDcInfo); LWNetSrvPingCLdapEnd(pContext); } *ppDcInfo = pDcInfo; *pbFailedFindWritable = bFailedFindWritable; return dwError; }
DWORD LWNetDnsSrvQuery( IN PCSTR pszDnsDomainName, IN OPTIONAL PCSTR pszSiteName, IN DWORD dwDsFlags, OUT PDNS_SERVER_INFO* ppServerArray, OUT PDWORD pdwServerCount ) // Call LWNET_SAFE_FREE_MEMORY on returned server array { DWORD dwError = 0; PSTR pszQuestion = NULL; const size_t dwBufferSize = (64 * 1024); PVOID pBuffer = NULL; PDNS_RESPONSE_HEADER pResponse = NULL; DWORD dwResponseSize = 0; PDLINKEDLIST pAnswersList = NULL; PDLINKEDLIST pAdditionalsList = NULL; PDLINKEDLIST pSRVRecordList = NULL; PDNS_SERVER_INFO pServerArray = NULL; DWORD dwServerCount = 0; // TODO - Handle trailing dot in domain; handle no dots in domain dwError = LWNetDnsGetSrvRecordQuestion(&pszQuestion, pszDnsDomainName, pszSiteName, dwDsFlags); BAIL_ON_LWNET_ERROR(dwError); dwError = LWNetAllocateMemory(dwBufferSize, &pBuffer); BAIL_ON_LWNET_ERROR(dwError); dwError = LWNetDnsQueryWithBuffer(pszQuestion, TRUE, FALSE, pBuffer, dwBufferSize, &dwResponseSize); BAIL_ON_LWNET_ERROR(dwError); pResponse = (PDNS_RESPONSE_HEADER) pBuffer; if (LWNetDnsIsTruncatedResponse(pResponse)) { dwError = LWNetDnsQueryWithBuffer(pszQuestion, FALSE, TRUE, pBuffer, dwBufferSize, &dwResponseSize); BAIL_ON_LWNET_ERROR(dwError); } // TODO: Add dwResponseSize validation to parsing. // Decode DNS response w/o taking into account record type dwError = LWNetDnsParseQueryResponse(pResponse, &pAnswersList, NULL, &pAdditionalsList); BAIL_ON_LWNET_ERROR(dwError); // Decode SRV records dwError = LWNetDnsBuildSRVRecordList(pResponse, pAnswersList, pAdditionalsList, &pSRVRecordList); BAIL_ON_LWNET_ERROR(dwError); // Create list of server names and addresses dwError = LWNetDnsBuildServerArray(pSRVRecordList, &pServerArray, &dwServerCount); BAIL_ON_LWNET_ERROR(dwError); error: LWNET_SAFE_FREE_STRING(pszQuestion); LWNET_SAFE_FREE_MEMORY(pBuffer); LWNET_SAFE_FREE_DNS_RECORD_LINKED_LIST(pAnswersList); LWNET_SAFE_FREE_DNS_RECORD_LINKED_LIST(pAdditionalsList); LWNET_SAFE_FREE_SRV_INFO_LINKED_LIST(pSRVRecordList); if (dwError) { LWNET_SAFE_FREE_MEMORY(pServerArray); dwServerCount = 0; } *ppServerArray= pServerArray; *pdwServerCount = dwServerCount; return dwError; }
VOID *LWNetSrvStartNetBiosThreadRoutine(VOID *ctx) { DWORD dwError = 0; struct pollfd pollfds[1]; int sts = 0; int sock = 0; UINT8 *NetBiosReply = NULL; struct sockaddr_in dgAddr; int NetBiosReplyAddrLen = 0; void *pNetBiosReplyAddrLen = &NetBiosReplyAddrLen; PLWNET_SRV_NETBIOS_CONTEXT pNbCtx = (PLWNET_SRV_NETBIOS_CONTEXT) ctx; int allowBroadcast = 1; UINT8 Flags = 0; UINT16 respTransactionId = 0; PSTR NbName = NULL; struct in_addr *addrs = NULL; DWORD addrsLen = 0; struct timeval tp = {0}; struct timespec cvTimeout = {0}; dwError = LWNetAllocateMemory( LWNB_NETBIOS_UDP_MAX, (PVOID*) &NetBiosReply); sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == -1) { dwError = ERROR_INVALID_HANDLE; BAIL_ON_LWNET_ERROR(dwError); } sts = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &allowBroadcast, sizeof(allowBroadcast)); if (sts == -1) { dwError = ERROR_INVALID_HANDLE; BAIL_ON_LWNET_ERROR(dwError); } pthread_mutex_lock(&pNbCtx->mutex); pNbCtx->sock = sock; pthread_mutex_unlock(&pNbCtx->mutex); do { memset(pollfds, 0, sizeof(pollfds)); pollfds[0].fd = sock; pollfds[0].events = POLLIN; sts = poll(pollfds, 1, -1); if (sts > 0 && pollfds[0].revents) { sts = recvfrom( sock, NetBiosReply, LWNB_NETBIOS_UDP_MAX, 0, /* flags */ (struct sockaddr *) &dgAddr, pNetBiosReplyAddrLen); if (sts > 0) { dwError = LWNetNbParseNameQueryResponse( NetBiosReply, sts, 0, // remove this argument &respTransactionId, &NbName, NULL, &Flags, &addrs, &addrsLen); pthread_mutex_lock(&pNbCtx->mutex); pNbCtx->respError = dwError; pNbCtx->transactionId = respTransactionId; pNbCtx->addrs = addrs; pNbCtx->addrsLen = addrsLen; pNbCtx->bNbRepsponse = TRUE; pthread_mutex_lock(&pNbCtx->mutexAck); pthread_mutex_unlock(&pNbCtx->mutex); pthread_cond_broadcast(&pNbCtx->cv); // Wait for LWNetNbResolveName ack address received do { gettimeofday(&tp, NULL); cvTimeout.tv_sec = tp.tv_sec + pNbCtx->udpTimeout; cvTimeout.tv_nsec = tp.tv_usec * 1000; sts = pthread_cond_timedwait( &pNbCtx->cvAck, &pNbCtx->mutexAck, &cvTimeout); } while (!pNbCtx->bAck && sts != ETIMEDOUT); pNbCtx->bAck = FALSE; pthread_mutex_unlock(&pNbCtx->mutexAck); } } } while (!pNbCtx->bShutdown); LWNET_LOG_INFO("Stopping NetBIOS listener thread"); cleanup: LWNET_SAFE_FREE_MEMORY(NetBiosReply); LWNET_SAFE_FREE_STRING(NbName); if (sock != -1) { close(sock); } return NULL; error: goto cleanup; }
/* "Second Level" NetBIOS name encoding */ DWORD LWNetNbStrToNbName2( PSTR Fqdn, UINT8 suffix, PBYTE *retNbNameL2, PDWORD retNbNameL2Len) { DWORD dwError = 0; DWORD len = 0; PSTR p = NULL; PSTR token = NULL; PSTR tokenPtr = NULL; UINT8 *retName = NULL; UINT8 *up = NULL; /* * 32=Max NetBIOS First Level encoding length * All . separators are replaced by 1 byte count, so * don't need to count number of dots to determine buffer length * 2=FirstLevel encoding length + ending length (by definition 0) */ len = LWNB_NETBIOS_ENCNAME_LEN + strlen(Fqdn) + 2; dwError = LWNetAllocateMemory(sizeof(CHAR) * len, (PVOID*)&retName); BAIL_ON_LWNET_ERROR(dwError); up = retName; dwError = LWNetAllocateString( Fqdn, &token); BAIL_ON_LWNET_ERROR(dwError); p = strchr(token, '.'); if (p) { *p++ = '\0'; Fqdn = token; } /* Store length of NetBIOS name component before that name */ *up++ = (UINT8) LWNB_NETBIOS_ENCNAME_LEN; LWNetNbStrToNbName(Fqdn, suffix, up); up += LWNB_NETBIOS_ENCNAME_LEN; /* Work through rest of Fqdn, replacing . with length of stuff before . */ if (p) { p = strtok_r(p, ".", &tokenPtr); } while (p) { len = strlen(p); *up++ = (UINT8) len; strncat((char *) up, p, sizeof(CHAR)*len - (up-retName)); up += len; p = strtok_r(NULL, ".", &tokenPtr); } *up++ = '\0'; *retNbNameL2 = (UINT8 *) retName; *retNbNameL2Len = up - retName; cleanup: LWNET_SAFE_FREE_MEMORY(token); return dwError; error: LWNET_SAFE_FREE_MEMORY(retName); goto cleanup; }
DWORD LWNetSrvNetBiosInit(VOID) { struct { unsigned mutexInit : 1; unsigned mutexAckInit : 1; unsigned cvInit : 1; unsigned cvAckInit : 1; } initialized = {0}; DWORD dwError = 0; PLWNET_SRV_NETBIOS_CONTEXT pNbCtx = NULL; dwError = LWNetAllocateMemory( sizeof(*pNbCtx), (PVOID*) &pNbCtx); BAIL_ON_LWNET_ERROR(dwError); dwError = LwErrnoToWin32Error(pthread_mutex_init(&pNbCtx->mutex, NULL)); BAIL_ON_LWNET_ERROR(dwError); initialized.mutexInit = TRUE; dwError = LwErrnoToWin32Error(pthread_cond_init(&pNbCtx->cv, NULL)); BAIL_ON_LWNET_ERROR(dwError); initialized.cvInit = TRUE; dwError = LwErrnoToWin32Error(pthread_mutex_init(&pNbCtx->mutexAck, NULL)); BAIL_ON_LWNET_ERROR(dwError); initialized.mutexAckInit = TRUE; dwError = LwErrnoToWin32Error(pthread_cond_init(&pNbCtx->cvAck, NULL)); BAIL_ON_LWNET_ERROR(dwError); initialized.cvAckInit = TRUE; dwError = LwErrnoToWin32Error(pthread_mutex_init( &pNbCtx->mutexTransactionId, NULL)); BAIL_ON_LWNET_ERROR(dwError); gpNbCtx = pNbCtx; cleanup: return dwError; error: if (initialized.mutexInit) { pthread_mutex_destroy(&pNbCtx->mutex); } if (initialized.mutexAckInit) { pthread_mutex_destroy(&pNbCtx->mutexAck); } if (initialized.cvInit) { pthread_cond_destroy(&pNbCtx->cv); } if (initialized.cvAckInit) { pthread_cond_destroy(&pNbCtx->cvAck); } LWNET_SAFE_FREE_MEMORY(pNbCtx); goto cleanup; }
int main( int argc, char* argv[] ) { DWORD dwError = 0; PSTR pszHostName = NULL; PWSTR pwszHostName = NULL; PWSTR pwszCanonName = NULL; PSTR pszCanonName = NULL; PLWNET_RESOLVE_ADDR *ppAddressList = NULL; DWORD dwAddressListLen = 0; DWORD i = 0; CHAR ipAddressBuf[INET_ADDRSTRLEN]; PCSTR pszAddress = NULL; DWORD ipAddressLen = 0; DWORD ipAddrFamily = 0; PBYTE pIpAddr = NULL; lwnet_init_logging_to_file(LWNET_LOG_LEVEL_VERBOSE, TRUE, ""); ParseArgs(argc, argv); if (argc == 1) { printf("usage: %s hostname\n", argv[0]); return 0; } pszHostName = argv[1]; dwError = LwRtlWC16StringAllocateFromCString(&pwszHostName, pszHostName); BAIL_ON_LWNET_ERROR(dwError); dwError = LWNetResolveName( (PCWSTR) pwszHostName, &pwszCanonName, &ppAddressList, &dwAddressListLen); BAIL_ON_LWNET_ERROR(dwError); dwError = LwRtlCStringAllocateFromWC16String(&pszCanonName, pwszCanonName); BAIL_ON_LWNET_ERROR(dwError); for (i=0; i<dwAddressListLen; i++) { if (ppAddressList[i]->AddressType == LWNET_IP_ADDR_V4) { ipAddressLen = 4; ipAddrFamily = PF_INET; pIpAddr = ppAddressList[i]->Address.Ip4Addr; } else if (ppAddressList[i]->AddressType == LWNET_IP_ADDR_V6) { ipAddressLen = 16; ipAddrFamily = PF_INET6; pIpAddr = ppAddressList[i]->Address.Ip4Addr; } pszAddress = inet_ntop(ipAddrFamily, pIpAddr, ipAddressBuf, sizeof(ipAddressBuf)); if (pszAddress) { printf("IP Address = %s\n", pszAddress); } } printf("Responses = %d Host: '%s'\n", dwAddressListLen, pszCanonName); cleanup: LWNetResolveNameFree(pwszCanonName, ppAddressList, dwAddressListLen); LWNET_SAFE_FREE_MEMORY(pwszHostName); LWNET_SAFE_FREE_STRING(pszCanonName); return (dwError); error: if (dwError == ERROR_BAD_NET_NAME) { printf("LWNetResolveName() failed DNS/NetBIOS name resolution\n"); } else { LWNET_LOG_ERROR("Failed communication with likewise-netlogond. " "Error code [%d]\n", dwError); } goto cleanup; }