/* This function returns the current Dirsync_Private that's inside Repl_Agmt ra as a ldap control. */ LDAPControl* windows_private_dirsync_control(const Repl_Agmt *ra) { LDAPControl *control = NULL; BerElement *ber; Dirsync_Private *dp; char iscritical = PR_TRUE; LDAPDebug0Args( LDAP_DEBUG_TRACE, "=> windows_private_dirsync_control\n" ); PR_ASSERT(ra); dp = (Dirsync_Private *) agmt_get_priv(ra); PR_ASSERT (dp); ber = ber_alloc(); ber_printf( ber, "{iio}", dp->dirsync_flags, dp->dirsync_maxattributecount, dp->dirsync_cookie ? dp->dirsync_cookie : "", dp->dirsync_cookie_len ); /* Use a regular directory server instead of a real AD - for testing */ if (getenv("WINSYNC_USE_DS")) { iscritical = PR_FALSE; } slapi_build_control( REPL_DIRSYNC_CONTROL_OID, ber, iscritical, &control); ber_free(ber,1); LDAPDebug0Args( LDAP_DEBUG_TRACE, "<= windows_private_dirsync_control\n" ); return control; }
int VmDirCreateRequestVoteCtrl( PVDIR_REQUEST_VOTE_CONTROL_VALUE pRequestVoteCtrlValue, LDAPControl* pRequestVoteCtrl ) { int retVal = LDAP_SUCCESS; BerElement* pBer = NULL; BerValue candidateIdBV = {0}; BerValue lastLogIndexBV = {0}; if (!pRequestVoteCtrlValue || !pRequestVoteCtrl) { BAIL_WITH_VMDIR_ERROR(retVal, VMDIR_ERROR_INVALID_PARAMETER); } if ((pBer = ber_alloc()) == NULL) { BAIL_WITH_VMDIR_ERROR(retVal, VMDIR_ERROR_NO_MEMORY); } candidateIdBV.bv_val = pRequestVoteCtrlValue->candidateId; candidateIdBV.bv_len = VmDirStringLenA(pRequestVoteCtrlValue->candidateId); retVal = VmDirAllocateStringPrintf(&lastLogIndexBV.bv_val, "%"PRIu64, pRequestVoteCtrlValue->lastLogIndex); BAIL_ON_VMDIR_ERROR( retVal ); lastLogIndexBV.bv_len = VmDirStringLenA(lastLogIndexBV.bv_val); if ( ber_printf( pBer, "{iOOi}", pRequestVoteCtrlValue->term, &candidateIdBV, &lastLogIndexBV, pRequestVoteCtrlValue->lastLogTerm) == -1) { VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "%s: ber_printf failed.", __FUNCTION__ ); BAIL_WITH_VMDIR_ERROR(retVal, VMDIR_ERROR_NO_MEMORY); } memset( pRequestVoteCtrl, 0, sizeof( LDAPControl )); pRequestVoteCtrl->ldctl_oid = LDAP_REQUEST_VOTE_CONTROL; pRequestVoteCtrl->ldctl_iscritical = '1'; if (ber_flatten2(pBer, &pRequestVoteCtrl->ldctl_value, 1)) { BAIL_WITH_VMDIR_ERROR(retVal, VMDIR_ERROR_NO_MEMORY); } cleanup: VMDIR_SAFE_FREE_MEMORY(lastLogIndexBV.bv_val); if (pBer) { ber_free(pBer, 1); } return retVal; error: VmDirFreeCtrlContent(pRequestVoteCtrl); goto cleanup; }
/** Takes the object DN and BER encodes the data into the BER value which is used as part of the request * @verbatim RequestBer contents: clientVersion INTEGER targetObjectDN OCTET STRING @endverbatim * * @param[out] request_bv where to write the request BER value (must be freed with ber_bvfree). * @param[in] dn to query for. * @return 0 on success, and < 0 on error. */ static int ber_encode_request_data(char const *dn, struct berval **request_bv) { int err = 0; int rc = 0; BerElement *request_ber = NULL; if (!dn || !*dn) { err = NMAS_E_INVALID_PARAMETER; goto finish; } /* Allocate a BerElement for the request parameters.*/ if ((request_ber = ber_alloc()) == NULL) { err = NMAS_E_FRAG_FAILURE; goto finish; } rc = ber_printf(request_ber, "{io}", NMAS_LDAP_EXT_VERSION, dn, strlen(dn) + 1); if (rc < 0) { err = NMAS_E_FRAG_FAILURE; goto finish; } /* * Convert the BER we just built to a berval that we'll * send with the extended request. */ if (ber_flatten(request_ber, request_bv) < 0) { err = NMAS_E_FRAG_FAILURE; goto finish; } finish: if (request_ber) ber_free(request_ber, 1); return err; }
int VmDirCreateSyncRequestControl( PCSTR pszInvocationId, USN lastLocalUsnProcessed, PCSTR pszUtdVector, LDAPControl * syncReqCtrl ) { int retVal = LDAP_SUCCESS; BerElement * ber = NULL; PSTR pszLastLocalUsnProcessed = NULL; if (syncReqCtrl == NULL) { retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_SIMPLE_LDAP_ERROR(retVal); } if ((ber = ber_alloc()) == NULL) { retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_SIMPLE_LDAP_ERROR(retVal); } if (VmDirAllocateStringPrintf(&pszLastLocalUsnProcessed, "%lld", lastLocalUsnProcessed)) { retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_SIMPLE_LDAP_ERROR(retVal); } if ( ber_printf( ber, "{i{sss}}", LDAP_SYNC_REFRESH_ONLY, pszInvocationId, pszLastLocalUsnProcessed, pszUtdVector ) == -1) { VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "VmDirCreateSyncRequestControl: ber_printf failed." ); retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_SIMPLE_LDAP_ERROR( retVal ); } memset( syncReqCtrl, 0, sizeof( LDAPControl )); syncReqCtrl->ldctl_oid = LDAP_CONTROL_SYNC; syncReqCtrl->ldctl_iscritical = '1'; if (ber_flatten2(ber, &syncReqCtrl->ldctl_value, 1)) { retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_SIMPLE_LDAP_ERROR(retVal); } cleanup: VMDIR_SAFE_FREE_STRINGA(pszLastLocalUsnProcessed); if (ber) { ber_free(ber, 1); } return retVal; ldaperror: ber_bvfree(&syncReqCtrl->ldctl_value); goto cleanup; }
static int BindListenOnPort( #ifndef _WIN32 sa_family_t addr_type, size_t addr_size, #else short addr_type, int addr_size, #endif void *pServ_addr, ber_socket_t *pSockfd ) { #define LDAP_PORT_LISTEN_BACKLOG 128 int optname = 0; int retVal = LDAP_SUCCESS; int retValBind = 0; PSTR pszLocalErrMsg = NULL; int on = 1; #ifdef _WIN32 DWORD sTimeout = 0; int reTries = 0; #else struct timeval sTimeout = {0}; #endif *pSockfd = -1; *pSockfd = socket(addr_type, SOCK_STREAM, 0); if (*pSockfd < 0) { #ifdef _WIN32 errno = WSAGetLastError(); #endif retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "%s: socket() call failed with errno: %d", __func__, errno ); } #ifdef _WIN32 optname = SO_EXCLUSIVEADDRUSE; #else optname = SO_REUSEADDR; #endif if (setsockopt(*pSockfd, SOL_SOCKET, optname, (const char *)(&on), sizeof(on)) < 0) { #ifdef _WIN32 errno = WSAGetLastError(); #endif retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "%s: setsockopt() call failed with errno: %d", __func__, errno ); } on = 1; // turn on TCP_NODELAY below if (setsockopt(*pSockfd, IPPROTO_TCP, TCP_NODELAY, (const char *)(&on), sizeof(on) ) < 0) { #ifdef _WIN32 errno = WSAGetLastError(); #endif retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "%s: setsockopt() TCP_NODELAY call failed with errno: %d", __func__, errno ); } if (addr_type == AF_INET6) { #ifdef _WIN32 if (setsockopt(*pSockfd, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)(&on), sizeof(on) ) < 0) { errno = WSAGetLastError(); #else if (setsockopt(*pSockfd, SOL_IPV6, IPV6_V6ONLY, (const char *)(&on), sizeof(on) ) < 0) { #endif retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "%s: setsockopt() IPV6_V6ONLY call failed with errno: %d", __func__, errno ); } } if (gVmdirGlobals.dwLdapRecvTimeoutSec > 0) { #ifdef _WIN32 sTimeout = gVmdirGlobals.dwLdapRecvTimeoutSec*1000; #else sTimeout.tv_sec = gVmdirGlobals.dwLdapRecvTimeoutSec; sTimeout.tv_usec = 0; #endif if (setsockopt(*pSockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*) &sTimeout, sizeof(sTimeout)) < 0) { #ifdef _WIN32 errno = WSAGetLastError(); #endif retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "%s: setsockopt() SO_RCVTIMEO failed, errno: %d", __func__, errno ); } } retValBind = bind(*pSockfd, (struct sockaddr *) pServ_addr, addr_size); #ifdef _WIN32 // Add retry logic per PR 1347783 reTries = 0; while (retValBind != 0 && reTries < MAX_NUM_OF_BIND_PORT_RETRIES) { errno = WSAGetLastError(); if (errno != WSAEADDRINUSE) { break; } reTries++; VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL, "%s: bind() call failed with errno: %d, re-trying (%d)", __func__, errno, reTries); VmDirSleep(1000); retValBind = bind(*pSockfd, (struct sockaddr *) pServ_addr, addr_size); } #endif if (retValBind != 0) { retVal = LDAP_OPERATIONS_ERROR; //need to free socket ... BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "%s: bind() call failed with errno: %d", __func__, errno ); } if (listen(*pSockfd, LDAP_PORT_LISTEN_BACKLOG) != 0) { #ifdef _WIN32 errno = WSAGetLastError(); #endif retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "%s: listen() call failed with errno: %d", __func__, errno ); } cleanup: VMDIR_SAFE_FREE_MEMORY(pszLocalErrMsg); return retVal; error: if (*pSockfd >= 0) { tcp_close(*pSockfd); *pSockfd = -1; } VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, VDIR_SAFE_STRING(pszLocalErrMsg)); goto cleanup; } /* * We own pConnection and delete it when done. */ static DWORD ProcessAConnection( PVOID pArg ) { VDIR_CONNECTION *pConn = NULL; int retVal = LDAP_SUCCESS; ber_tag_t tag = LBER_ERROR; ber_len_t len = 0; BerElement * ber = NULL; ber_int_t msgid = -1; PVDIR_OPERATION pOperation = NULL; int reTries = 0; BOOLEAN bDownOpThrCount = FALSE; PVDIR_CONNECTION_CTX pConnCtx = NULL; // increment operation thread counter retVal = VmDirSyncCounterIncrement(gVmdirGlobals.pOperationThrSyncCounter); BAIL_ON_VMDIR_ERROR(retVal); bDownOpThrCount = TRUE; pConnCtx = (PVDIR_CONNECTION_CTX)pArg; assert(pConnCtx); retVal = NewConnection(pConnCtx->sockFd, &pConn, pConnCtx->pSockbuf_IO); if (retVal != LDAP_SUCCESS) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s: NewConnection [%d] failed with error: %d", __func__, pConnCtx->sockFd, retVal); goto error; } while (TRUE) { if (VmDirdState() == VMDIRD_STATE_SHUTDOWN) { goto cleanup; } ber = ber_alloc(); assert( ber != NULL); /* An LDAP request message looks like: * LDAPMessage ::= SEQUENCE { * messageID MessageID, * protocolOp CHOICE { * bindRequest BindRequest, * unbindRequest UnbindRequest, * searchRequest SearchRequest, * ... }, * controls [0] Controls OPTIONAL } */ // reset retry count reTries = 0; // Read complete LDAP request message (tag, length, and real message). while( reTries < MAX_NUM_OF_SOCK_READ_RETRIES ) { if ((tag = ber_get_next( pConn->sb, &len, ber )) == LDAP_TAG_MESSAGE ) { break; } #ifdef _WIN32 // in ber_get_next (liblber) call, sock_errset() call WSASetLastError() errno = WSAGetLastError(); if ( errno == EWOULDBLOCK || errno == EAGAIN || errno == WSAETIMEDOUT) #else if ( errno == EWOULDBLOCK || errno == EAGAIN) #endif { if (gVmdirGlobals.dwLdapRecvTimeoutSec > 0 && ber->ber_len == 0) { VMDIR_LOG_INFO( LDAP_DEBUG_CONNS, "%s: disconnecting peer (%s), idle > %d seconds", __func__, pConn->szClientIP, gVmdirGlobals.dwLdapRecvTimeoutSec); retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR( retVal ); } //This may occur when not all data have recieved - set to EAGAIN/EWOULDBLOCK by ber_get_next, // and in such case ber->ber_len > 0; if (reTries > 0 && reTries % 5 == 0) { VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL, "%s: ber_get_next() failed with errno = %d, peer (%s), re-trying (%d)", __func__, errno , pConn->szClientIP, reTries); } VmDirSleep(200); reTries++; continue; } // Unexpected error case. if (errno == 0) { VMDIR_LOG_INFO( LDAP_DEBUG_CONNS, "%s: ber_get_next() peer (%s) disconnected", __func__, pConn->szClientIP); } else { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s: ber_get_next() call failed with errno = %d peer (%s)", __func__, errno, pConn->szClientIP); } retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR( retVal ); } // Read LDAP request messageID (tag, length (not returned since it is implicit/integer), and messageID value) if ( (tag = ber_get_int( ber, &msgid )) != LDAP_TAG_MSGID ) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ProcessAConnection: ber_get_int() call failed." ); retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR( retVal ); } // Read protocolOp (tag) and length of the LDAP operation message, and leave the pointer at the beginning // of the LDAP operation message (to be parsed by PerformXYZ methods). if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ProcessAConnection: ber_peek_tag() call failed." ); retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR( retVal ); } retVal = VmDirNewOperation(ber, msgid, tag, pConn, &pOperation); if (retVal) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ProcessAConnection: NewOperation() call failed." ); retVal = LDAP_OPERATIONS_ERROR; } BAIL_ON_VMDIR_ERROR( retVal ); // // If this is a multi-stage operation don't overwrite the start time if it's already set. // pConn->SuperLogRec.iStartTime = pConn->SuperLogRec.iStartTime ? pConn->SuperLogRec.iStartTime : VmDirGetTimeInMilliSec(); switch (tag) { case LDAP_REQ_BIND: retVal = VmDirPerformBind(pOperation); if (retVal != LDAP_SASL_BIND_IN_PROGRESS) { _VmDirCollectBindSuperLog(pConn, pOperation); // ignore error } break; case LDAP_REQ_ADD: retVal = VmDirPerformAdd(pOperation); break; case LDAP_REQ_SEARCH: retVal = VmDirPerformSearch(pOperation); break; case LDAP_REQ_UNBIND: retVal = VmDirPerformUnbind(pOperation); break; case LDAP_REQ_MODIFY: retVal = VmDirPerformModify(pOperation); break; case LDAP_REQ_DELETE: retVal = VmDirPerformDelete(pOperation); break; case LDAP_REQ_MODDN: case LDAP_REQ_COMPARE: case LDAP_REQ_ABANDON: case LDAP_REQ_EXTENDED: VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "ProcessAConnection: Operation is not yet implemented.." ); pOperation->ldapResult.errCode = retVal = LDAP_UNWILLING_TO_PERFORM; // ignore following VmDirAllocateStringA error. VmDirAllocateStringA( "Operation is not yet implemented.", &pOperation->ldapResult.pszErrMsg); VmDirSendLdapResult( pOperation ); break; default: pOperation->ldapResult.errCode = LDAP_PROTOCOL_ERROR; retVal = LDAP_NOTICE_OF_DISCONNECT; break; } pConn->SuperLogRec.iEndTime = VmDirGetTimeInMilliSec(); VmDirOPStatisticUpdate(tag, pConn->SuperLogRec.iEndTime - pConn->SuperLogRec.iStartTime); if (tag != LDAP_REQ_BIND) { VmDirLogOperation(gVmdirGlobals.pLogger, tag, pConn, pOperation->ldapResult.errCode); _VmDirScrubSuperLogContent(tag, &pConn->SuperLogRec); } VmDirFreeOperation(pOperation); pOperation = NULL; ber_free( ber, 1); ber = NULL; if (retVal == LDAP_NOTICE_OF_DISCONNECT) // returned as a result of protocol parsing error. { // RFC 4511, section 4.1.1: If the server receives an LDAPMessage from the client in which the LDAPMessage // SEQUENCE tag cannot be recognized, the messageID cannot be parsed, the tag of the protocolOp is not // recognized as a request, or the encoding structures or lengths of data fields are found to be incorrect, // then the server **SHOULD** return the Notice of Disconnection, with the resultCode // set to protocolError, and **MUST** immediately terminate the LDAP session as described in Section 5.3. goto cleanup; } } cleanup: if (retVal == LDAP_NOTICE_OF_DISCONNECT) { // Optionally send Notice of Disconnection with rs->err. } if (ber != NULL) { ber_free( ber, 1 ); } VmDirDeleteConnection(&pConn); VMDIR_SAFE_FREE_MEMORY(pConnCtx); VmDirFreeOperation(pOperation); if (bDownOpThrCount) { VmDirSyncCounterDecrement(gVmdirGlobals.pOperationThrSyncCounter); } _VmDirFlowCtrlThrExit(); // TODO: should we return dwError ? return 0; error: goto cleanup; }
static int berEncodePasswordData( struct berval **requestBV, const char *objectDN, const char *password, const char *password2) { int err = 0, rc=0; BerElement *requestBer = NULL; const char * utf8ObjPtr = NULL; int utf8ObjSize = 0; const char * utf8PwdPtr = NULL; int utf8PwdSize = 0; const char * utf8Pwd2Ptr = NULL; int utf8Pwd2Size = 0; /* Convert objectDN and tag strings from Unicode to UTF-8 */ utf8ObjSize = strlen(objectDN)+1; utf8ObjPtr = objectDN; if (password != NULL) { utf8PwdSize = strlen(password)+1; utf8PwdPtr = password; } if (password2 != NULL) { utf8Pwd2Size = strlen(password2)+1; utf8Pwd2Ptr = password2; } /* Allocate a BerElement for the request parameters. */ if ((requestBer = ber_alloc()) == NULL) { err = LDAP_ENCODING_ERROR; goto Cleanup; } if (password != NULL && password2 != NULL) { /* BER encode the NMAS Version, the objectDN, and the password */ rc = ber_printf(requestBer, "{iooo}", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize, utf8PwdPtr, utf8PwdSize, utf8Pwd2Ptr, utf8Pwd2Size); } else if (password != NULL) { /* BER encode the NMAS Version, the objectDN, and the password */ rc = ber_printf(requestBer, "{ioo}", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize, utf8PwdPtr, utf8PwdSize); } else { /* BER encode the NMAS Version and the objectDN */ rc = ber_printf(requestBer, "{io}", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize); } if (rc < 0) { err = LDAP_ENCODING_ERROR; goto Cleanup; } else { err = 0; } /* Convert the BER we just built to a berval that we'll send with the extended request. */ if (ber_flatten(requestBer, requestBV) == LBER_ERROR) { err = LDAP_ENCODING_ERROR; goto Cleanup; } Cleanup: if (requestBer) { ber_free(requestBer, 1); } return err; }
static int berEncodeLoginData( struct berval **requestBV, char *objectDN, unsigned int methodIDLen, unsigned int *methodID, char *tag, size_t putDataLen, void *putData) { int err = 0; BerElement *requestBer = NULL; unsigned int i; unsigned int elemCnt = methodIDLen / sizeof(unsigned int); char *utf8ObjPtr=NULL; int utf8ObjSize = 0; char *utf8TagPtr = NULL; int utf8TagSize = 0; utf8ObjPtr = objectDN; utf8ObjSize = strlen(utf8ObjPtr)+1; utf8TagPtr = tag; utf8TagSize = strlen(utf8TagPtr)+1; /* Allocate a BerElement for the request parameters. */ if ((requestBer = ber_alloc()) == NULL) { err = LDAP_ENCODING_ERROR; goto Cleanup; } /* BER encode the NMAS Version and the objectDN */ err = (ber_printf(requestBer, "{io", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize) < 0) ? LDAP_ENCODING_ERROR : 0; /* BER encode the MethodID Length and value */ if (!err) { err = (ber_printf(requestBer, "{i{", methodIDLen) < 0) ? LDAP_ENCODING_ERROR : 0; } for (i = 0; !err && i < elemCnt; i++) { err = (ber_printf(requestBer, "i", methodID[i]) < 0) ? LDAP_ENCODING_ERROR : 0; } if (!err) { err = (ber_printf(requestBer, "}}", 0) < 0) ? LDAP_ENCODING_ERROR : 0; } if (putData) { /* BER Encode the the tag and data */ err = (ber_printf(requestBer, "oio}", utf8TagPtr, utf8TagSize, putDataLen, putData, putDataLen) < 0) ? LDAP_ENCODING_ERROR : 0; } else { /* BER Encode the the tag */ err = (ber_printf(requestBer, "o}", utf8TagPtr, utf8TagSize) < 0) ? LDAP_ENCODING_ERROR : 0; } if (err) { goto Cleanup; } /* Convert the BER we just built to a berval that we'll send with the extended request. */ if (ber_flatten(requestBer, requestBV) == LBER_ERROR) { err = LDAP_ENCODING_ERROR; goto Cleanup; } Cleanup: if (requestBer) { ber_free(requestBer, 1); } return err; }
DOMAIN_CONTROLLER_INFO * dc_locate(const char *prefix, const char *dname) { lsa_srv_ctx_t *ctx; srv_rr_t *sr; BerElement *pdu = NULL, *ret; struct _berelement *be, *rbe; DOMAIN_CONTROLLER_INFO *dci = NULL; int r, fd = -1; struct sockaddr_storage addr; struct sockaddr_in6 *paddr; socklen_t addrlen; char *dcaddr = NULL, *dcname = NULL; ctx = lsa_srv_init(); if (ctx == NULL) goto fail; r = lsa_srv_lookup(ctx, prefix, dname); if (r <= 0) goto fail; if (lsa_srv_output) lsa_srv_output(ctx); if ((fd = lsa_bind()) < 0) goto fail; if ((pdu = ber_alloc()) == NULL) goto fail; /* * Is ntver right? It certainly works on w2k8... If others are needed, * that might require changes to lsa_cldap_parse */ r = lsa_cldap_setup_pdu(pdu, dname, NULL, NETLOGON_NT_VERSION_5EX); struct pollfd pingchk = {fd, POLLIN, 0}; if ((dcaddr = malloc(INET6_ADDRSTRLEN + 2)) == NULL) goto fail; if (strncpy(dcaddr, "\\\\", 3) == NULL) goto fail; if ((dcname = malloc(MAXHOSTNAMELEN + 3)) == NULL) goto fail; be = (struct _berelement *)pdu; sr = NULL; while ((sr = lsa_srv_next(ctx, sr)) != NULL) { r = sendto(fd, be->ber_buf, (size_t)(be->ber_end - be->ber_buf), 0, (struct sockaddr *)&sr->addr, sizeof(sr->addr)); if (poll(&pingchk, 1, 100) == 0) continue; if ((ret = ber_alloc()) == NULL) goto fail; rbe = (struct _berelement *)ret; recvfrom(fd, rbe->ber_buf, (size_t)(rbe->ber_end - rbe->ber_buf), 0, (struct sockaddr *)&addr, &addrlen); if ((dci = malloc(sizeof (DOMAIN_CONTROLLER_INFO))) == NULL) { ber_free(ret, 1); goto fail; } dci->DomainControllerName = dcname; r = lsa_cldap_parse(ret, dci); ber_free(ret, 1); if (r == 0) break; if (r > 1) goto fail; } if (sr == NULL) goto fail; paddr = (struct sockaddr_in6 *)&addr; inet_ntop(paddr->sin6_family, &paddr->sin6_addr, dcaddr+2, INET6_ADDRSTRLEN); dci->DomainControllerAddress = dcaddr; dci->DomainControllerAddressType = DS_INET_ADDRESS; ber_free(pdu, 1); lsa_srv_fini(ctx); (void) close(fd); return (dci); fail: lsa_srv_fini(ctx); if (dci) freedci(dci); else free(dcname); free(dcaddr); ber_free(pdu, 1); if (fd >= 0) (void) close(fd); return (NULL); }
int VmDirCreateAppendEntriesCtrl( PVDIR_APPEND_ENTRIES_CONTROL_VALUE pAppendEntriesCtrlValue, LDAPControl* pAppendEntriesCtrl ) { int retVal = LDAP_SUCCESS; BerElement* pBer = NULL; BerValue leaderBV = {0}; BerValue preLogIndexBV = {0}; BerValue leaderCommitBV = {0}; BerValue entriesBV = {0}; if (!pAppendEntriesCtrlValue || !pAppendEntriesCtrl) { BAIL_WITH_VMDIR_ERROR(retVal, VMDIR_ERROR_INVALID_PARAMETER); } if ((pBer = ber_alloc()) == NULL) { BAIL_WITH_VMDIR_ERROR(retVal, VMDIR_ERROR_NO_MEMORY); } leaderBV.bv_val = (char*)pAppendEntriesCtrlValue->leader; leaderBV.bv_len = VmDirStringLenA(pAppendEntriesCtrlValue->leader); retVal = VmDirAllocateStringPrintf(&preLogIndexBV.bv_val, "%"PRIu64, pAppendEntriesCtrlValue->preLogIndex); BAIL_ON_VMDIR_ERROR( retVal ); preLogIndexBV.bv_len = VmDirStringLenA(preLogIndexBV.bv_val); retVal = VmDirAllocateStringPrintf(&leaderCommitBV.bv_val, "%"PRIu64, pAppendEntriesCtrlValue->leaderCommit); BAIL_ON_VMDIR_ERROR( retVal ); leaderCommitBV.bv_len = VmDirStringLenA( leaderCommitBV.bv_val); entriesBV.bv_val = pAppendEntriesCtrlValue->entries.lberbv.bv_val; entriesBV.bv_len = pAppendEntriesCtrlValue->entries.lberbv.bv_len; if ( ber_printf( pBer, "{iOOiOO}", pAppendEntriesCtrlValue->term, &leaderBV, &preLogIndexBV, pAppendEntriesCtrlValue->preLogTerm, &leaderCommitBV, &entriesBV) == -1) { VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "%s: ber_printf failed.", __FUNCTION__ ); BAIL_WITH_VMDIR_ERROR(retVal, VMDIR_ERROR_NO_MEMORY); } memset( pAppendEntriesCtrl, 0, sizeof( LDAPControl )); pAppendEntriesCtrl->ldctl_oid = LDAP_APPEND_ENTRIES_CONTROL; pAppendEntriesCtrl->ldctl_iscritical = '1'; if (ber_flatten2(pBer, &pAppendEntriesCtrl->ldctl_value, 1)) { BAIL_WITH_VMDIR_ERROR(retVal, VMDIR_ERROR_NO_MEMORY); } cleanup: VMDIR_SAFE_FREE_MEMORY(preLogIndexBV.bv_val); VMDIR_SAFE_FREE_MEMORY(leaderCommitBV.bv_val); if (pBer) { ber_free(pBer, 1); } return retVal; error: VmDirFreeCtrlContent(pAppendEntriesCtrl); goto cleanup; }
/* * Filter out unresponsive servers, and save the domain info * returned by the "LDAP ping" in the returned object. * If ctx != NULL, this is a query for a DC, in which case we * also save the Domain GUID, Site name, and Forest name as * "auto" (discovered) values in the ctx. * * Only return the "winner". (We only want one DC/GC) */ ad_disc_ds_t * ldap_ping(ad_disc_t ctx, ad_disc_cds_t *dclist, char *dname, int reqflags) { struct sockaddr_in6 addr6; socklen_t addrlen; struct pollfd pingchk; ad_disc_cds_t *send_ds; ad_disc_cds_t *recv_ds = NULL; ad_disc_ds_t *ret_ds = NULL; BerElement *req = NULL; BerElement *res = NULL; struct _berelement *be, *rbe; size_t be_len, rbe_len; int fd = -1; int tries = 3; int waitsec; int r; uint16_t msgid; /* One plus a null entry. */ ret_ds = calloc(2, sizeof (ad_disc_ds_t)); if (ret_ds == NULL) goto fail; if ((fd = socket(PF_INET6, SOCK_DGRAM, 0)) < 0) goto fail; (void) memset(&addr6, 0, sizeof (addr6)); addr6.sin6_family = AF_INET6; addr6.sin6_addr = in6addr_any; if (bind(fd, (struct sockaddr *)&addr6, sizeof (addr6)) < 0) goto fail; /* * semi-unique msgid... */ msgid = gethrtime() & 0xffff; /* * Is ntver right? It certainly works on w2k8... If others are needed, * that might require changes to cldap_parse */ req = cldap_build_request(dname, NULL, NETLOGON_NT_VERSION_5EX, msgid); if (req == NULL) goto fail; be = (struct _berelement *)req; be_len = be->ber_end - be->ber_buf; if ((res = ber_alloc()) == NULL) goto fail; rbe = (struct _berelement *)res; rbe_len = rbe->ber_end - rbe->ber_buf; pingchk.fd = fd; pingchk.events = POLLIN; pingchk.revents = 0; try_again: send_ds = dclist; waitsec = 5; while (recv_ds == NULL && waitsec > 0) { /* * If there is another candidate, send to it. */ if (send_ds->cds_ds.host[0] != '\0') { send_to_cds(send_ds, be->ber_buf, be_len, fd); send_ds++; /* * Wait 1/10 sec. before the next send. */ r = poll(&pingchk, 1, 100); #if 0 /* DEBUG */ /* Drop all responses 1st pass. */ if (waitsec == 5) r = 0; #endif } else { /* * No more candidates to "ping", so * just wait a sec for responses. */ r = poll(&pingchk, 1, 1000); if (r == 0) --waitsec; } if (r > 0) { /* * Got a response. */ (void) memset(&addr6, 0, addrlen = sizeof (addr6)); r = recvfrom(fd, rbe->ber_buf, rbe_len, 0, (struct sockaddr *)&addr6, &addrlen); recv_ds = find_cds_by_addr(dclist, &addr6); if (recv_ds == NULL) continue; (void) cldap_parse(ctx, recv_ds, res); if ((recv_ds->cds_ds.flags & reqflags) != reqflags) { logger(LOG_ERR, "Skip %s" "due to flags 0x%X", recv_ds->cds_ds.host, recv_ds->cds_ds.flags); recv_ds = NULL; } } } if (recv_ds == NULL) { if (--tries <= 0) goto fail; goto try_again; } (void) memcpy(ret_ds, recv_ds, sizeof (*ret_ds)); ber_free(res, 1); ber_free(req, 1); (void) close(fd); return (ret_ds); fail: ber_free(res, 1); ber_free(req, 1); (void) close(fd); free(ret_ds); return (NULL); }
/* * Construct CLDAPMessage PDU for NetLogon search request. * * CLDAPMessage ::= SEQUENCE { * messageID MessageID, * protocolOp searchRequest SearchRequest; * } * * SearchRequest ::= * [APPLICATION 3] SEQUENCE { * baseObject LDAPDN, * scope ENUMERATED { * baseObject (0), * singleLevel (1), * wholeSubtree (2) * }, * derefAliases ENUMERATED { * neverDerefAliases (0), * derefInSearching (1), * derefFindingBaseObj (2), * derefAlways (3) * }, * sizeLimit INTEGER (0 .. MaxInt), * timeLimit INTEGER (0 .. MaxInt), * attrsOnly BOOLEAN, * filter Filter, * attributes SEQUENCE OF AttributeType * } */ BerElement * cldap_build_request(const char *dname, const char *host, uint32_t ntver, uint16_t msgid) { BerElement *ber; int len = 0; char *basedn = ""; int scope = LDAP_SCOPE_BASE, deref = LDAP_DEREF_NEVER, sizelimit = 0, timelimit = 0, attrsonly = 0; char filter[512]; char ntver_esc[13]; char *p, *pend; /* * Construct search filter in LDAP format. */ p = filter; pend = p + sizeof (filter); len = snprintf(p, pend - p, "(&(DnsDomain=%s)", dname); if (len >= (pend - p)) goto fail; p += len; if (host != NULL) { len = snprintf(p, (pend - p), "(Host=%s)", host); if (len >= (pend - p)) goto fail; p += len; } if (ntver != 0) { /* * Format NtVer as little-endian with LDAPv3 escapes. */ cldap_escape_le64(ntver_esc, ntver, sizeof (ntver)); len = snprintf(p, (pend - p), "(NtVer=%s)", ntver_esc); if (len >= (pend - p)) goto fail; p += len; } len = snprintf(p, pend - p, ")"); if (len >= (pend - p)) goto fail; p += len; /* * Encode CLDAPMessage and beginning of SearchRequest sequence. */ if ((ber = ber_alloc()) == NULL) goto fail; if (ber_printf(ber, "{it{seeiib", msgid, LDAP_REQ_SEARCH, basedn, scope, deref, sizelimit, timelimit, attrsonly) < 0) goto fail; /* * Encode Filter sequence. */ if (ldap_put_filter(ber, filter) < 0) goto fail; /* * Encode attribute and close Filter and SearchRequest sequences. */ if (ber_printf(ber, "{s}}}", NETLOGON_ATTR_NAME) < 0) goto fail; /* * Success */ return (ber); fail: if (ber != NULL) ber_free(ber, 1); return (NULL); }
/* * Get a Slapi_Entry ready to send over the wire as part of * a total update protocol stream. Convert the entry and all * of its state information to a BerElement which will be the * payload of an extended LDAP operation. * * Entries consist of: * - An entry DN * - A uniqueID * - A set of present attributes, each of which consists of: * - A set of present values, each of which consists of: * - A value * - A set of CSNs * - A set of deleted values, each of which consists of: * - A value * - A set of CSNs * - A set of deleted attibutes, each of which consists of: * - An attribute type * - A set of CSNs. Note that this list of CSNs will always contain exactly one CSN. * * This all gets mashed into one BerElement, ready to be blasted over the wire to * a replica. * */ BerElement * entry2bere(const Slapi_Entry *e, char **excluded_attrs) { BerElement *ber = NULL; const char *str = NULL; const char *dnstr = NULL; char *type; Slapi_DN *sdn = NULL; Slapi_Attr *attr = NULL, *prev_attr; int rc; PR_ASSERT(NULL != e); if ((ber = ber_alloc()) == NULL) { goto loser; } BER_DEBUG("{"); if (ber_printf(ber, "{") == -1) /* Begin outer sequence */ { goto loser; } /* Get the entry's uniqueid */ if ((str = slapi_entry_get_uniqueid(e)) == NULL) { goto loser; } BER_DEBUG("s(uniqueid)"); if (ber_printf(ber, "s", str) == -1) { goto loser; } /* Get the entry's DN */ if ((sdn = slapi_entry_get_sdn((Slapi_Entry *)e)) == NULL) /* XXXggood had to cast away const */ { goto loser; } if ((dnstr = slapi_sdn_get_dn(sdn)) == NULL) { goto loser; } BER_DEBUG("s(dn)"); if (ber_printf(ber, "s", dnstr) == -1) { goto loser; } /* Next comes the annoted list of the entry's attributes */ BER_DEBUG("["); if (ber_printf(ber, "[") == -1) /* Begin set of attributes */ { goto loser; } /* * We iterate over all of the non-deleted attributes first. */ slapi_entry_first_attr(e, &attr); while (NULL != attr) { /* ONREPL - skip uniqueid attribute since we already sent uniqueid This is a hack; need to figure a better way of storing uniqueid in an entry */ slapi_attr_get_type (attr, &type); if (strcasecmp (type, SLAPI_ATTR_UNIQUEID) != 0) { /* Check to see if this attribute is excluded by the fractional list */ if ( (NULL == excluded_attrs) || !charray_inlist(excluded_attrs,type)) { /* Process this attribute */ rc = my_ber_printf_attr (ber, attr, PR_FALSE); if (rc != 0) { goto loser; } } } prev_attr = attr; slapi_entry_next_attr(e, prev_attr, &attr); } /* * Now iterate over the deleted attributes. */ entry_first_deleted_attribute(e, &attr); while (attr != NULL) { slapi_attr_get_type (attr, &type); /* Check to see if this attribute is excluded by the fractional list */ if ( (NULL == excluded_attrs) || !charray_inlist(excluded_attrs,type)) { /* Process this attribute */ rc = my_ber_printf_attr (ber, attr, PR_TRUE); if (rc != 0) { goto loser; } } entry_next_deleted_attribute(e, &attr); } BER_DEBUG("]"); if (ber_printf(ber, "]") == -1) /* End set for attributes */ { goto loser; } BER_DEBUG("}"); if (ber_printf(ber, "}") == -1) /* End sequence for this entry */ { goto loser; } /* If we get here, everything went ok */ BER_DEBUG("\n"); goto free_and_return; loser: if (NULL != ber) { ber_free(ber, 1); ber = NULL; } free_and_return: return ber; }