summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/ldap_server/ldap_rootdse.c235
-rw-r--r--source4/ldap_server/rootdse.ldif62
-rwxr-xr-xsource4/script/rootdse.pl151
3 files changed, 407 insertions, 41 deletions
diff --git a/source4/ldap_server/ldap_rootdse.c b/source4/ldap_server/ldap_rootdse.c
index 665bcde9af..b936c92da3 100644
--- a/source4/ldap_server/ldap_rootdse.c
+++ b/source4/ldap_server/ldap_rootdse.c
@@ -20,52 +20,121 @@
#include "includes.h"
-#define ATTR_BLOB_CONST(val) data_blob_talloc(attrs, val, sizeof(val)-1)
-#define ATTR_SINGLE_NOVAL(attr, blob, num, nam) do { \
- attr.name = talloc_strdup(attrs, nam);\
- if (!attr.name) {\
+#define ATTR_BLOB_CONST(val) data_blob_talloc(mem_ctx, val, sizeof(val)-1)
+#define ATTR_SINGLE_NOVAL(ctx, attr, blob, num, nam) do { \
+ attr->name = talloc_strdup(ctx, nam);\
+ if (!attr->name) {\
+ return NT_STATUS_NO_MEMORY;\
+ }\
+ attr->num_values = num; \
+ attr->values = blob;\
+} while(0)
+#define ALLOC_CHECK(ptr) do {\
+ if (!(ptr)) {\
return NT_STATUS_NO_MEMORY;\
}\
- attr.num_values = num; \
- attr.values = blob;\
} while(0)
-static NTSTATUS rootdse_Search(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
- struct ldap_SearchRequest *r)
+
+struct rootdse_db_context {
+ struct ldb_context *ldb;
+ struct rootdse_db_context **static_ptr;
+};
+
+/*
+ this is used to catch debug messages from ldb
+*/
+void rootdse_db_debug(void *context, enum ldb_debug_level level, const char *fmt, va_list ap) _PRINTF_ATTRIBUTE(3,0)
{
- struct ldap_SearchResEntry *ent;
- struct ldap_Result *done;
- int code = 0;
- struct ldapsrv_reply *ent_r, *done_r;
- int num_attrs = 3;
- struct ldap_attribute *attrs;
+ char *s = NULL;
+ if (DEBUGLEVEL < 4 && level > LDB_DEBUG_WARNING) {
+ return;
+ }
+ vasprintf(&s, fmt, ap);
+ if (!s) return;
+ DEBUG(level, ("rootdse: %s\n", s));
+ free(s);
+}
- DEBUG(10, ("Root DSE: %s\n", r->filter));
- if (r->scope != LDAP_SEARCH_SCOPE_BASE) {
- code = 32; /* nosuchobject */
- goto no_base_scope;
+/* destroy the last connection to the sam */
+static int rootdse_db_destructor(void *ctx)
+{
+ struct rootdse_db_context *rd_ctx = ctx;
+ ldb_close(rd_ctx->ldb);
+ *(rd_ctx->static_ptr) = NULL;
+ return 0;
+}
+
+/*
+ connect to the SAM database
+ return an opaque context pointer on success, or NULL on failure
+ */
+void *rootdse_db_connect(TALLOC_CTX *mem_ctx)
+{
+ static struct rootdse_db_context *ctx;
+ char *db_path;
+ /*
+ the way that unix fcntl locking works forces us to have a
+ static ldb handle here rather than a much more sensible
+ approach of having the ldb handle as part of the
+ ldap base structures. Otherwise we would try to open
+ the ldb more than once, and tdb would rightly refuse the
+ second open due to the broken nature of unix locking.
+ */
+ if (ctx != NULL) {
+ return talloc_reference(mem_ctx, ctx);
}
- attrs = talloc_array_p(call, struct ldap_attribute, num_attrs);
- if (!attrs) {
- return NT_STATUS_NO_MEMORY;
+ ctx = talloc_p(mem_ctx, struct rootdse_db_context);
+ if (ctx == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ ctx->static_ptr = &ctx;
+
+ db_path = talloc_asprintf(ctx, "tdb://%s/rootdse.ldb", dyn_PRIVATE_DIR);
+ if (db_path == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ DEBUG(10, ("opening %s", db_path));
+ ctx->ldb = ldb_connect(db_path, 0, NULL);
+ if (ctx->ldb == NULL) {
+ talloc_free(ctx);
+ return NULL;
}
+ talloc_set_destructor(ctx, rootdse_db_destructor);
+ ldb_set_debug(ctx->ldb, rootdse_db_debug, NULL);
+
+ return ctx;
+}
+
+
+static NTSTATUS fill_dynamic_values(void *mem_ctx, struct ldap_attribute *attrs)
+{
/*
* currentTime
* 20040918090350.0Z
*/
+
+ DEBUG(10, ("fill_dynamic_values for %s\n", attrs[0].name));
+
+ if (strcasecmp(attrs->name, "currentTime") == 0)
{
int num_currentTime = 1;
- DATA_BLOB *currentTime = talloc_array_p(attrs, DATA_BLOB, num_currentTime);
- char *str = ldap_timestring(call, time(NULL));
+ DATA_BLOB *currentTime = talloc_array_p(mem_ctx, DATA_BLOB, num_currentTime);
+ char *str = ldap_timestring(mem_ctx, time(NULL));
if (!str) {
return NT_STATUS_NO_MEMORY;
}
currentTime[0].data = str;
currentTime[0].length = strlen(str);
- ATTR_SINGLE_NOVAL(attrs[0], currentTime, num_currentTime, "currentTime");
+ ATTR_SINGLE_NOVAL(mem_ctx, attrs, currentTime, num_currentTime, "currentTime");
+ return NT_STATUS_OK;
}
/*
@@ -137,11 +206,13 @@ static NTSTATUS rootdse_Search(struct ldapsrv_partition *partition, struct ldaps
* 3
* 2
*/
+ if (strcasecmp(attrs->name, "supportedLDAPVersion") == 0)
{
int num_supportedLDAPVersion = 1;
- DATA_BLOB *supportedLDAPVersion = talloc_array_p(attrs, DATA_BLOB, num_supportedLDAPVersion);
+ DATA_BLOB *supportedLDAPVersion = talloc_array_p(mem_ctx, DATA_BLOB, num_supportedLDAPVersion);
supportedLDAPVersion[0] = ATTR_BLOB_CONST("3");
- ATTR_SINGLE_NOVAL(attrs[1], supportedLDAPVersion, num_supportedLDAPVersion, "supportedLDAPVersion");
+ ATTR_SINGLE_NOVAL(mem_ctx, attrs, supportedLDAPVersion, num_supportedLDAPVersion, "supportedLDAPVersion");
+ return NT_STATUS_OK;
}
/*
@@ -177,12 +248,6 @@ static NTSTATUS rootdse_Search(struct ldapsrv_partition *partition, struct ldaps
* dnsHostName
* netbiosname.dom.tld
*/
- {
- int num_dnsHostName = 1;
- DATA_BLOB *dnsHostName = talloc_array_p(attrs, DATA_BLOB, num_dnsHostName);
- dnsHostName[0] = data_blob_talloc(attrs, lp_netbios_name(),strlen(lp_netbios_name()));
- ATTR_SINGLE_NOVAL(attrs[2], dnsHostName, num_dnsHostName, "dnsHostName");
- }
/*
* ldapServiceName
@@ -226,18 +291,89 @@ static NTSTATUS rootdse_Search(struct ldapsrv_partition *partition, struct ldaps
* 2
*/
+def:
+ {
+ DATA_BLOB *x = talloc_array_p(mem_ctx, DATA_BLOB, 1);
+ x[0] = ATTR_BLOB_CONST("0");
+ ATTR_SINGLE_NOVAL(mem_ctx, attrs, x, 1, attrs->name);
+ }
+ return NT_STATUS_OK;
+}
- ent_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultEntry);
- if (!ent_r) {
- return NT_STATUS_NO_MEMORY;
+static NTSTATUS rootdse_Search(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
+ struct ldap_SearchRequest *r)
+{
+ NTSTATUS status;
+ void *local_ctx;
+ struct ldap_SearchResEntry *ent;
+ struct ldap_Result *done;
+ struct ldb_message **res;
+ int result = 0;
+ struct ldapsrv_reply *ent_r, *done_r;
+ struct rootdse_db_context *rootdsedb;
+ const char *errstr = NULL;
+ int count, i, j, y;
+
+ if (r->scope != LDAP_SEARCH_SCOPE_BASE) {
+ count = -1;
+ goto no_base_scope;
+ }
+
+ local_ctx = talloc_named(call, 0, "rootdse_Search local memory context");
+ ALLOC_CHECK(local_ctx);
+
+ rootdsedb = rootdse_db_connect(local_ctx);
+ ALLOC_CHECK(rootdsedb);
+
+ ldb_set_alloc(rootdsedb->ldb, talloc_realloc_fn, rootdsedb);
+ count = ldb_search(rootdsedb->ldb, "", 0, "dn=rootDSE", NULL, &res);
+
+ for (i = 0; i < count; i++) {
+ ent_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultEntry);
+ if (!ent_r) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ent = &ent_r->msg.r.SearchResultEntry;
+ ent->dn = "";
+ ent->num_attributes = 0;
+ ent->attributes = NULL;
+ if (res[i]->num_elements == 0) {
+ goto queue_reply;
+ }
+ ent->num_attributes = res[i]->num_elements;
+ ent->attributes = talloc_array_p(ent_r, struct ldap_attribute, ent->num_attributes);
+ ALLOC_CHECK(ent->attributes);
+ for (j=0; j < ent->num_attributes; j++) {
+ ent->attributes[j].name = talloc_steal(ent->attributes, res[i]->elements[j].name);
+ ent->attributes[j].num_values = 0;
+ ent->attributes[j].values = NULL;
+ ent->attributes[j].num_values = res[i]->elements[j].num_values;
+ if (ent->attributes[j].num_values == 1 &&
+ strncmp(res[i]->elements[j].values[0].data, "_DYNAMIC_", 9) == 0) {
+ fill_dynamic_values(ent->attributes, &(ent->attributes[j]));
+ if (ent->attributes[j].values[0].data == NULL) {
+ DEBUG (10, ("ARRGHH!\n"));
+ }
+ } else {
+ ent->attributes[j].values = talloc_array_p(ent->attributes,
+ DATA_BLOB, ent->attributes[j].num_values);
+ ALLOC_CHECK(ent->attributes[j].values);
+ for (y=0; y < ent->attributes[j].num_values; y++) {
+ ent->attributes[j].values[y].length = res[i]->elements[j].values[y].length;
+ ent->attributes[j].values[y].data = talloc_steal(ent->attributes[j].values,
+ res[i]->elements[j].values[y].data);
+ }
+ }
+ }
+queue_reply:
+ status = ldapsrv_queue_reply(call, ent_r);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
}
- ent = &ent_r->msg.r.SearchResultEntry;
- ent->dn = "";
- ent->num_attributes = num_attrs;
- ent->attributes = attrs;
- ldapsrv_queue_reply(call, ent_r);
no_base_scope:
@@ -246,12 +382,29 @@ no_base_scope:
return NT_STATUS_NO_MEMORY;
}
+ if (count > 0) {
+ DEBUG(10,("rootdse_Search: results: [%d]\n",count));
+ result = 0;
+ errstr = NULL;
+ } else if (count == 0) {
+ DEBUG(10,("rootdse_Search: no results\n"));
+ result = 32; /* nosuchobject */
+ errstr = talloc_strdup(done_r, ldb_errstring(rootdsedb->ldb));
+ } else if (count == -1) {
+ DEBUG(10,("rootdse_Search: error\n"));
+ result = 1;
+ errstr = talloc_strdup(done_r, ldb_errstring(rootdsedb->ldb));
+ }
+
+
done = &done_r->msg.r.SearchResultDone;
- done->resultcode = code;
+ done->resultcode = result;
done->dn = NULL;
done->errormessage = NULL;
done->referral = NULL;
+ talloc_free(local_ctx);
+
return ldapsrv_queue_reply(call, done_r);
}
diff --git a/source4/ldap_server/rootdse.ldif b/source4/ldap_server/rootdse.ldif
new file mode 100644
index 0000000000..f129492732
--- /dev/null
+++ b/source4/ldap_server/rootdse.ldif
@@ -0,0 +1,62 @@
+dn: rootDSE
+currentTime: _DYNAMIC_
+subschemaSubentry: CN=Aggregate,CN=Schema,CN=Configuration,${BASEDN}
+dsServiceName: CN=NTDS Settings,CN=${NETBIOSNAME},CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,${BASEDN}
+namingContexts: ${BASEDN}
+namingContexts: CN=Configuration,${BASEDN}
+namingContexts: CN=Schema,CN=Configuration,${BASEDN}
+namingContexts: DC=DomainDnsZones,${BASEDN}
+namingContexts: DC=ForestDnsZones,${BASEDN}
+defaultNamingContext: ${BASEDN}
+rootDomainNamingContext: ${BASEDN}
+configurationNamingContext: CN=Configuration,${BASEDN}
+schemaNamingContext: CN=Schema,CN=Configuration,${BASEDN}
+supportedControl: 1.2.840.113556.1.4.319
+supportedControl: 1.2.840.113556.1.4.801
+supportedControl: 1.2.840.113556.1.4.473
+supportedControl: 1.2.840.113556.1.4.528
+supportedControl: 1.2.840.113556.1.4.417
+supportedControl: 1.2.840.113556.1.4.619
+supportedControl: 1.2.840.113556.1.4.841
+supportedControl: 1.2.840.113556.1.4.529
+supportedControl: 1.2.840.113556.1.4.805
+supportedControl: 1.2.840.113556.1.4.521
+supportedControl: 1.2.840.113556.1.4.970
+supportedControl: 1.2.840.113556.1.4.1338
+supportedControl: 1.2.840.113556.1.4.474
+supportedControl: 1.2.840.113556.1.4.1339
+supportedControl: 1.2.840.113556.1.4.1340
+supportedControl: 1.2.840.113556.1.4.1413
+supportedControl: 2.16.840.1.113730.3.4.9
+supportedControl: 2.16.840.1.113730.3.4.10
+supportedControl: 1.2.840.113556.1.4.1504
+supportedControl: 1.2.840.113556.1.4.1852
+supportedControl: 1.2.840.113556.1.4.802
+supportedLDAPVersion: 3
+supportedLDAPPolicies: MaxPoolThreads
+supportedLDAPPolicies: MaxDatagramRecv
+supportedLDAPPolicies: MaxReceiveBuffer
+supportedLDAPPolicies: InitRecvTimeout
+supportedLDAPPolicies: MaxConnections
+supportedLDAPPolicies: MaxConnIdleTime
+supportedLDAPPolicies: MaxPageSize
+supportedLDAPPolicies: MaxQueryDuration
+supportedLDAPPolicies: MaxTempTableSize
+supportedLDAPPolicies: MaxResultSetSize
+supportedLDAPPolicies: MaxNotificationPerConn
+supportedLDAPPolicies: MaxValRange
+highestCommittedUSN: _DYNAMIC_
+supportedSASLMechanisms: GSSAPI
+supportedSASLMechanisms: GSS-SPNEGO
+supportedSASLMechanisms: EXTERNAL
+supportedSASLMechanisms: DIGEST-MD5
+dnsHostName: ${NETBIOSNAME}.${DNSDOMAIN}
+ldapServiceName: ${DNSDOMAIN}:${NETBIOSNAME}$@${DNSDOMAIN}
+serverName: CN=${NETBIOSNAME},CN=Servers,CN=Default-First-Site,CN=Sites,CN=Configuration,${BASEDN}
+supportedCapabilities: 1.2.840.113556.1.4.800
+supportedCapabilities: 1.2.840.113556.1.4.1670
+supportedCapabilities: 1.2.840.113556.1.4.1791
+isSynchronized: _DYNAMIC_
+domainFunctionality: 0
+forestFunctionality: 0
+domainControllerFunctionality: 2
diff --git a/source4/script/rootdse.pl b/source4/script/rootdse.pl
new file mode 100755
index 0000000000..5e620a0991
--- /dev/null
+++ b/source4/script/rootdse.pl
@@ -0,0 +1,151 @@
+#!/usr/bin/perl -w
+
+use strict;
+use Getopt::Long;
+
+my $opt_hostname = `hostname`;
+chomp $opt_hostname;
+my $opt_realm;
+my $opt_domain;
+my $opt_netbiosname;
+my $dnsdomain;
+my $dnsname;
+my $basedn;
+
+sub ldaptime()
+{
+ my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = gmtime(time);
+ return sprintf "%04u%02u%02u%02u%02u%02u.0Z",
+ $year+1900, $mon+1, $mday, $hour, $min, $sec;
+}
+
+#######################
+# substitute a single variable
+sub substitute($)
+{
+ my $var = shift;
+
+ if ($var eq "BASEDN") {
+ return $basedn;
+ }
+
+ if ($var eq "NETBIOSNAME") {
+ return $opt_netbiosname;
+ }
+
+ if ($var eq "DNSDOMAIN") {
+ return $dnsdomain;
+ }
+
+ die "ERROR: Uknown substitution variable $var\n";
+}
+
+#####################################################################
+# write a string into a file
+sub FileSave($$)
+{
+ my($filename) = shift;
+ my($v) = shift;
+ local(*FILE);
+ open(FILE, ">$filename") || die "can't open $filename";
+ print FILE $v;
+ close(FILE);
+}
+
+#####################################################################
+# read a file into a string
+sub FileLoad($)
+{
+ my($filename) = shift;
+ local(*INPUTFILE);
+ open(INPUTFILE, $filename) || return undef;
+ my($saved_delim) = $/;
+ undef $/;
+ my($data) = <INPUTFILE>;
+ close(INPUTFILE);
+ $/ = $saved_delim;
+ return $data;
+}
+
+############################################
+# show some help
+sub ShowHelp()
+{
+ print "
+Samba4 provisioning
+
+rootdse.pl [options]
+ --realm REALM set realm
+ --domain DOMAIN set domain
+ --hostname HOSTNAME set hostname
+ --netbiosname NETBIOSNAME choose admin password (otherwise random)
+
+You must provide at least a realm and domain
+
+";
+ exit(1);
+}
+
+my $opt_help;
+
+GetOptions(
+ 'help|h|?' => \$opt_help,
+ 'realm=s' => \$opt_realm,
+ 'domain=s' => \$opt_domain,
+ 'hostname=s' => \$opt_hostname,
+ 'netbiosname=s' => \$opt_netbiosname,
+ );
+
+if ($opt_help ||
+ !$opt_realm ||
+ !$opt_domain ||
+ !$opt_hostname ||
+ !$opt_netbiosname) {
+ ShowHelp();
+}
+
+$opt_realm=uc($opt_realm);
+$opt_domain=uc($opt_domain);
+$opt_hostname=uc($opt_hostname);
+$opt_netbiosname=uc($opt_netbiosname);
+
+print "Provisioning host '$opt_hostname' with netbios name '$opt_netbiosname' for domain '$opt_domain' in realm '$opt_realm'\n";
+
+print "generating ldif ...\n";
+
+$dnsdomain = lc($opt_realm);
+$dnsname = lc($opt_hostname).".".$dnsdomain;
+$basedn = "DC=" . join(",DC=", split(/\./, $opt_realm));
+
+my $data = FileLoad("rootdse.ldif") || die "Unable to load rootdse.ldif\n";
+
+my $res = "";
+
+print "applying substitutions ...\n";
+
+while ($data =~ /(.*?)\$\{(\w*)\}(.*)/s) {
+ my $sub = substitute($2);
+ $res .= "$1$sub";
+ $data = $3;
+}
+$res .= $data;
+
+print "saving ldif to newrootdse.ldif ...\n";
+
+FileSave("newrootdse.ldif", $res);
+
+unlink("newrootdse.ldb");
+
+print "creating newrootdse.ldb ...\n";
+
+# allow provisioning to be run from the source directory
+$ENV{"PATH"} .= ":bin";
+
+system("ldbadd -H newrootdse.ldb newroodse.ldif");
+
+print "done
+
+Please move newrootdse.ldb to rootdse.ldb in the lib/private/ directory of your
+Samba4 installation
+";
+