2 Unix SMB/CIFS implementation.
4 Copyright (C) Stefan Metzmacher 2004
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "system/time.h"
24 #define ATTR_BLOB_CONST(val) data_blob_talloc(mem_ctx, val, sizeof(val)-1)
25 #define ATTR_SINGLE_NOVAL(ctx, attr, blob, num, nam) do { \
26 attr->name = talloc_strdup(ctx, nam);\
28 return NT_STATUS_NO_MEMORY;\
30 attr->num_values = num; \
33 #define ALLOC_CHECK(ptr) do {\
35 return NT_STATUS_NO_MEMORY;\
40 struct rootdse_db_context {
41 struct ldb_context *ldb;
42 struct rootdse_db_context **static_ptr;
46 this is used to catch debug messages from ldb
48 void rootdse_db_debug(void *context, enum ldb_debug_level level, const char *fmt, va_list ap) _PRINTF_ATTRIBUTE(3,0)
51 if (DEBUGLEVEL < 4 && level > LDB_DEBUG_WARNING) {
54 vasprintf(&s, fmt, ap);
56 DEBUG(level, ("rootdse: %s\n", s));
61 /* destroy the last connection to the sam */
62 static int rootdse_db_destructor(void *ctx)
64 struct rootdse_db_context *rd_ctx = ctx;
65 ldb_close(rd_ctx->ldb);
66 *(rd_ctx->static_ptr) = NULL;
71 connect to the SAM database
72 return an opaque context pointer on success, or NULL on failure
74 void *rootdse_db_connect(TALLOC_CTX *mem_ctx)
76 static struct rootdse_db_context *ctx;
79 the way that unix fcntl locking works forces us to have a
80 static ldb handle here rather than a much more sensible
81 approach of having the ldb handle as part of the
82 ldap base structures. Otherwise we would try to open
83 the ldb more than once, and tdb would rightly refuse the
84 second open due to the broken nature of unix locking.
87 return talloc_reference(mem_ctx, ctx);
90 ctx = talloc_p(mem_ctx, struct rootdse_db_context);
96 ctx->static_ptr = &ctx;
98 db_path = talloc_asprintf(ctx, "tdb://%s/rootdse.ldb", dyn_PRIVATE_DIR);
99 if (db_path == NULL) {
104 DEBUG(10, ("opening %s\n", db_path));
105 ctx->ldb = ldb_connect(db_path, 0, NULL);
106 if (ctx->ldb == NULL) {
111 talloc_set_destructor(ctx, rootdse_db_destructor);
112 ldb_set_debug(ctx->ldb, rootdse_db_debug, NULL);
118 static NTSTATUS fill_dynamic_values(void *mem_ctx, struct ldap_attribute *attrs)
125 DEBUG(10, ("fill_dynamic_values for %s\n", attrs[0].name));
127 if (strcasecmp(attrs->name, "currentTime") == 0)
129 int num_currentTime = 1;
130 DATA_BLOB *currentTime = talloc_array_p(mem_ctx, DATA_BLOB, num_currentTime);
131 char *str = ldap_timestring(mem_ctx, time(NULL));
133 currentTime[0].data = str;
134 currentTime[0].length = strlen(str);
135 ATTR_SINGLE_NOVAL(mem_ctx, attrs, currentTime, num_currentTime, "currentTime");
141 * CN=Aggregate,CN=Schema,CN=Configuration,DC=DOM,DC=TLD
146 * CN=NTDS Settings,CN=NETBIOSNAME,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=DOM,DC=TLD
152 * CN=Configuration,DC=DOM,DC=TLD
153 * CN=Schema,CN=Configuration,DC=DOM,DC=TLD
154 * DC=DomainDnsZones,DC=DOM,DC=TLD
155 * DC=ForestDnsZones,DC=DOM,DC=TLD
159 * defaultNamingContext
164 * schemaNamingContext
165 * CN=Schema,CN=Configuration,DC=DOM,DC=TLD
169 * configurationNamingContext
170 * CN=Configuration,DC=DOM,DC=TLD
174 * rootDomainNamingContext
180 * 1.2.840.113556.1.4.319
181 * 1.2.840.113556.1.4.801
182 * 1.2.840.113556.1.4.473
183 * 1.2.840.113556.1.4.528
184 * 1.2.840.113556.1.4.417
185 * 1.2.840.113556.1.4.619
186 * 1.2.840.113556.1.4.841
187 * 1.2.840.113556.1.4.529
188 * 1.2.840.113556.1.4.805
189 * 1.2.840.113556.1.4.521
190 * 1.2.840.113556.1.4.970
191 * 1.2.840.113556.1.4.1338
192 * 1.2.840.113556.1.4.474
193 * 1.2.840.113556.1.4.1339
194 * 1.2.840.113556.1.4.1340
195 * 1.2.840.113556.1.4.1413
196 * 2.16.840.1.113730.3.4.9
197 * 2.16.840.1.113730.3.4.10
198 * 1.2.840.113556.1.4.1504
199 * 1.2.840.113556.1.4.1852
200 * 1.2.840.113556.1.4.802
204 * supportedLDAPVersion
208 if (strcasecmp(attrs->name, "supportedLDAPVersion") == 0)
210 int num_supportedLDAPVersion = 1;
211 DATA_BLOB *supportedLDAPVersion = talloc_array_p(mem_ctx, DATA_BLOB, num_supportedLDAPVersion);
212 supportedLDAPVersion[0] = ATTR_BLOB_CONST("3");
213 ATTR_SINGLE_NOVAL(mem_ctx, attrs, supportedLDAPVersion, num_supportedLDAPVersion, "supportedLDAPVersion");
218 * supportedLDAPPolicies
229 * MaxNotificationPerConn
234 * highestCommittedUSN
239 * supportedSASLMechanisms
248 * netbiosname.dom.tld
253 * dom.tld:netbiosname$@DOM.TLD
258 * CN=NETBIOSNAME,CN=Servers,CN=Default-First-Site,CN=Sites,CN=Configuration,DC=DOM,DC=TLD
262 * supportedCapabilities
263 * 1.2.840.113556.1.4.800
264 * 1.2.840.113556.1.4.1670
265 * 1.2.840.113556.1.4.1791
274 * isGlobalCatalogReady
279 * domainFunctionality
284 * forestFunctionality
289 * domainControllerFunctionality
294 DATA_BLOB *x = talloc_array_p(mem_ctx, DATA_BLOB, 1);
295 x[0] = ATTR_BLOB_CONST("0");
296 ATTR_SINGLE_NOVAL(mem_ctx, attrs, x, 1, attrs->name);
301 static NTSTATUS rootdse_Search(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
302 struct ldap_SearchRequest *r)
306 struct ldap_SearchResEntry *ent;
307 struct ldap_Result *done;
308 struct ldb_message **res;
309 int result = LDAP_SUCCESS;
310 struct ldapsrv_reply *ent_r, *done_r;
311 struct rootdse_db_context *rootdsedb;
312 const char *errstr = NULL;
314 const char **attrs = NULL;
316 if (r->scope != LDAP_SEARCH_SCOPE_BASE) {
317 return NT_STATUS_INVALID_PARAMETER;
320 local_ctx = talloc_named(call, 0, "rootdse_Search local memory context");
321 ALLOC_CHECK(local_ctx);
323 rootdsedb = rootdse_db_connect(local_ctx);
324 ALLOC_CHECK(rootdsedb);
326 if (r->num_attributes >= 1) {
327 attrs = talloc_array_p(rootdsedb, const char *, r->num_attributes+1);
330 for (j=0; j < r->num_attributes; j++) {
331 DEBUG(10,("rootDSE_Search: attrs: [%s]\n",r->attributes[j]));
332 attrs[j] = r->attributes[j];
337 ldb_set_alloc(rootdsedb->ldb, talloc_realloc_fn, rootdsedb);
338 count = ldb_search(rootdsedb->ldb, "", 0, "dn=cn=rootDSE", attrs, &res);
341 ent_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultEntry);
344 ent = &ent_r->msg.r.SearchResultEntry;
346 ent->num_attributes = 0;
347 ent->attributes = NULL;
348 if (res[0]->num_elements == 0) {
351 ent->num_attributes = res[0]->num_elements;
352 ent->attributes = talloc_array_p(ent_r, struct ldap_attribute, ent->num_attributes);
353 ALLOC_CHECK(ent->attributes);
354 for (j=0; j < ent->num_attributes; j++) {
355 ent->attributes[j].name = talloc_steal(ent->attributes, res[0]->elements[j].name);
356 ent->attributes[j].num_values = 0;
357 ent->attributes[j].values = NULL;
358 ent->attributes[j].num_values = res[0]->elements[j].num_values;
359 if (ent->attributes[j].num_values == 1 &&
360 strncmp(res[0]->elements[j].values[0].data, "_DYNAMIC_", 9) == 0) {
361 status = fill_dynamic_values(ent->attributes, &(ent->attributes[j]));
362 if (!NT_STATUS_IS_OK(status)) {
366 ent->attributes[j].values = talloc_array_p(ent->attributes,
367 DATA_BLOB, ent->attributes[j].num_values);
368 ALLOC_CHECK(ent->attributes[j].values);
369 for (y=0; y < ent->attributes[j].num_values; y++) {
370 ent->attributes[j].values[y].length = res[0]->elements[j].values[y].length;
371 ent->attributes[j].values[y].data = talloc_steal(ent->attributes[j].values,
372 res[0]->elements[j].values[y].data);
377 status = ldapsrv_queue_reply(call, ent_r);
378 if (!NT_STATUS_IS_OK(status)) {
383 done_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultDone);
387 DEBUG(10,("rootdse_Search: results: [%d]\n",count));
388 result = LDAP_SUCCESS;
390 } else if (count == 0) {
391 DEBUG(10,("rootdse_Search: no results\n"));
392 result = LDAP_NO_SUCH_OBJECT;
393 errstr = ldb_errstring(rootdsedb->ldb);
394 } else if (count > 1) {
395 DEBUG(10,("rootdse_Search: too many results[%d]\n", count));
397 errstr = "internal error";
398 } else if (count == -1) {
399 DEBUG(10,("rootdse_Search: error\n"));
401 errstr = ldb_errstring(rootdsedb->ldb);
404 done = &done_r->msg.r.SearchResultDone;
406 done->resultcode = result;
407 done->errormessage = (errstr?talloc_strdup(done_r,errstr):NULL);;
408 done->referral = NULL;
410 talloc_free(local_ctx);
412 return ldapsrv_queue_reply(call, done_r);
415 static const struct ldapsrv_partition_ops rootdse_ops = {
416 .Search = rootdse_Search
419 const struct ldapsrv_partition_ops *ldapsrv_get_rootdse_partition_ops(void)