*/
#include "includes.h"
+#include "lib/ldb/include/includes.h"
#ifdef HAVE_LDAP
if (gotalarm != 0)
return LDAP_TIMELIMIT_EXCEEDED;
+ /*
+ * A bug in OpenLDAP means ldap_search_ext_s can return
+ * LDAP_SUCCESS but with a NULL res pointer. Cope with
+ * this. See bug #6279 for details. JRA.
+ */
+
+ if (*res == NULL) {
+ return LDAP_TIMELIMIT_EXCEEDED;
+ }
+
return result;
}
bool ads_closest_dc(ADS_STRUCT *ads)
{
- if (ads->config.flags & ADS_CLOSEST) {
- DEBUG(10,("ads_closest_dc: ADS_CLOSEST flag set\n"));
+ if (ads->config.flags & NBT_SERVER_CLOSEST) {
+ DEBUG(10,("ads_closest_dc: NBT_SERVER_CLOSEST flag set\n"));
return True;
}
/* not sure if this can ever happen */
if (ads_sitename_match(ads)) {
- DEBUG(10,("ads_closest_dc: ADS_CLOSEST flag not set but sites match\n"));
+ DEBUG(10,("ads_closest_dc: NBT_SERVER_CLOSEST flag not set but sites match\n"));
+ return True;
+ }
+
+ if (ads->config.client_site_name == NULL) {
+ DEBUG(10,("ads_closest_dc: client belongs to no site\n"));
return True;
}
bool ads_try_connect(ADS_STRUCT *ads, const char *server )
{
char *srv;
- struct cldap_netlogon_reply cldap_reply;
+ struct nbt_cldap_netlogon_5 cldap_reply;
+ TALLOC_CTX *mem_ctx = NULL;
+ bool ret = false;
if (!server || !*server) {
return False;
DEBUG(5,("ads_try_connect: sending CLDAP request to %s (realm: %s)\n",
server, ads->server.realm));
+ mem_ctx = talloc_init("ads_try_connect");
+ if (!mem_ctx) {
+ DEBUG(0,("out of memory\n"));
+ return false;
+ }
+
/* this copes with inet_ntoa brokenness */
srv = SMB_STRDUP(server);
ZERO_STRUCT( cldap_reply );
- if ( !ads_cldap_netlogon( srv, ads->server.realm, &cldap_reply ) ) {
+ if ( !ads_cldap_netlogon_5(mem_ctx, srv, ads->server.realm, &cldap_reply ) ) {
DEBUG(3,("ads_try_connect: CLDAP request %s failed.\n", srv));
- SAFE_FREE( srv );
- return False;
+ ret = false;
+ goto out;
}
/* Check the CLDAP reply flags */
- if ( !(cldap_reply.flags & ADS_LDAP) ) {
+ if ( !(cldap_reply.server_type & NBT_SERVER_LDAP) ) {
DEBUG(1,("ads_try_connect: %s's CLDAP reply says it is not an LDAP server!\n",
srv));
- SAFE_FREE( srv );
- return False;
+ ret = false;
+ goto out;
}
/* Fill in the ads->config values */
SAFE_FREE(ads->config.client_site_name);
SAFE_FREE(ads->server.workgroup);
- ads->config.flags = cldap_reply.flags;
- ads->config.ldap_server_name = SMB_STRDUP(cldap_reply.hostname);
- strupper_m(cldap_reply.domain);
- ads->config.realm = SMB_STRDUP(cldap_reply.domain);
+ ads->config.flags = cldap_reply.server_type;
+ ads->config.ldap_server_name = SMB_STRDUP(cldap_reply.pdc_dns_name);
+ ads->config.realm = SMB_STRDUP(cldap_reply.dns_domain);
+ strupper_m(ads->config.realm);
ads->config.bind_path = ads_build_dn(ads->config.realm);
- if (*cldap_reply.server_site_name) {
+ if (*cldap_reply.server_site) {
ads->config.server_site_name =
- SMB_STRDUP(cldap_reply.server_site_name);
+ SMB_STRDUP(cldap_reply.server_site);
}
- if (*cldap_reply.client_site_name) {
+ if (*cldap_reply.client_site) {
ads->config.client_site_name =
- SMB_STRDUP(cldap_reply.client_site_name);
+ SMB_STRDUP(cldap_reply.client_site);
}
- ads->server.workgroup = SMB_STRDUP(cldap_reply.netbios_domain);
+ ads->server.workgroup = SMB_STRDUP(cldap_reply.domain);
ads->ldap.port = LDAP_PORT;
if (!interpret_string_addr(&ads->ldap.ss, srv, 0)) {
DEBUG(1,("ads_try_connect: unable to convert %s "
"to an address\n",
srv));
- SAFE_FREE( srv );
- return False;
+ ret = false;
+ goto out;
}
- SAFE_FREE(srv);
-
/* Store our site name. */
- sitename_store( cldap_reply.domain, cldap_reply.client_site_name );
+ sitename_store( cldap_reply.domain, cldap_reply.client_site);
+ sitename_store( cldap_reply.dns_domain, cldap_reply.client_site);
- return True;
+ ret = true;
+ out:
+ SAFE_FREE(srv);
+ TALLOC_FREE(mem_ctx);
+
+ return ret;
}
/**********************************************************************
static NTSTATUS ads_find_dc(ADS_STRUCT *ads)
{
+ const char *c_domain;
const char *c_realm;
int count, i=0;
struct ip_service *ip_list;
const char *realm;
+ const char *domain;
bool got_realm = False;
bool use_own_domain = False;
char *sitename;
if (c_realm && *c_realm)
got_realm = True;
+ again:
+
/* we need to try once with the realm name and fallback to the
netbios domain name if we fail (if netbios has not been disabled */
if ( use_own_domain )
c_realm = lp_workgroup();
}
+ }
- if ( !c_realm || !*c_realm ) {
- DEBUG(0,("ads_find_dc: no realm or workgroup! Don't know what to do\n"));
- return NT_STATUS_INVALID_PARAMETER; /* rather need MISSING_PARAMETER ... */
- }
+ if ( !c_realm || !*c_realm ) {
+ DEBUG(0,("ads_find_dc: no realm or workgroup! Don't know what to do\n"));
+ return NT_STATUS_INVALID_PARAMETER; /* rather need MISSING_PARAMETER ... */
+ }
+
+ if ( use_own_domain ) {
+ c_domain = lp_workgroup();
+ } else {
+ c_domain = ads->server.workgroup;
}
realm = c_realm;
+ domain = c_domain;
- sitename = sitename_fetch(realm);
+ /*
+ * In case of LDAP we use get_dc_name() as that
+ * creates the custom krb5.conf file
+ */
+ if (!(ads->auth.flags & ADS_AUTH_NO_BIND)) {
+ fstring srv_name;
+ struct sockaddr_storage ip_out;
+
+ DEBUG(6,("ads_find_dc: (ldap) looking for %s '%s'\n",
+ (got_realm ? "realm" : "domain"), realm));
+
+ if (get_dc_name(domain, realm, srv_name, &ip_out)) {
+ /*
+ * we call ads_try_connect() to fill in the
+ * ads->config details
+ */
+ if (ads_try_connect(ads, srv_name)) {
+ return NT_STATUS_OK;
+ }
+ }
- again:
+ return NT_STATUS_NO_LOGON_SERVERS;
+ }
- DEBUG(6,("ads_find_dc: looking for %s '%s'\n",
+ sitename = sitename_fetch(realm);
+
+ DEBUG(6,("ads_find_dc: (cldap) looking for %s '%s'\n",
(got_realm ? "realm" : "domain"), realm));
status = get_sorted_dc_list(realm, sitename, &ip_list, &count, got_realm);
/* cache the successful connection for workgroup and realm */
if (ads_closest_dc(ads)) {
- print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
- saf_store( ads->server.workgroup, addr);
- saf_store( ads->server.realm, addr);
+ saf_store( ads->server.workgroup, ads->config.ldap_server_name);
+ saf_store( ads->server.realm, ads->config.ldap_server_name);
}
ldap_set_option(ads->ldap.ld, LDAP_OPT_PROTOCOL_VERSION, &version);
if (!values) return NULL;
for (i=0; in_vals[i]; i++) {
- push_utf8_talloc(ctx, &values[i], in_vals[i]);
+ if (push_utf8_talloc(ctx, &values[i], in_vals[i]) == (size_t) -1) {
+ TALLOC_FREE(values);
+ return NULL;
+ }
}
return values;
}
}
/* if/when we decide to utf8-encode attrs, take out this next line */
- str_list_free(&search_attrs);
+ TALLOC_FREE(search_attrs);
return ADS_ERROR(rc);
}
/* this relies on the way that ldap_add_result_entry() works internally. I hope
that this works on all ldap libs, but I have only tested with openldap */
- for (msg = ads_first_entry(ads, res2); msg; msg = next) {
- next = ads_next_entry(ads, msg);
+ for (msg = ads_first_message(ads, res2); msg; msg = next) {
+ next = ads_next_message(ads, msg);
ldap_add_result_entry((LDAPMessage **)res, msg);
}
/* note that we do not free res2, as the memory is now
done:
talloc_destroy(ctx);
/* if/when we decide to utf8-encode attrs, take out this next line */
- str_list_free(&search_attrs);
+ TALLOC_FREE(search_attrs);
return ADS_ERROR(rc);
}
/**
return ldap_next_entry(ads->ldap.ld, res);
}
+/**
+ * pull the first message from a ADS result
+ * @param ads connection to ads server
+ * @param res Results of search
+ * @return first message from result
+ **/
+ LDAPMessage *ads_first_message(ADS_STRUCT *ads, LDAPMessage *res)
+{
+ return ldap_first_message(ads->ldap.ld, res);
+}
+
+/**
+ * pull the next message from a ADS result
+ * @param ads connection to ads server
+ * @param res Results of search
+ * @return next message from result
+ **/
+ LDAPMessage *ads_next_message(ADS_STRUCT *ads, LDAPMessage *res)
+{
+ return ldap_next_message(ads->ldap.ld, res);
+}
+
/**
* pull a single string from a ADS result
* @param ads connection to ads server
if ( (ads_s = ads_init( ads->server.realm, ads->server.workgroup,
ads->server.ldap_server )) == NULL )
{
+ status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
goto done;
}
ads_s->auth.flags = ADS_AUTH_ANON_BIND;
/**
* pull a DOM_SID from an extended dn string
- * @param mem_ctx TALLOC_CTX
+ * @param mem_ctx TALLOC_CTX
* @param extended_dn string
* @param flags string type of extended_dn
* @param sid pointer to a DOM_SID
- * @return boolean inidicating success
+ * @return NT_STATUS_OK on success,
+ * NT_INVALID_PARAMETER on error,
+ * NT_STATUS_NOT_FOUND if no SID present
**/
-bool ads_get_sid_from_extended_dn(TALLOC_CTX *mem_ctx,
- const char *extended_dn,
- enum ads_extended_dn_flags flags,
- DOM_SID *sid)
+ADS_STATUS ads_get_sid_from_extended_dn(TALLOC_CTX *mem_ctx,
+ const char *extended_dn,
+ enum ads_extended_dn_flags flags,
+ DOM_SID *sid)
{
char *p, *q, *dn;
if (!extended_dn) {
- return False;
+ return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
/* otherwise extended_dn gets stripped off */
if ((dn = talloc_strdup(mem_ctx, extended_dn)) == NULL) {
- return False;
+ return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
- /*
+ /*
* ADS_EXTENDED_DN_HEX_STRING:
* <GUID=238e1963cb390f4bb032ba0105525a29>;<SID=010500000000000515000000bb68c8fd6b61b427572eb04556040000>;CN=gd,OU=berlin,OU=suse,DC=ber,DC=suse,DC=de
*
* ADS_EXTENDED_DN_STRING (only with w2k3):
- <GUID=63198e23-39cb-4b0f-b032-ba0105525a29>;<SID=S-1-5-21-4257769659-666132843-1169174103-1110>;CN=gd,OU=berlin,OU=suse,DC=ber,DC=suse,DC=de
+ * <GUID=63198e23-39cb-4b0f-b032-ba0105525a29>;<SID=S-1-5-21-4257769659-666132843-1169174103-1110>;CN=gd,OU=berlin,OU=suse,DC=ber,DC=suse,DC=de
+ *
+ * Object with no SID, such as an Exchange Public Folder
+ * <GUID=28907fb4bdf6854993e7f0a10b504e7c>;CN=public,CN=Microsoft Exchange System Objects,DC=sd2k3ms,DC=west,DC=isilon,DC=com
*/
p = strchr(dn, ';');
if (!p) {
- return False;
+ return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
if (strncmp(p, ";<SID=", strlen(";<SID=")) != 0) {
- return False;
+ DEBUG(5,("No SID present in extended dn\n"));
+ return ADS_ERROR_NT(NT_STATUS_NOT_FOUND);
}
p += strlen(";<SID=");
q = strchr(p, '>');
if (!q) {
- return False;
+ return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
-
+
*q = '\0';
DEBUG(100,("ads_get_sid_from_extended_dn: sid string is %s\n", p));
switch (flags) {
-
+
case ADS_EXTENDED_DN_STRING:
if (!string_to_sid(sid, p)) {
- return False;
+ return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
break;
case ADS_EXTENDED_DN_HEX_STRING: {
buf_len = strhex_to_str(buf, sizeof(buf), p, strlen(p));
if (buf_len == 0) {
- return False;
+ return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
if (!sid_parse(buf, buf_len, sid)) {
DEBUG(10,("failed to parse sid\n"));
- return False;
+ return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
break;
}
default:
DEBUG(10,("unknown extended dn format\n"));
- return False;
+ return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
- return True;
+ return ADS_ERROR_NT(NT_STATUS_OK);
}
/**
* @param sids pointer to sid array to allocate
* @return the count of SIDs pulled
**/
- int ads_pull_sids_from_extendeddn(ADS_STRUCT *ads,
- TALLOC_CTX *mem_ctx,
- LDAPMessage *msg,
+ int ads_pull_sids_from_extendeddn(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ LDAPMessage *msg,
const char *field,
enum ads_extended_dn_flags flags,
DOM_SID **sids)
{
int i;
- size_t dn_count;
+ ADS_STATUS rc;
+ size_t dn_count, ret_count = 0;
char **dn_strings;
- if ((dn_strings = ads_pull_strings(ads, mem_ctx, msg, field,
+ if ((dn_strings = ads_pull_strings(ads, mem_ctx, msg, field,
&dn_count)) == NULL) {
return 0;
}
}
for (i=0; i<dn_count; i++) {
-
- if (!ads_get_sid_from_extended_dn(mem_ctx, dn_strings[i],
- flags, &(*sids)[i])) {
- TALLOC_FREE(*sids);
- TALLOC_FREE(dn_strings);
- return 0;
+ rc = ads_get_sid_from_extended_dn(mem_ctx, dn_strings[i],
+ flags, &(*sids)[i]);
+ if (!ADS_ERR_OK(rc)) {
+ if (NT_STATUS_EQUAL(ads_ntstatus(rc),
+ NT_STATUS_NOT_FOUND)) {
+ continue;
+ }
+ else {
+ TALLOC_FREE(*sids);
+ TALLOC_FREE(dn_strings);
+ return 0;
+ }
}
+ ret_count++;
}
TALLOC_FREE(dn_strings);
- return dn_count;
+ return ret_count;
}
/********************************************************************
filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)(sAMAccountName=%s))",
samaccountname);
if (filter == NULL) {
+ status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
goto out;
}
}
+/**
+ * verify or build and verify an account ou
+ * @param mem_ctx Pointer to talloc context
+ * @param ads connection to ads server
+ * @param account_ou
+ * @return status of search
+ **/
+
+ADS_STATUS ads_check_ou_dn(TALLOC_CTX *mem_ctx,
+ ADS_STRUCT *ads,
+ const char **account_ou)
+{
+ struct ldb_dn *name_dn = NULL;
+ const char *name = NULL;
+ char *ou_string = NULL;
+
+ name_dn = ldb_dn_explode(mem_ctx, *account_ou);
+ if (name_dn) {
+ return ADS_SUCCESS;
+ }
+
+ ou_string = ads_ou_string(ads, *account_ou);
+ if (!ou_string) {
+ return ADS_ERROR_LDAP(LDAP_INVALID_DN_SYNTAX);
+ }
+
+ name = talloc_asprintf(mem_ctx, "%s,%s", ou_string,
+ ads->config.bind_path);
+ SAFE_FREE(ou_string);
+ if (!name) {
+ return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+ }
+
+ name_dn = ldb_dn_explode(mem_ctx, name);
+ if (!name_dn) {
+ return ADS_ERROR_LDAP(LDAP_INVALID_DN_SYNTAX);
+ }
+
+ *account_ou = talloc_strdup(mem_ctx, name);
+ if (!*account_ou) {
+ return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+ }
+
+ return ADS_SUCCESS;
+}
+
#endif