2N/A * The contents of this file are subject to the terms of the 2N/A * Common Development and Distribution License (the "License"). 2N/A * You may not use this file except in compliance with the License. 2N/A * See the License for the specific language governing permissions 2N/A * and limitations under the License. 2N/A * When distributing Covered Code, include this CDDL HEADER in each 2N/A * If applicable, add the following below this CDDL HEADER, with the 2N/A * fields enclosed by brackets "[]" replaced with your own identifying 2N/A * information: Portions Copyright [yyyy] [name of copyright owner] 2N/A * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. 2N/A/* List of DSs, needed by the idle connection reaper thread */ 2N/A * List of query state structs -- needed so we can "route" LDAP results 2N/A * to the right context if multiple threads should be using the same 2N/A * connection concurrently 2N/A * Turn "dc=foo,dc=bar,dc=com" into "foo.bar.com"; ignores any other 2N/A * attributes (CN, etc...). 2N/A * Convert a binary SID in a BerValue to a adutils_sid_t 2N/A * The binary format of a SID is as follows: 2N/A * byte #0: version, always 0x01 2N/A * byte #1: RID count, always <= 0x0f 2N/A * bytes #2-#7: SID authority, big-endian 48-bit unsigned int 2N/A * followed by RID count RIDs, each a little-endian, unsigned 2N/A * Sanity checks: must have at least one RID, version must be 2N/A * 0x01, and the length must be 8 + rid count * 4 2N/A /* big endian -- so start from the left */ 2N/A /* little endian -- so start from the right */ 2N/A a = (v[j +
3] <<
24) | (v[j +
2] <<
16) |
2N/A (v[j +
1] <<
8) | (v[j]);
2N/A * Convert a adutils_sid_t to S-1-... 2N/A * We could optimize like so, but, why? 2N/A * if (sidp->authority < 10) 2N/A * else if (sidp->authority < 100) 2N/A * len += snprintf(NULL, 0"%llu", sidp->authority); 2N/A /* Max length of a uint32_t printed out in ASCII is 10 bytes */ 2N/A * Convert a adutils_sid_t to on-the-wire encoding 2N/A *p++ =
0x01;
/* version */ 2N/A /* sub authority count */ 2N/A /* big-endian -- start from left */ 2N/A *p++ = (a >>
40) &
0xFF;
2N/A *p++ = (a >>
32) &
0xFF;
2N/A *p++ = (a >>
24) &
0xFF;
2N/A *p++ = (a >>
16) &
0xFF;
2N/A *p++ = (a >>
8) &
0xFF;
2N/A /* sub-authorities */ 2N/A /* little-endian -- start from right */ 2N/A *p++ = (r &
0x000000FF);
2N/A *p++ = (r &
0x0000FF00) >>
8;
2N/A *p++ = (r &
0x00FF0000) >>
16;
2N/A *p++ = (r &
0xFF000000) >>
24;
2N/A * Convert a stringified SID (S-1-...) into a hex-encoded version of the 2N/A * on-the-wire encoding, but with each pair of hex digits pre-pended 2N/A * with a '\', so we can pass this to libldap. 2N/A /* Only version 1 SIDs please */ 2N/A /* can't end on a '-' */ 2N/A /* Adjust count for version and authority */ 2N/A /* we know the version number and RID count */ 2N/A /* must have at least one RID, but not too many */ 2N/A /* check that we only have digits and '-' */ 2N/A /* 64-bit safe parsing of unsigned 48-bit authority value */ 2N/A /* errors parsing the authority or too many bits */ 2N/A (a &
0x0000ffffffffffffULL) != a)
2N/A for (i = 0; i < j; i++) {
2N/A /* 64-bit safe parsing of unsigned 32-bit RID */ 2N/A /* errors parsing the RID or too many bits */ 2N/A (r &
0xffffffffUL) != r)
2N/A /* check that all of the string SID has been consumed */ 2N/A /* binary encode the SID */ 2N/A /* hex encode, with a backslash before each byte */ 2N/A * user or group SID (i.e., S-1-5-w-x-y-z-<user/group RID>) then 2N/A * save the last RID and truncate the SID 2N/A * Return a NUL-terminated stringified SID from the value of an 2N/A * objectSid attribute and put the last RID in *rid. 2N/A /* objectSid is single valued */ 2N/A * Extract an int from the Ber value 2N/A * Return B_TRUE if a valid integer was found, B_FALSE if not. 2N/A char buf[
40];
/* big enough for any int */ 2N/A /* Junk after the number? */ 2N/A/* Return a NUL-terminated string from the Ber value */ 2N/A /* There should be no extra arguemnts for SASL/GSSAPI authentication */ 2N/A * Idle connection reaping side of connection management 2N/A /* domain_name is required iff we are talking directly to a DC */ 2N/A /* Open and bind an LDAP connection */ 2N/A /* Error has already been logged */ 2N/A * Enforce I/O timeout to protect SASL bind from hang. 2N/A * Connection management: find an open connection or open one 2N/A * First try: count the number of DSes. 2N/A * Integer overflow is not an issue -- we can't have so many 2N/A * DSes because they won't fit even DNS over TCP, and SMF 2N/A * shouldn't let you set so many. 2N/A * Begin round-robin at the next DS in the list after the last 2N/A * one that we had a connection to, else start with the first 2N/A * Round-robin -- pick the next one on the list; if the list 2N/A * changes on us, no big deal, we'll just potentially go 2N/A * around the wrong number of times. 2N/A /* Found suitable DS, open it if not already opened */ 2N/A /* Free this host if its owner no longer exists. */ 2N/A * Create a adutils_host_t, populate it and add it to the list of hosts. 2N/A * Free a DS configuration. 2N/A * Caller must lock the adhostlock mutex 2N/A * Still in use. Set its owner to NULL so 2N/A * that it can be freed when its ref count 2N/A * Add known domain name and domain SID to AD configuration. 2N/A * Check that this AD supports this domain. 2N/A * If there are no known domains assume that the 2N/A * domain is supported by this AD. 2N/A * Returns 1 if this domain is supported by this AD 2N/A return ((i == 0) ?
1 : 0);
2N/A * Check that this AD supports the SID prefix. 2N/A * The SID prefix should match the domain SID. 2N/A * If there are no known domains assume that the 2N/A * SID prefix is supported by this AD. 2N/A * Returns 1 if this sid prefix is supported by this AD 2N/A return ((i == 0) ?
1 : 0);
2N/A * Find the adutils_query_state_t to which a given LDAP result msgid on a 2N/A * given connection belongs. This routine increaments the reference count 2N/A * so that the object can not be freed. adutils_lookup_batch_unlock() 2N/A * must be called to decreament the reference count. 2N/A * Queue LDAP result for the given query. 2N/A /* Check that this is the domain that we were looking for */ 2N/A /* Allocate memory for the entry */ 2N/A /* Count the number of name-value pairs for this entry */ 2N/A /* Allocate array for the attribute name-value pairs */ 2N/A * Put the search result onto the given adutils_q_t. 2N/A * Returns: 0 success 2N/A * Try to get a result; if there is one, find the corresponding 2N/A * adutils_q_t and process the result. 2N/A * Returns: 0 success 2N/A /* Get one result */ 2N/A "AD ldap_result error - %d queued requests",
num);
2N/A * We use the caller-provided callback 2N/A * to process the result. 2N/A * No callback. We fallback to our 2N/A * default behaviour. All the entries 2N/A * gotten from this search have been 2N/A * added to the result list during 2N/A * LDAP_RES_SEARCH_ENTRY (see below). 2N/A * Here we set the return status to 2N/A * notfound if the result is still empty. 2N/A "AD cannot find message ID (%d) " 2N/A "- %d queued requests",
2N/A * We use the caller-provided callback 2N/A * to process the entry. 2N/A * No callback. We fallback to our 2N/A * default behaviour. This entry 2N/A * will be added to the result list. 2N/A "Failed to queue entry by " 2N/A "- %d queued requests",
2N/A "AD cannot find message ID (%d) " 2N/A "- %d queued requests",
2N/A * We have no need for these at the moment. Eventually, 2N/A * when we query things that we can't expect to find in 2N/A * the Global Catalog then we'll need to learn to follow 2N/A /* timeout or error; treat the same */ 2N/A * This routine decreament the reference count of the 2N/A * adutils_query_state_t 2N/A * Decrement reference count with qstatelock locked 2N/A * If there are no references wakup the allocating thread 2N/A * This routine frees the adutils_query_state_t structure 2N/A * If the reference count is greater than 1 it waits 2N/A * for the other threads to finish using it. 2N/A * Set state to dead to stop further operations. 2N/A * Wait for reference count with qstatelock locked 2N/A /* Remove this state struct from the list of state structs */ 2N/A /* Clear results for queries that failed */ 2N/A * This routine waits for other threads using the 2N/A * adutils_query_state_t structure to finish. 2N/A * If the reference count is greater than 1 it waits 2N/A * for the other threads to finish using it. 2N/A * Set state to dead to stop further operation. 2N/A * Wait for reference count to get to one 2N/A * with qstatelock locked. 2N/A * Process active queries in the AD lookup batch and then finalize the 2N/A /* Process results until done or until timeout, if given */ 2N/A /* Wait for other threads processing search result to finish */ 2N/A * Send one prepared search, queue up msgid, process what results are 2N/A * Remember the expected domain so we can check the results 2N/A /* Remember where to put the results */ 2N/A * Provide sane defaults for the results in case we never hear 2N/A * back from the DS before closing the connection. 2N/A /* Check the number of queued requests first */ 2N/A /* Send this lookup, don't wait for a result here */ 2N/A "AD ldap_search_ext error (%s) " 2N/A "- %d queued requests",
2N/A * Reap as many requests as we can _without_ waiting to prevent 2N/A * any possible TCP socket buffer starvation deadlocks. 2N/A * Single AD lookup request implemented on top of the batch API.