Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
Copyright (C) Guenther Deschner 2005
Copyright (C) Gerald Carter 2006
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
-#include "lib/ldb/include/includes.h"
+#include "lib/ldb/include/ldb.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;
}
return True;
}
+ if (ads->config.client_site_name == NULL) {
+ DEBUG(10,("ads_closest_dc: client belongs to no site\n"));
+ return True;
+ }
+
DEBUG(10,("ads_closest_dc: %s is not the closest DC\n",
ads->config.ldap_server_name));
try a connection to a given ldap server, returning True and setting the servers IP
in the ads struct if successful
*/
-bool ads_try_connect(ADS_STRUCT *ads, const char *server )
+static bool ads_try_connect(ADS_STRUCT *ads, const char *server, bool gc)
{
char *srv;
- struct nbt_cldap_netlogon_5 cldap_reply;
- TALLOC_CTX *mem_ctx = NULL;
+ struct NETLOGON_SAM_LOGON_RESPONSE_EX cldap_reply;
+ TALLOC_CTX *frame = talloc_stackframe();
bool ret = false;
if (!server || !*server) {
+ TALLOC_FREE(frame);
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"));
+ if (!is_ipaddress(server)) {
+ struct sockaddr_storage ss;
+ char addr[INET6_ADDRSTRLEN];
+
+ if (!resolve_name(server, &ss, 0x20, true)) {
+ DEBUG(5,("ads_try_connect: unable to resolve name %s\n",
+ server ));
+ TALLOC_FREE(frame);
+ return false;
+ }
+ print_sockaddr(addr, sizeof(addr), &ss);
+ srv = talloc_strdup(frame, addr);
+ } else {
+ /* this copes with inet_ntoa brokenness */
+ srv = talloc_strdup(frame, server);
+ }
+
+ if (!srv) {
+ TALLOC_FREE(frame);
return false;
}
- /* this copes with inet_ntoa brokenness */
-
- srv = SMB_STRDUP(server);
+ DEBUG(5,("ads_try_connect: sending CLDAP request to %s (realm: %s)\n",
+ srv, ads->server.realm));
ZERO_STRUCT( cldap_reply );
- if ( !ads_cldap_netlogon_5(mem_ctx, srv, ads->server.realm, &cldap_reply ) ) {
+ if ( !ads_cldap_netlogon_5(frame, srv, ads->server.realm, &cldap_reply ) ) {
DEBUG(3,("ads_try_connect: CLDAP request %s failed.\n", srv));
ret = false;
goto out;
}
ads->server.workgroup = SMB_STRDUP(cldap_reply.domain);
- ads->ldap.port = LDAP_PORT;
+ ads->ldap.port = gc ? LDAP_GC_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",
sitename_store( cldap_reply.dns_domain, cldap_reply.client_site);
ret = true;
+
out:
- SAFE_FREE(srv);
- TALLOC_FREE(mem_ctx);
+ TALLOC_FREE(frame);
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 ( 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;
+
+ /*
+ * 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, false)) {
+ return NT_STATUS_OK;
+ }
+ }
+
+ return NT_STATUS_NO_LOGON_SERVERS;
+ }
sitename = sitename_fetch(realm);
again:
- DEBUG(6,("ads_find_dc: looking for %s '%s'\n",
+ 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);
}
}
- if ( ads_try_connect(ads, server) ) {
+ if ( ads_try_connect(ads, server, false) ) {
SAFE_FREE(ip_list);
SAFE_FREE(sitename);
return NT_STATUS_OK;
}
-
+
/* keep track of failures */
add_failed_connection_entry( realm, server, NT_STATUS_UNSUCCESSFUL );
}
return NT_STATUS_NO_LOGON_SERVERS;
}
+/*********************************************************************
+ *********************************************************************/
+
+static NTSTATUS ads_lookup_site(void)
+{
+ ADS_STRUCT *ads = NULL;
+ ADS_STATUS ads_status;
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+
+ ads = ads_init(lp_realm(), NULL, NULL);
+ if (!ads) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* The NO_BIND here will find a DC and set the client site
+ but not establish the TCP connection */
+
+ ads->auth.flags = ADS_AUTH_NO_BIND;
+ ads_status = ads_connect(ads);
+ if (!ADS_ERR_OK(ads_status)) {
+ DEBUG(4, ("ads_lookup_site: ads_connect to our realm failed! (%s)\n",
+ ads_errstr(ads_status)));
+ }
+ nt_status = ads_ntstatus(ads_status);
+
+ if (ads) {
+ ads_destroy(&ads);
+ }
+
+ return nt_status;
+}
+
+/*********************************************************************
+ *********************************************************************/
+
+static const char* host_dns_domain(const char *fqdn)
+{
+ const char *p = fqdn;
+
+ /* go to next char following '.' */
+
+ if ((p = strchr_m(fqdn, '.')) != NULL) {
+ p++;
+ }
+
+ return p;
+}
+
+
+/**
+ * Connect to the Global Catalog server
+ * @param ads Pointer to an existing ADS_STRUCT
+ * @return status of connection
+ *
+ * Simple wrapper around ads_connect() that fills in the
+ * GC ldap server information
+ **/
+
+ADS_STATUS ads_connect_gc(ADS_STRUCT *ads)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct dns_rr_srv *gcs_list;
+ int num_gcs;
+ char *realm = ads->server.realm;
+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+ ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
+ int i;
+ bool done = false;
+ char *sitename = NULL;
+
+ if (!realm)
+ realm = lp_realm();
+
+ if ((sitename = sitename_fetch(realm)) == NULL) {
+ ads_lookup_site();
+ sitename = sitename_fetch(realm);
+ }
+
+ do {
+ /* We try once with a sitename and once without
+ (unless we don't have a sitename and then we're
+ done */
+
+ if (sitename == NULL)
+ done = true;
+
+ nt_status = ads_dns_query_gcs(frame, realm, sitename,
+ &gcs_list, &num_gcs);
+
+ SAFE_FREE(sitename);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ ads_status = ADS_ERROR_NT(nt_status);
+ goto done;
+ }
+
+ /* Loop until we get a successful connection or have gone
+ through them all. When connecting a GC server, make sure that
+ the realm is the server's DNS name and not the forest root */
+
+ for (i=0; i<num_gcs; i++) {
+ ads->server.gc = true;
+ ads->server.ldap_server = SMB_STRDUP(gcs_list[i].hostname);
+ ads->server.realm = SMB_STRDUP(host_dns_domain(ads->server.ldap_server));
+ ads_status = ads_connect(ads);
+ if (ADS_ERR_OK(ads_status)) {
+ /* Reset the bind_dn to "". A Global Catalog server
+ may host multiple domain trees in a forest.
+ Windows 2003 GC server will accept "" as the search
+ path to imply search all domain trees in the forest */
+
+ SAFE_FREE(ads->config.bind_path);
+ ads->config.bind_path = SMB_STRDUP("");
+
+
+ goto done;
+ }
+ SAFE_FREE(ads->server.ldap_server);
+ SAFE_FREE(ads->server.realm);
+ }
+
+ TALLOC_FREE(gcs_list);
+ num_gcs = 0;
+ } while (!done);
+
+done:
+ SAFE_FREE(sitename);
+ talloc_destroy(frame);
+
+ return ads_status;
+}
+
/**
* Connect to the LDAP server
TALLOC_FREE(s);
}
- if (ads->server.ldap_server &&
- ads_try_connect(ads, ads->server.ldap_server)) {
- goto got_connection;
+ if (ads->server.ldap_server)
+ {
+ if (ads_try_connect(ads, ads->server.ldap_server, ads->server.gc)) {
+ goto got_connection;
+ }
+
+ /* The choice of which GC use is handled one level up in
+ ads_connect_gc(). If we continue on from here with
+ ads_find_dc() we will get GC searches on port 389 which
+ doesn't work. --jerry */
+
+ if (ads->server.gc == true) {
+ return ADS_ERROR(LDAP_OPERATIONS_ERROR);
+ }
}
ntstatus = ads_find_dc(ads);
/* Must use the userPrincipalName value here or sAMAccountName
and not servicePrincipalName; found by Guenther Deschner */
- asprintf(&ads->auth.user_name, "%s$", global_myname() );
+ if (asprintf(&ads->auth.user_name, "%s$", global_myname() ) == -1) {
+ DEBUG(0,("ads_connect: asprintf fail.\n"));
+ ads->auth.user_name = NULL;
+ }
}
if (!ads->auth.realm) {
/* this is a really nasty hack to avoid ADS DNS problems. It needs a patch
to MIT kerberos to work (tridge) */
{
- char *env;
- asprintf(&env, "KRB5_KDC_ADDRESS_%s", ads->config.realm);
- setenv(env, ads->auth.kdc_server, 1);
- free(env);
+ char *env = NULL;
+ if (asprintf(&env, "KRB5_KDC_ADDRESS_%s", ads->config.realm) > 0) {
+ setenv(env, ads->auth.kdc_server, 1);
+ free(env);
+ }
}
#endif
/* If the caller() requested no LDAP bind, then we are done */
-
+
if (ads->auth.flags & ADS_AUTH_NO_BIND) {
status = ADS_SUCCESS;
goto out;
status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
goto out;
}
-
+
/* Otherwise setup the TCP LDAP session */
ads->ldap.ld = ldap_open_with_timeout(ads->config.ldap_server_name,
- LDAP_PORT, lp_ldap_timeout());
+ ads->ldap.port, lp_ldap_timeout());
if (ads->ldap.ld == NULL) {
status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
goto out;
/* 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);
- status = ADS_ERROR(smb_ldap_start_tls(ads->ldap.ld, version));
- if (!ADS_ERR_OK(status)) {
- goto out;
+ if ( lp_ldap_ssl_ads() ) {
+ status = ADS_ERROR(smb_ldap_start_tls(ads->ldap.ld, version));
+ if (!ADS_ERR_OK(status)) {
+ goto out;
+ }
}
/* fill in the current time and offsets */
-
+
status = ads_current_time( ads );
if ( !ADS_ERR_OK(status) ) {
goto out;
}
/* Now do the bind */
-
+
if (ads->auth.flags & ADS_AUTH_ANON_BIND) {
status = ADS_ERROR(ldap_simple_bind_s(ads->ldap.ld, NULL, NULL));
goto out;
return status;
}
+/**
+ * Connect to the LDAP server using given credentials
+ * @param ads Pointer to an existing ADS_STRUCT
+ * @return status of connection
+ **/
+ADS_STATUS ads_connect_user_creds(ADS_STRUCT *ads)
+{
+ ads->auth.flags |= ADS_AUTH_USER_CREDS;
+
+ return ads_connect(ads);
+}
+
/**
* Disconnect the LDAP server
* @param ads Pointer to an existing ADS_STRUCT
{
struct berval **values;
int i;
-
+
if (!in_vals) return NULL;
for (i=0; in_vals[i]; i++)
; /* count values */
char **values;
int i;
size_t converted_size;
-
+
if (!in_vals) return NULL;
for (i=0; in_vals[i]; i++)
; /* count values */
int *count, struct berval **cookie)
{
int rc, i, version;
- char *utf8_expr, *utf8_path, **search_attrs;
+ char *utf8_expr, *utf8_path, **search_attrs = NULL;
size_t converted_size;
LDAPControl PagedResults, NoReferrals, ExternalCtrl, *controls[4], **rcontrols;
BerElement *cookie_be = NULL;
else {
/* This would be the utf8-encoded version...*/
/* if (!(search_attrs = ads_push_strvals(ctx, attrs))) */
- if (!(str_list_copy(talloc_tos(), &search_attrs, attrs))) {
+ if (!(search_attrs = str_list_copy(talloc_tos(), attrs))) {
rc = LDAP_NO_MEMORY;
goto done;
}
}
-
+
/* Paged results only available on ldap v3 or later */
ldap_get_option(ads->ldap.ld, LDAP_OPT_PROTOCOL_VERSION, &version);
if (version < LDAP_VERSION3) {
cookie_be = ber_alloc_t(LBER_USE_DER);
if (*cookie) {
- ber_printf(cookie_be, "{iO}", (ber_int_t) 1000, *cookie);
+ ber_printf(cookie_be, "{iO}", (ber_int_t) ads->config.ldap_page_size, *cookie);
ber_bvfree(*cookie); /* don't need it from last time */
*cookie = NULL;
} else {
- ber_printf(cookie_be, "{io}", (ber_int_t) 1000, "", 0);
+ ber_printf(cookie_be, "{io}", (ber_int_t) ads->config.ldap_page_size, "", 0);
}
ber_flatten(cookie_be, &cookie_bv);
PagedResults.ldctl_oid = CONST_DISCARD(char *, ADS_PAGE_CTL_OID);
handle them and paged results at the same time. Using them
together results in the result record containing the server
page control being removed from the result list (tridge/jmcd)
-
+
leaving this in despite the control that says don't generate
referrals, in case the server doesn't support it (jmcd)
*/
if (ext_bv) {
ber_bvfree(ext_bv);
}
-
+
/* if/when we decide to utf8-encode attrs, take out this next line */
TALLOC_FREE(search_attrs);
&res, &count, &cookie);
if (!ADS_ERR_OK(status)) break;
-
+
ads_process_results(ads, res, fn, data_area);
ads_msgfree(ads, res);
}
else {
/* This would be the utf8-encoded version...*/
/* if (!(search_attrs = ads_push_strvals(ctx, attrs))) */
- if (!(str_list_copy(talloc_tos(), &search_attrs, attrs)))
+ if (!(search_attrs = str_list_copy(talloc_tos(), attrs)))
{
DEBUG(1,("ads_do_search: str_list_copy() failed!"));
rc = LDAP_NO_MEMORY;
ldap_msgfree(msg);
}
-/**
- * Free up memory from various ads requests
- * @param ads connection to ads server
- * @param mem Area to free
- **/
-void ads_memfree(ADS_STRUCT *ads, void *mem)
-{
- SAFE_FREE(mem);
-}
-
/**
* Get a dn from search results
* @param ads connection to ads server
* @param msg Search result
* @return dn string
**/
- char *ads_get_dn(ADS_STRUCT *ads, LDAPMessage *msg)
+ char *ads_get_dn(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, LDAPMessage *msg)
{
char *utf8_dn, *unix_dn;
size_t converted_size;
return NULL;
}
- if (!pull_utf8_allocate(&unix_dn, utf8_dn, &converted_size)) {
+ if (!pull_utf8_talloc(mem_ctx, &unix_dn, utf8_dn, &converted_size)) {
DEBUG(0,("ads_get_dn: string conversion failure utf8 [%s]\n",
utf8_dn ));
return NULL;
DEBUG(1, ("asprintf failed!\n"));
return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
}
-
+
status = ads_search(ads, res, expr, attrs);
SAFE_FREE(expr);
return status;
{
#define ADS_MODLIST_ALLOC_SIZE 10
LDAPMod **mods;
-
+
if ((mods = TALLOC_ZERO_ARRAY(ctx, LDAPMod *, ADS_MODLIST_ALLOC_SIZE + 1)))
/* -1 is safety to make sure we don't go over the end.
need to reset it to NULL before doing ldap modify */
mods[ADS_MODLIST_ALLOC_SIZE] = (LDAPMod *) -1;
-
+
return (ADS_MODLIST)mods;
}
modlist[curmod+ADS_MODLIST_ALLOC_SIZE] = (LDAPMod *) -1;
*mods = (ADS_MODLIST)modlist;
}
-
+
if (!(modlist[curmod] = TALLOC_ZERO_P(ctx, LDAPMod)))
return ADS_ERROR(LDAP_NO_MEMORY);
modlist[curmod]->mod_type = talloc_strdup(ctx, name);
controls[0] = &PermitModify;
controls[1] = NULL;
- if (!push_utf8_allocate(&utf8_dn, mod_dn, &converted_size)) {
+ if (!push_utf8_talloc(talloc_tos(), &utf8_dn, mod_dn, &converted_size)) {
return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
}
mods[i] = NULL;
ret = ldap_modify_ext_s(ads->ldap.ld, utf8_dn,
(LDAPMod **) mods, controls, NULL);
- SAFE_FREE(utf8_dn);
+ TALLOC_FREE(utf8_dn);
return ADS_ERROR(ret);
}
char *utf8_dn = NULL;
size_t converted_size;
- if (!push_utf8_allocate(&utf8_dn, new_dn, &converted_size)) {
- DEBUG(1, ("ads_gen_add: push_utf8_allocate failed!"));
+ if (!push_utf8_talloc(talloc_tos(), &utf8_dn, new_dn, &converted_size)) {
+ DEBUG(1, ("ads_gen_add: push_utf8_talloc failed!"));
return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
}
-
+
/* find the end of the list, marked by NULL or -1 */
for(i=0;(mods[i]!=0)&&(mods[i]!=(LDAPMod *) -1);i++);
/* make sure the end of the list is NULL */
mods[i] = NULL;
ret = ldap_add_s(ads->ldap.ld, utf8_dn, (LDAPMod**)mods);
- SAFE_FREE(utf8_dn);
+ TALLOC_FREE(utf8_dn);
return ADS_ERROR(ret);
}
int ret;
char *utf8_dn = NULL;
size_t converted_size;
- if (!push_utf8_allocate(&utf8_dn, del_dn, &converted_size)) {
- DEBUG(1, ("ads_del_dn: push_utf8_allocate failed!"));
+ if (!push_utf8_talloc(talloc_tos(), &utf8_dn, del_dn, &converted_size)) {
+ DEBUG(1, ("ads_del_dn: push_utf8_talloc failed!"));
return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
}
-
+
ret = ldap_delete_s(ads->ldap.ld, utf8_dn);
- SAFE_FREE(utf8_dn);
+ TALLOC_FREE(utf8_dn);
return ADS_ERROR(ret);
}
/* samba4 might not yet respond to a wellknownobject-query */
return ret ? ret : SMB_STRDUP("cn=Computers");
}
-
+
if (strequal(org_unit, "Computers")) {
return SMB_STRDUP("cn=Computers");
}
}
/* substitute the bind-path from the well-known-guid-search result */
- wkn_dn = ads_get_dn(ads, res);
+ wkn_dn = ads_get_dn(ads, talloc_tos(), res);
if (!wkn_dn) {
goto out;
}
for (i=1; i < new_ln; i++) {
char *s = NULL;
-
+
if (asprintf(&s, "%s,%s", ret, wkn_dn_exp[i]) == -1) {
SAFE_FREE(ret);
goto out;
out:
SAFE_FREE(base);
ads_msgfree(ads, res);
- ads_memfree(ads, wkn_dn);
+ TALLOC_FREE(wkn_dn);
if (wkn_dn_exp) {
ldap_value_free(wkn_dn_exp);
}
}
/**
- * Determines the computer account's current KVNO via an LDAP lookup
+ * Determines the an account's current KVNO via an LDAP lookup
* @param ads An initialized ADS_STRUCT
- * @param machine_name the NetBIOS name of the computer, which is used to identify the computer account.
- * @return the kvno for the computer account, or -1 in case of a failure.
+ * @param account_name the NT samaccountname.
+ * @return the kvno for the account, or -1 in case of a failure.
**/
-uint32 ads_get_kvno(ADS_STRUCT *ads, const char *machine_name)
+uint32 ads_get_kvno(ADS_STRUCT *ads, const char *account_name)
{
LDAPMessage *res = NULL;
uint32 kvno = (uint32)-1; /* -1 indicates a failure */
char *dn_string = NULL;
ADS_STATUS ret = ADS_ERROR(LDAP_SUCCESS);
- DEBUG(5,("ads_get_kvno: Searching for host %s\n", machine_name));
- if (asprintf(&filter, "(samAccountName=%s$)", machine_name) == -1) {
+ DEBUG(5,("ads_get_kvno: Searching for account %s\n", account_name));
+ if (asprintf(&filter, "(samAccountName=%s)", account_name) == -1) {
return kvno;
}
ret = ads_search(ads, &res, filter, attrs);
SAFE_FREE(filter);
- if (!ADS_ERR_OK(ret) && ads_count_replies(ads, res)) {
- DEBUG(1,("ads_get_kvno: Computer Account For %s not found.\n", machine_name));
+ if (!ADS_ERR_OK(ret) || (ads_count_replies(ads, res) != 1)) {
+ DEBUG(1,("ads_get_kvno: Account for %s not found.\n", account_name));
ads_msgfree(ads, res);
return kvno;
}
- dn_string = ads_get_dn(ads, res);
+ dn_string = ads_get_dn(ads, talloc_tos(), res);
if (!dn_string) {
DEBUG(0,("ads_get_kvno: out of memory.\n"));
ads_msgfree(ads, res);
return kvno;
}
DEBUG(5,("ads_get_kvno: Using: %s\n", dn_string));
- ads_memfree(ads, dn_string);
+ TALLOC_FREE(dn_string);
/* ---------------------------------------------------------
* 0 is returned as a default KVNO from this point on...
return kvno;
}
+/**
+ * Determines the computer account's current KVNO via an LDAP lookup
+ * @param ads An initialized ADS_STRUCT
+ * @param machine_name the NetBIOS name of the computer, which is used to identify the computer account.
+ * @return the kvno for the computer account, or -1 in case of a failure.
+ **/
+
+uint32_t ads_get_machine_kvno(ADS_STRUCT *ads, const char *machine_name)
+{
+ char *computer_account = NULL;
+ uint32_t kvno = -1;
+
+ if (asprintf(&computer_account, "%s$", machine_name) < 0) {
+ return kvno;
+ }
+
+ kvno = ads_get_kvno(ads, computer_account);
+ free(computer_account);
+
+ return kvno;
+}
+
/**
* This clears out all registered spn's for a given hostname
* @param ads An initilaized ADS_STRUCT
talloc_destroy(ctx);
return ret;
}
- dn_string = ads_get_dn(ads, res);
+ dn_string = ads_get_dn(ads, talloc_tos(), res);
if (!dn_string) {
talloc_destroy(ctx);
ads_msgfree(ads, res);
return ADS_ERROR(LDAP_NO_MEMORY);
}
ret = ads_gen_mod(ads, dn_string, mods);
- ads_memfree(ads,dn_string);
+ TALLOC_FREE(dn_string);
if (!ADS_ERR_OK(ret)) {
DEBUG(1,("ads_clear_service_principal_names: Error: Updating Service Principals for machine %s in LDAP\n",
machine_name));
}
/* add short name spn */
-
+
if ( (psp1 = talloc_asprintf(ctx, "%s/%s", spn, machine_name)) == NULL ) {
talloc_destroy(ctx);
ads_msgfree(ads, res);
strupper_m(psp1);
strlower_m(&psp1[strlen(spn)]);
servicePrincipalName[0] = psp1;
-
+
DEBUG(5,("ads_add_service_principal_name: INFO: Adding %s to host %s\n",
psp1, machine_name));
/* add fully qualified spn */
-
+
if ( (psp2 = talloc_asprintf(ctx, "%s/%s", spn, my_fqdn)) == NULL ) {
ret = ADS_ERROR(LDAP_NO_MEMORY);
goto out;
ret = ADS_ERROR(LDAP_NO_MEMORY);
goto out;
}
-
+
ret = ads_add_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
if (!ADS_ERR_OK(ret)) {
DEBUG(1,("ads_add_service_principal_name: Error: Updating Service Principals in LDAP\n"));
goto out;
}
-
- if ( (dn_string = ads_get_dn(ads, res)) == NULL ) {
+
+ if ( (dn_string = ads_get_dn(ads, ctx, res)) == NULL ) {
ret = ADS_ERROR(LDAP_NO_MEMORY);
goto out;
}
-
+
ret = ads_gen_mod(ads, dn_string, mods);
- ads_memfree(ads,dn_string);
if (!ADS_ERR_OK(ret)) {
DEBUG(1,("ads_add_service_principal_name: Error: Updating Service Principals in LDAP\n"));
goto out;
uint32 acct_control = ( UF_WORKSTATION_TRUST_ACCOUNT |\
UF_DONT_EXPIRE_PASSWD |\
UF_ACCOUNTDISABLE );
-
+
if (!(ctx = talloc_init("ads_add_machine_acct")))
return ADS_ERROR(LDAP_NO_MEMORY);
if ( !new_dn || !samAccountName ) {
goto done;
}
-
+
#ifndef ENCTYPE_ARCFOUR_HMAC
acct_control |= UF_USE_DES_KEY_ONLY;
#endif
if (!(mods = ads_init_mods(ctx))) {
goto done;
}
-
+
ads_mod_str(ctx, &mods, "cn", machine_name);
ads_mod_str(ctx, &mods, "sAMAccountName", samAccountName);
ads_mod_strlist(ctx, &mods, "objectClass", objectClass);
SAFE_FREE(machine_escaped);
ads_msgfree(ads, res);
talloc_destroy(ctx);
-
+
return ret;
}
goto done;
}
- computer_dn = ads_get_dn(ads, res);
+ computer_dn = ads_get_dn(ads, talloc_tos(), res);
if (!computer_dn) {
rc = ADS_ERROR(LDAP_NO_MEMORY);
goto done;
done:
ads_msgfree(ads, res);
SAFE_FREE(filter);
- SAFE_FREE(computer_dn);
+ TALLOC_FREE(computer_dn);
SAFE_FREE(computer_rdn);
if (!ADS_ERR_OK(rc)) {
memcpy(guid.info, values[i]->bv_val, sizeof(guid.info));
smb_uuid_unpack(guid, &tmp);
- printf("%s: %s\n", field, smb_uuid_string(talloc_tos(), tmp));
+ printf("%s: %s\n", field, GUID_string(talloc_tos(), &tmp));
}
}
for (i=0; values[i]; i++) {
DOM_SID sid;
fstring tmp;
- sid_parse(values[i]->bv_val, values[i]->bv_len, &sid);
+ if (!sid_parse(values[i]->bv_val, values[i]->bv_len, &sid)) {
+ continue;
+ }
printf("%s: %s\n", field, sid_to_fstring(tmp, &sid));
}
}
msg = ads_next_entry(ads, msg)) {
char *utf8_field;
BerElement *b;
-
+
for (utf8_field=ldap_first_attribute(ads->ldap.ld,
(LDAPMessage *)msg,&b);
utf8_field;
values = ldap_get_values(ads->ldap.ld, msg, field);
if (!values)
return NULL;
-
+
if (values[0] && pull_utf8_talloc(mem_ctx, &ux_string, values[0],
&converted_size))
{
size_t num_new_strings;
unsigned long int range_start;
unsigned long int range_end;
-
+
/* we might have been given the whole lot anyway */
if ((strings = ads_pull_strings(ads, mem_ctx, msg, field, num_strings))) {
*more_strings = False;
*more_strings = False;
return NULL;
}
-
+
if (sscanf(&range_attr[strlen(expected_range_attrib)], "%lu-%lu",
&range_start, &range_end) == 2) {
*more_strings = True;
}
new_strings = ads_pull_strings(ads, mem_ctx, msg, range_attr, &num_new_strings);
-
+
if (*more_strings && ((*num_strings + num_new_strings) != (range_end + 1))) {
DEBUG(1, ("ads_pull_strings_range: Range attribute (%s) tells us we have %lu "
"strings in this bunch, but we only got %lu - aborting range retreival\n",
strings = TALLOC_REALLOC_ARRAY(mem_ctx, current_strings, char *,
*num_strings + num_new_strings);
-
+
if (strings == NULL) {
ldap_memfree(range_attr);
*more_strings = False;
return NULL;
}
-
+
if (new_strings && num_new_strings) {
memcpy(&strings[*num_strings], new_strings,
sizeof(*new_strings) * num_new_strings);
"%s;range=%d-*",
field,
(int)*num_strings);
-
+
if (!*next_attribute) {
DEBUG(1, ("talloc_asprintf for next attribute failed!\n"));
ldap_memfree(range_attr);
values = ldap_get_values(ads->ldap.ld, msg, "objectGUID");
if (!values)
return False;
-
+
if (values[0]) {
memcpy(&flat_guid.info, values[0], sizeof(UUID_FLAT));
smb_uuid_unpack(flat_guid, guid);
bool ads_pull_sid(ADS_STRUCT *ads, LDAPMessage *msg, const char *field,
DOM_SID *sid)
{
- struct berval **values;
- bool ret = False;
-
- values = ldap_get_values_len(ads->ldap.ld, msg, field);
-
- if (!values)
- return False;
-
- if (values[0])
- ret = sid_parse(values[0]->bv_val, values[0]->bv_len, sid);
-
- ldap_value_free_len(values);
- return ret;
+ return smbldap_pull_sid(ads->ldap.ld, msg, field, sid);
}
/**
count++;
}
}
-
+
ldap_value_free_len(values);
return count;
}
ret = false;
}
}
-
+
ldap_value_free_len(values);
return ret;
}
}
/* but save the time and offset in the original ADS_STRUCT */
-
+
ads->config.current_time = ads_parse_time(timestr);
if (ads->config.current_time != 0) {
ADS_STATUS status;
LDAPMessage *res;
ADS_STRUCT *ads_s = ads;
-
+
*val = DS_DOMAIN_FUNCTION_2000;
/* establish a new ldap tcp session if necessary */
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;
/* If the attribute does not exist assume it is a Windows 2000
functional domain */
-
+
status = ads_do_search(ads_s, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
if (!ADS_ERR_OK(status)) {
if ( status.err.rc == LDAP_NO_SUCH_ATTRIBUTE ) {
}
DEBUG(3,("ads_domain_func_level: %d\n", *val));
-
+
ads_msgfree(ads, res);
done:
return ADS_ERROR_SYSTEM(ENOENT);
}
ads_msgfree(ads, res);
-
+
return ADS_SUCCESS;
}
return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
}
- dn = ads_get_dn(ads, res);
+ dn = ads_get_dn(ads, mem_ctx, res);
if (dn == NULL) {
ads_msgfree(ads, res);
return ADS_ERROR(LDAP_NO_MEMORY);
parent = ads_parent_dn(ads_parent_dn(ads_parent_dn(dn)));
if (parent == NULL) {
ads_msgfree(ads, res);
- ads_memfree(ads, dn);
+ TALLOC_FREE(dn);
return ADS_ERROR(LDAP_NO_MEMORY);
}
*site_dn = talloc_strdup(mem_ctx, parent);
if (*site_dn == NULL) {
ads_msgfree(ads, res);
- ads_memfree(ads, dn);
+ TALLOC_FREE(dn);
return ADS_ERROR(LDAP_NO_MEMORY);
}
- ads_memfree(ads, dn);
+ TALLOC_FREE(dn);
ads_msgfree(ads, res);
return status;
char *dn = NULL;
- dn = ads_get_dn(ads, msg);
+ dn = ads_get_dn(ads, talloc_tos(), msg);
if (!dn) {
ads_msgfree(ads, res);
return ADS_ERROR(LDAP_NO_MEMORY);
if (!add_string_to_array(mem_ctx, dn,
(const char ***)ous,
(int *)num_ous)) {
- ads_memfree(ads, dn);
+ TALLOC_FREE(dn);
ads_msgfree(ads, res);
return ADS_ERROR(LDAP_NO_MEMORY);
}
- ads_memfree(ads, dn);
+ TALLOC_FREE(dn);
}
ads_msgfree(ads, res);
/**
* 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;
}
/********************************************************************
ADS_STATUS status;
int count = 0;
char *name = NULL;
-
+
status = ads_find_machine_acct(ads, &res, global_myname());
if (!ADS_ERR_OK(status)) {
DEBUG(0,("ads_get_dnshostname: Failed to find account for %s\n",
global_myname()));
goto out;
}
-
+
if ( (count = ads_count_replies(ads, res)) != 1 ) {
DEBUG(1,("ads_get_dnshostname: %d entries returned!\n", count));
goto out;
}
-
+
if ( (name = ads_pull_string(ads, ctx, res, "dNSHostName")) == NULL ) {
DEBUG(0,("ads_get_dnshostname: No dNSHostName attribute!\n"));
}
out:
ads_msgfree(ads, res);
-
+
return name;
}
ADS_STATUS status;
int count = 0;
char *name = NULL;
-
+
status = ads_find_machine_acct(ads, &res, global_myname());
if (!ADS_ERR_OK(status)) {
DEBUG(0,("ads_get_dnshostname: Failed to find account for %s\n",
global_myname()));
goto out;
}
-
+
if ( (count = ads_count_replies(ads, res)) != 1 ) {
DEBUG(1,("ads_get_dnshostname: %d entries returned!\n", count));
goto out;
}
-
+
if ( (name = ads_pull_string(ads, ctx, res, "sAMAccountName")) == NULL ) {
DEBUG(0,("ads_get_dnshostname: No sAMAccountName attribute!\n"));
}
out:
ads_msgfree(ads, res);
-
+
return name;
}
return ADS_ERROR_SYSTEM(ENOENT);
}
- hostnameDN = ads_get_dn(ads, (LDAPMessage *)msg);
+ hostnameDN = ads_get_dn(ads, talloc_tos(), (LDAPMessage *)msg);
rc = ldap_delete_ext_s(ads->ldap.ld, hostnameDN, pldap_control, NULL);
if (rc) {
if (!ADS_ERR_OK(status)) {
SAFE_FREE(host);
- ads_memfree(ads, hostnameDN);
+ TALLOC_FREE(hostnameDN);
return status;
}
char *dn = NULL;
- if ((dn = ads_get_dn(ads, msg_sub)) == NULL) {
+ if ((dn = ads_get_dn(ads, talloc_tos(), msg_sub)) == NULL) {
SAFE_FREE(host);
- ads_memfree(ads, hostnameDN);
+ TALLOC_FREE(hostnameDN);
return ADS_ERROR(LDAP_NO_MEMORY);
}
if (!ADS_ERR_OK(status)) {
DEBUG(3,("failed to delete dn %s: %s\n", dn, ads_errstr(status)));
SAFE_FREE(host);
- ads_memfree(ads, dn);
- ads_memfree(ads, hostnameDN);
+ TALLOC_FREE(dn);
+ TALLOC_FREE(hostnameDN);
return status;
}
- ads_memfree(ads, dn);
+ TALLOC_FREE(dn);
}
/* there should be no subordinate objects anymore */
if (!ADS_ERR_OK(status) || ( (ads_count_replies(ads, res)) > 0 ) ) {
SAFE_FREE(host);
- ads_memfree(ads, hostnameDN);
+ TALLOC_FREE(hostnameDN);
return status;
}
if (!ADS_ERR_OK(status)) {
SAFE_FREE(host);
DEBUG(3,("failed to delete dn %s: %s\n", hostnameDN, ads_errstr(status)));
- ads_memfree(ads, hostnameDN);
+ TALLOC_FREE(hostnameDN);
return status;
}
}
- ads_memfree(ads, hostnameDN);
+ TALLOC_FREE(hostnameDN);
status = ads_find_machine_acct(ads, &res, host);
if (ADS_ERR_OK(status) && ads_count_replies(ads, res) == 1) {
status = ads_do_search_all(ads, ads->config.bind_path,
LDAP_SCOPE_SUBTREE,
filter, attrs, &res);
-
+
if (!ADS_ERR_OK(status)) {
goto out;
}
goto out;
}
- dn = ads_get_dn(ads, res);
+ dn = ads_get_dn(ads, talloc_tos(), res);
if (dn == NULL) {
status = ADS_ERROR(LDAP_NO_MEMORY);
goto out;
}
}
out:
- ads_memfree(ads, dn);
+ TALLOC_FREE(dn);
ads_msgfree(ads, res);
return status;
}
expr = talloc_asprintf(mem_ctx, "(rightsGuid=%s)",
- smb_uuid_string(mem_ctx, *rights_guid));
+ GUID_string(mem_ctx, rights_guid));
if (!expr) {
goto done;
}
done:
ads_msgfree(ads, res);
return result;
-
}
/**
ADS_STRUCT *ads,
const char **account_ou)
{
- struct ldb_dn *name_dn = NULL;
- const char *name = NULL;
- char *ou_string = NULL;
+ char **exploded_dn;
+ const char *name;
+ char *ou_string;
- name_dn = ldb_dn_explode(mem_ctx, *account_ou);
- if (name_dn) {
+ exploded_dn = ldap_explode_dn(*account_ou, 0);
+ if (exploded_dn) {
+ ldap_value_free(exploded_dn);
return ADS_SUCCESS;
}
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) {
+ exploded_dn = ldap_explode_dn(name, 0);
+ if (!exploded_dn) {
return ADS_ERROR_LDAP(LDAP_INVALID_DN_SYNTAX);
}
+ ldap_value_free(exploded_dn);
- *account_ou = talloc_strdup(mem_ctx, name);
- if (!*account_ou) {
- return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
- }
-
+ *account_ou = name;
return ADS_SUCCESS;
}