NTSTATUS LWNetSvcmStart( PLW_SVCM_INSTANCE pInstance, ULONG ArgCount, PWSTR* ppArgs, ULONG FdCount, int* pFds ) { DWORD dwError = 0; dwError = LWNetSrvSetDefaults(); BAIL_ON_LWNET_ERROR(dwError); dwError = LWNetSrvInitialize(); BAIL_ON_LWNET_ERROR(dwError); dwError = LWNetSrvStartListenThread(); BAIL_ON_LWNET_ERROR(dwError); // Post service started event to eventlog LWNetSrvLogProcessStartedEvent(); cleanup: return LwWin32ErrorToNtStatus(dwError); error: goto cleanup; }
DWORD LWNetSrvGetPrefixPath( PSTR* ppszPath ) { DWORD dwError = 0; PSTR pszPath = NULL; BOOLEAN bInLock = FALSE; LWNET_LOCK_SERVERINFO(bInLock); if (IsNullOrEmptyString(gpLwnetServerInfo->szPrefixPath)) { dwError = ERROR_PATH_NOT_FOUND; BAIL_ON_LWNET_ERROR(dwError); } dwError = LWNetAllocateString(gpLwnetServerInfo->szPrefixPath, &pszPath); BAIL_ON_LWNET_ERROR(dwError); *ppszPath = pszPath; cleanup: LWNET_UNLOCK_SERVERINFO(bInLock); return dwError; error: LWNET_SAFE_FREE_STRING(pszPath); *ppszPath = NULL; goto cleanup; }
DWORD LWNetSrvStartNetBiosThread( VOID) { DWORD dwError = 0; pthread_t thread; pthread_attr_t attrib; gpNbCtx->udpTimeout = LWNetConfigIsNetBiosUdpTimeout(); dwError = LwErrnoToWin32Error(pthread_attr_init(&attrib)); BAIL_ON_LWNET_ERROR(dwError); dwError = LwErrnoToWin32Error(pthread_attr_setdetachstate( &attrib, PTHREAD_CREATE_DETACHED)); BAIL_ON_LWNET_ERROR(dwError); dwError = LwErrnoToWin32Error(pthread_create(&thread, &attrib, LWNetSrvStartNetBiosThreadRoutine, (void *) gpNbCtx)); BAIL_ON_LWNET_ERROR(dwError); cleanup: return dwError; error: goto cleanup; }
/* 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; }
DWORD LWNetDnsGetSrvRecordQuestion( OUT PSTR* ppszQuestion, IN PCSTR pszDomainName, IN OPTIONAL PCSTR pszSiteName, IN DWORD dwDsFlags ) { DWORD dwError = 0; PSTR question = NULL; PCSTR kind = "dc"; PCSTR service = "_ldap"; if (dwDsFlags & DS_PDC_REQUIRED) { kind = "pdc"; service = "_ldap"; } else if (dwDsFlags & DS_GC_SERVER_REQUIRED) { kind = "gc"; service = "_ldap"; } else if (dwDsFlags & DS_KDC_REQUIRED) { kind = "dc"; service = "_kerberos"; } else { kind = "dc"; service = "_ldap"; } if (IsNullOrEmptyString(pszSiteName)) { dwError = LwAllocateStringPrintf(&question, "%s._tcp.%s._msdcs.%s", service, kind, pszDomainName); BAIL_ON_LWNET_ERROR(dwError); } else { dwError = LwAllocateStringPrintf(&question, "%s._tcp.%s._sites.%s._msdcs.%s", service, pszSiteName, kind, pszDomainName); BAIL_ON_LWNET_ERROR(dwError); } error: if (dwError) { LWNET_SAFE_FREE_STRING(question); } *ppszQuestion = question; return dwError; }
DWORD LWNetDnsBuildSRVRecord( IN PDNS_RESPONSE_HEADER pHeader, IN PDNS_RECORD pAnswerRecord, IN PDLINKEDLIST pAdditionalsList, OUT PDNS_SRV_INFO_RECORD* ppSRVInfoRecord ) { DWORD dwError = 0; PDNS_SRV_INFO_RECORD pSRVInfoRecord = NULL; PBYTE pCurrent = NULL; DWORD dwNameLen = 0; if (pAnswerRecord->wDataLen < (4 * sizeof(WORD))) { dwError = DNS_ERROR_BAD_PACKET; BAIL_ON_LWNET_ERROR(dwError); } dwError = LWNetAllocateMemory(sizeof(DNS_SRV_INFO_RECORD), (PVOID*)&pSRVInfoRecord); BAIL_ON_LWNET_ERROR(dwError); pCurrent = pAnswerRecord->pData; pSRVInfoRecord->wPriority = LWNetDnsReadWORD(pCurrent); pCurrent += sizeof(WORD); pSRVInfoRecord->wWeight = LWNetDnsReadWORD(pCurrent); pCurrent += sizeof(WORD); pSRVInfoRecord->wPort = LWNetDnsReadWORD(pCurrent); pCurrent += sizeof(WORD); dwError = LWNetDnsParseName(pHeader, pCurrent, &dwNameLen, &pSRVInfoRecord->pszTarget); BAIL_ON_LWNET_ERROR(dwError); dwError = LWNetDnsGetAddressForServer(pAdditionalsList, pSRVInfoRecord->pszTarget, &pSRVInfoRecord->pszAddress); BAIL_ON_LWNET_ERROR(dwError); error: if (dwError) { if (pSRVInfoRecord) { LWNetDnsFreeSRVInfoRecord(pSRVInfoRecord); pSRVInfoRecord = NULL; } } *ppSRVInfoRecord = pSRVInfoRecord; return dwError; }
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; }
DWORD LWNetGetErrorMessageForLoggingEvent( DWORD dwErrCode, PSTR* ppszErrorMsg ) { DWORD dwErrorBufferSize = 0; DWORD dwError = 0; DWORD dwLen = 0; PSTR pszErrorMsg = NULL; PSTR pszErrorBuffer = NULL; dwErrorBufferSize = LwGetErrorString(dwErrCode, NULL, 0); if (!dwErrorBufferSize) goto cleanup; dwError = LWNetAllocateMemory( dwErrorBufferSize, (PVOID*)&pszErrorBuffer); BAIL_ON_LWNET_ERROR(dwError); dwLen = LwGetErrorString(dwErrCode, pszErrorBuffer, dwErrorBufferSize); if ((dwLen == dwErrorBufferSize) && !IsNullOrEmptyString(pszErrorBuffer)) { dwError = LwAllocateStringPrintf( &pszErrorMsg, "Error: %s [error code: %d]", pszErrorBuffer, dwErrCode); BAIL_ON_LWNET_ERROR(dwError); } *ppszErrorMsg = pszErrorMsg; cleanup: LWNET_SAFE_FREE_STRING(pszErrorBuffer); return dwError; error: LWNET_SAFE_FREE_STRING(pszErrorMsg); *ppszErrorMsg = NULL; goto cleanup; }
DWORD LWNetDnsParseRecords( IN PDNS_RESPONSE_HEADER pHeader, IN WORD wNRecords, IN PBYTE pData, OUT PDLINKEDLIST* ppRecordList, OUT PDWORD pdwBytesToAdvance ) { DWORD dwError = 0; PBYTE pCurrent = pData; PDLINKEDLIST pRecordList = NULL; PDNS_RECORD pRecord = NULL; DWORD dwBytesToAdvance = 0; WORD iRecord = 0; for (iRecord = 0; iRecord < wNRecords; iRecord++) { DWORD dwLen = 0; dwError = LWNetDnsParseRecord(pHeader, pCurrent, &pRecord, &dwLen); BAIL_ON_LWNET_ERROR(dwError); dwError = LWNetDLinkedListAppend(&pRecordList, pRecord); BAIL_ON_LWNET_ERROR(dwError); pRecord = NULL; pCurrent += dwLen; dwBytesToAdvance += dwLen; } error: if (dwError) { if (pRecord) { LWNetDnsFreeRecord(pRecord); } LWNET_SAFE_FREE_DNS_RECORD_LINKED_LIST(pRecordList); dwBytesToAdvance = 0; } *ppRecordList = pRecordList; *pdwBytesToAdvance = dwBytesToAdvance; return dwError; }
DWORD LWNetSrvStopListenThread( void ) { DWORD dwError = 0; if (gpServer) { dwError = MAP_LWMSG_ERROR(lwmsg_peer_stop_listen(gpServer)); BAIL_ON_LWNET_ERROR(dwError); } error: if (gpServer) { lwmsg_peer_delete(gpServer); gpServer = NULL; } if (gpProtocol) { lwmsg_protocol_delete(gpProtocol); gpProtocol = NULL; } return dwError; }
DWORD LWNetSrvOpenServer( uid_t peerUID, gid_t peerGID, PHANDLE phServer ) { DWORD dwError = 0; PLWNET_SRV_API_STATE pServerState = NULL; dwError = LWNetAllocateMemory( sizeof(LWNET_SRV_API_STATE), (PVOID*)&pServerState); BAIL_ON_LWNET_ERROR(dwError); pServerState->peerUID = peerUID; pServerState->peerGID = peerGID; *phServer = (HANDLE)pServerState; cleanup: return dwError; error: *phServer = (HANDLE)NULL; if (pServerState) { LWNetSrvCloseServer((HANDLE)pServerState); } goto cleanup; }
DWORD AddFlag( DWORD dwFlag, PDWORD pdwFlags ) { DWORD dwError = 0; DWORD dwFlags = *pdwFlags; if(dwFlags & dwFlag) { printf("Duplicate flag entered: [0x%.8X]\n", dwFlag); dwError = ERROR_INVALID_PARAMETER; } else if(!(dwFlag & LWNET_SUPPORTED_DS_INPUT_FLAGS)) { printf("Invalid flag entered: [0x%.8X]\n", dwFlag); dwError = ERROR_INVALID_PARAMETER; } BAIL_ON_LWNET_ERROR(dwError); dwFlags |= dwFlag; *pdwFlags = dwFlags; error: return dwError; }
VOID LWNetSrvLogProcessStartedEvent( VOID ) { DWORD dwError = 0; PSTR pszDescription = NULL; dwError = LwAllocateStringPrintf( &pszDescription, "The Likewise site manager service was started."); BAIL_ON_LWNET_ERROR(dwError); LWNetSrvLogInformationEvent( LWNET_EVENT_INFO_SERVICE_STARTED, SERVICE_EVENT_CATEGORY, pszDescription, NULL); cleanup: LWNET_SAFE_FREE_STRING(pszDescription); return; error: goto cleanup; }
VOID LWNetSrvLogProcessStoppedEvent( DWORD dwExitCode ) { DWORD dwError = 0; PSTR pszDescription = NULL; PSTR pszData = NULL; dwError = LwAllocateStringPrintf( &pszDescription, "The Likewise site manager service was stopped"); BAIL_ON_LWNET_ERROR(dwError); dwError = LWNetGetErrorMessageForLoggingEvent( dwExitCode, &pszData); BAIL_ON_LWNET_ERROR(dwError); if (dwExitCode) { LWNetSrvLogErrorEvent( LWNET_EVENT_ERROR_SERVICE_STOPPED, SERVICE_EVENT_CATEGORY, pszDescription, pszData); } else { LWNetSrvLogInformationEvent( LWNET_EVENT_INFO_SERVICE_STOPPED, SERVICE_EVENT_CATEGORY, pszDescription, pszData); } cleanup: LWNET_SAFE_FREE_STRING(pszDescription); LWNET_SAFE_FREE_STRING(pszData); return; error: goto cleanup; }
DWORD LWNetSrvGetDCNameDiscover( IN PCSTR pszDnsDomainName, IN OPTIONAL PCSTR pszSiteName, IN OPTIONAL PCSTR pszPrimaryDomain, IN DWORD dwDsFlags, IN DWORD dwBlackListCount, IN OPTIONAL PSTR* ppszAddressBlackList, OUT PLWNET_DC_INFO* ppDcInfo, OUT OPTIONAL PDNS_SERVER_INFO* ppServerArray, OUT OPTIONAL PDWORD pdwServerCount, OUT PBOOLEAN pbFailedFindWritable ) { DWORD dwError = 0; /* First try with the "Preferred DC list" */ dwError = LWNetSrvGetDCNameDiscoverInternal( pszDnsDomainName, pszSiteName, pszPrimaryDomain, dwDsFlags, dwBlackListCount, ppszAddressBlackList, LWNetGetPreferredDcList, ppDcInfo, ppServerArray, pdwServerCount, pbFailedFindWritable); if (dwError == ERROR_SUCCESS) { goto cleanup; } /* Try again using the standard DNS SRV queries */ dwError = LWNetSrvGetDCNameDiscoverInternal( pszDnsDomainName, pszSiteName, pszPrimaryDomain, dwDsFlags, dwBlackListCount, ppszAddressBlackList, LWNetDnsSrvQuery, ppDcInfo, ppServerArray, pdwServerCount, pbFailedFindWritable); BAIL_ON_LWNET_ERROR(dwError); cleanup: return dwError; error: goto cleanup; }
static DWORD LWNetSrvPingCLdapPoll( IN DWORD dwTimeoutMilliseconds, IN DWORD dwFdCount, IN struct pollfd *Readfds ) { DWORD dwError = 0; int sret = 0; LWNET_UNIX_MS_TIME_T CurrentTime = 0; LWNET_UNIX_MS_TIME_T StopTime = 0; DWORD dwRemainder = 0; dwError = LWNetGetSystemTimeInMs(&StopTime); BAIL_ON_LWNET_ERROR(dwError); StopTime += dwTimeoutMilliseconds; do { dwError = LWNetGetSystemTimeInMs(&CurrentTime); BAIL_ON_LWNET_ERROR(dwError); if (CurrentTime < StopTime) { dwRemainder = StopTime - CurrentTime; sret = poll(Readfds, dwFdCount, dwRemainder); } else { sret = 0; } } while (sret < 0 && errno == EINTR); if (sret < 0) { dwError = LwMapErrnoToLwError(errno); } BAIL_ON_LWNET_ERROR(dwError); error: return dwError; }
DWORD LWNetDnsBuildSRVRecordList( IN PDNS_RESPONSE_HEADER pHeader, IN PDLINKEDLIST pAnswersList, IN PDLINKEDLIST pAdditionalsList, OUT PDLINKEDLIST* ppSRVRecordList ) { DWORD dwError = 0; PDNS_SRV_INFO_RECORD pSRVRecord = NULL; PDLINKEDLIST pListMember = NULL; PDLINKEDLIST pSRVRecordList = NULL; pListMember = pAnswersList; while (pListMember) { dwError = LWNetDnsBuildSRVRecord(pHeader, (PDNS_RECORD)pListMember->pItem, pAdditionalsList, &pSRVRecord); if (dwError) { // Already logged on ERROR_NOT_FOUND if (dwError != ERROR_NOT_FOUND) { LWNET_LOG_ERROR("Failed to build SRV record information"); } // Skip dwError = 0; } else { dwError = LWNetDLinkedListAppend(&pSRVRecordList, pSRVRecord); BAIL_ON_LWNET_ERROR(dwError); pSRVRecord = NULL; } pListMember = pListMember->pNext; } error: if (pSRVRecord) { LWNetDnsFreeSRVInfoRecord(pSRVRecord); } if (dwError) { LWNET_SAFE_FREE_SRV_INFO_LINKED_LIST(pSRVRecordList); } *ppSRVRecordList = pSRVRecordList; return dwError; }
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; }
NTSTATUS LWNetSvcmRefresh( PLW_SVCM_INSTANCE pInstance ) { DWORD dwError = 0; HANDLE hServer = NULL; LWNET_LOG_INFO("Refreshing configuration"); dwError = LWNetSrvOpenServer( getuid(), getgid(), &hServer); BAIL_ON_LWNET_ERROR(dwError); dwError = LWNetSrvRefreshConfiguration(hServer); BAIL_ON_LWNET_ERROR(dwError); LWNET_LOG_INFO("Refreshed configuration successfully"); cleanup: if (hServer != NULL) { LWNetSrvCloseServer(hServer); } return LwWin32ErrorToNtStatus(dwError); error: LWNET_LOG_ERROR("Failed to refresh configuration. [Error code:%u]", dwError); goto cleanup; }
VOID LWNetSrvLogProcessFailureEvent( DWORD dwErrCode ) { DWORD dwError = 0; PSTR pszDescription = NULL; PSTR pszData = NULL; dwError = LwAllocateStringPrintf( &pszDescription, "The Likewise site manager service stopped running due to an error"); BAIL_ON_LWNET_ERROR(dwError); dwError = LWNetGetErrorMessageForLoggingEvent( dwErrCode, &pszData); BAIL_ON_LWNET_ERROR(dwError); LWNetSrvLogErrorEvent( LWNET_EVENT_ERROR_SERVICE_START_FAILURE, SERVICE_EVENT_CATEGORY, pszDescription, pszData); cleanup: LWNET_SAFE_FREE_STRING(pszDescription); LWNET_SAFE_FREE_STRING(pszData); return; error: goto cleanup; }
DWORD LWNetSrvStartNetBios( VOID) { DWORD dwError = 0; if (LWNetConfigIsNetBiosEnabled()) { dwError = LWNetSrvNetBiosInit(); BAIL_ON_LWNET_ERROR(dwError); dwError = LWNetSrvStartNetBiosThread(); BAIL_ON_LWNET_ERROR(dwError); } cleanup: return dwError; error: LWNetSrvNetBiosCleanup(); LWNET_LOG_ERROR("Failed initializing NetBIOS listener thread %s", LwErrnoToName(dwError)); goto cleanup; }
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; }
DWORD LWNetSrvInitialize( VOID ) { DWORD dwError = 0; dwError = LWNetSrvApiInit(); BAIL_ON_LWNET_ERROR(dwError); cleanup: return dwError; error: goto cleanup; }
DWORD LWNetReadGUID( OUT PBYTE pbtDest, IN PACKED_ARRAY* pArray ) { DWORD dwError = 0; if (BYTES_REMAINING((*pArray)) < LWNET_GUID_SIZE) { dwError = DNS_ERROR_BAD_PACKET; BAIL_ON_LWNET_ERROR(dwError); } memcpy(pbtDest, pArray->pCur, LWNET_GUID_SIZE); pArray->pCur += LWNET_GUID_SIZE; error: return dwError; }
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; }
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; }
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; }
DWORD LWNetNbResolveName( IN PSTR pszHostName, IN UINT16 flags, OUT struct in_addr **retAddrs, OUT PDWORD retAddrsLen) { DWORD dwError = 0; /* Derive this value from flags; hard code to FILE_SERVICE for now */ unsigned char queryType = LWNB_RESOLVE_FILE_SERVICE; PSTR winsPrimary = NULL; PSTR winsSecondary = NULL; if (!gpNbCtx) { dwError = ERROR_INVALID_HANDLE; BAIL_ON_LWNET_ERROR(dwError); } if (flags) { if (flags & LWNB_NETBIOS_FLAGS_RESOLVE_FILE_SERVICE) { queryType = LWNB_RESOLVE_FILE_SERVICE; } else if (flags & LWNB_NETBIOS_FLAGS_RESOLVE_WORKSTATION) { queryType = LWNB_RESOLVE_WORKSTATION; } else if (flags & LWNB_NETBIOS_FLAGS_RESOLVE_DC) { queryType = LWNB_RESOLVE_DC; } } if (flags & LWNB_NETBIOS_FLAGS_MODE_WINS) { LwNetConfigGetWinsServers(&winsPrimary, &winsSecondary); dwError = LWNetNbResolveNameUdp( pszHostName, winsPrimary, queryType, retAddrs, retAddrsLen); if (dwError) { dwError = LWNetNbResolveNameUdp( pszHostName, winsSecondary, queryType, retAddrs, retAddrsLen); } } if (dwError && (flags & LWNB_NETBIOS_FLAGS_MODE_BROADCAST)) { dwError = LWNetNbResolveNameUdp( pszHostName, NULL, queryType, retAddrs, retAddrsLen); } cleanup: return dwError; error: 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; }