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 "dynconfig.h"
23 #include "ldap_server/ldap_server.h"
24 #include "system/time.h"
25 #include "lib/ldb/include/ldb.h"
27 #define ATTR_BLOB_CONST(val) data_blob_talloc(mem_ctx, val, sizeof(val)-1)
29 #define ATTR_SINGLE_NOVAL(ctx, attr, blob, num, nam) do { \
30 attr->name = talloc_strdup(ctx, nam);\
31 NT_STATUS_HAVE_NO_MEMORY(attr->name);\
32 attr->num_values = num; \
36 struct rootdse_db_context {
37 struct ldb_context *ldb;
38 struct rootdse_db_context **static_ptr;
42 this is used to catch debug messages from ldb
44 static void rootdse_db_debug(void *context, enum ldb_debug_level level, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
45 static void rootdse_db_debug(void *context, enum ldb_debug_level level, const char *fmt, va_list ap)
48 if (DEBUGLEVEL < 4 && level > LDB_DEBUG_WARNING) {
51 vasprintf(&s, fmt, ap);
53 DEBUG(level, ("rootdse: %s\n", s));
58 /* destroy the last connection to the sam */
59 static int rootdse_db_destructor(void *ctx)
61 struct rootdse_db_context *rd_ctx = ctx;
62 ldb_close(rd_ctx->ldb);
63 *(rd_ctx->static_ptr) = NULL;
68 connect to the SAM database
69 return an opaque context pointer on success, or NULL on failure
71 static void *rootdse_db_connect(TALLOC_CTX *mem_ctx)
73 static struct rootdse_db_context *ctx;
76 the way that unix fcntl locking works forces us to have a
77 static ldb handle here rather than a much more sensible
78 approach of having the ldb handle as part of the
79 ldap base structures. Otherwise we would try to open
80 the ldb more than once, and tdb would rightly refuse the
81 second open due to the broken nature of unix locking.
84 return talloc_reference(mem_ctx, ctx);
87 ctx = talloc_p(mem_ctx, struct rootdse_db_context);
93 ctx->static_ptr = &ctx;
95 db_path = talloc_asprintf(ctx, "tdb://%s/rootdse.ldb", dyn_PRIVATE_DIR);
96 if (db_path == NULL) {
101 DEBUG(10, ("opening %s\n", db_path));
102 ctx->ldb = ldb_connect(db_path, 0, NULL);
103 if (ctx->ldb == NULL) {
108 talloc_set_destructor(ctx, rootdse_db_destructor);
109 ldb_set_debug(ctx->ldb, rootdse_db_debug, NULL);
115 static NTSTATUS fill_dynamic_values(void *mem_ctx, struct ldap_attribute *attrs)
122 DEBUG(10, ("fill_dynamic_values for %s\n", attrs[0].name));
124 if (strcasecmp(attrs->name, "currentTime") == 0)
126 int num_currentTime = 1;
127 DATA_BLOB *currentTime = talloc_array_p(mem_ctx, DATA_BLOB, num_currentTime);
128 char *str = ldap_timestring(mem_ctx, time(NULL));
129 NT_STATUS_HAVE_NO_MEMORY(str);
130 currentTime[0].data = (uint8_t *)str;
131 currentTime[0].length = strlen(str);
132 ATTR_SINGLE_NOVAL(mem_ctx, attrs, currentTime, num_currentTime, "currentTime");
138 * CN=Aggregate,CN=Schema,CN=Configuration,DC=DOM,DC=TLD
143 * CN=NTDS Settings,CN=NETBIOSNAME,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=DOM,DC=TLD
149 * CN=Configuration,DC=DOM,DC=TLD
150 * CN=Schema,CN=Configuration,DC=DOM,DC=TLD
151 * DC=DomainDnsZones,DC=DOM,DC=TLD
152 * DC=ForestDnsZones,DC=DOM,DC=TLD
156 * defaultNamingContext
161 * schemaNamingContext
162 * CN=Schema,CN=Configuration,DC=DOM,DC=TLD
166 * configurationNamingContext
167 * CN=Configuration,DC=DOM,DC=TLD
171 * rootDomainNamingContext
177 * 1.2.840.113556.1.4.319
178 * 1.2.840.113556.1.4.801
179 * 1.2.840.113556.1.4.473
180 * 1.2.840.113556.1.4.528
181 * 1.2.840.113556.1.4.417
182 * 1.2.840.113556.1.4.619
183 * 1.2.840.113556.1.4.841
184 * 1.2.840.113556.1.4.529
185 * 1.2.840.113556.1.4.805
186 * 1.2.840.113556.1.4.521
187 * 1.2.840.113556.1.4.970
188 * 1.2.840.113556.1.4.1338
189 * 1.2.840.113556.1.4.474
190 * 1.2.840.113556.1.4.1339
191 * 1.2.840.113556.1.4.1340
192 * 1.2.840.113556.1.4.1413
193 * 2.16.840.1.113730.3.4.9
194 * 2.16.840.1.113730.3.4.10
195 * 1.2.840.113556.1.4.1504
196 * 1.2.840.113556.1.4.1852
197 * 1.2.840.113556.1.4.802
201 * supportedLDAPVersion
205 if (strcasecmp(attrs->name, "supportedLDAPVersion") == 0)
207 int num_supportedLDAPVersion = 1;
208 DATA_BLOB *supportedLDAPVersion = talloc_array_p(mem_ctx, DATA_BLOB, num_supportedLDAPVersion);
209 supportedLDAPVersion[0] = ATTR_BLOB_CONST("3");
210 ATTR_SINGLE_NOVAL(mem_ctx, attrs, supportedLDAPVersion, num_supportedLDAPVersion, "supportedLDAPVersion");
215 * supportedLDAPPolicies
226 * MaxNotificationPerConn
231 * highestCommittedUSN
236 * supportedSASLMechanisms
245 * netbiosname.dom.tld
250 * dom.tld:netbiosname$@DOM.TLD
255 * CN=NETBIOSNAME,CN=Servers,CN=Default-First-Site,CN=Sites,CN=Configuration,DC=DOM,DC=TLD
259 * supportedCapabilities
260 * 1.2.840.113556.1.4.800
261 * 1.2.840.113556.1.4.1670
262 * 1.2.840.113556.1.4.1791
271 * isGlobalCatalogReady
276 * domainFunctionality
281 * forestFunctionality
286 * domainControllerFunctionality
291 DATA_BLOB *x = talloc_array_p(mem_ctx, DATA_BLOB, 1);
292 x[0] = ATTR_BLOB_CONST("0");
293 ATTR_SINGLE_NOVAL(mem_ctx, attrs, x, 1, attrs->name);
298 static NTSTATUS rootdse_Search(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
299 struct ldap_SearchRequest *r)
303 struct ldap_SearchResEntry *ent;
304 struct ldap_Result *done;
305 struct ldb_message **res = NULL;
306 int result = LDAP_SUCCESS;
307 struct ldapsrv_reply *ent_r, *done_r;
308 struct rootdse_db_context *rootdsedb;
309 const char *errstr = NULL;
311 const char **attrs = NULL;
313 if (r->scope != LDAP_SEARCH_SCOPE_BASE) {
314 return NT_STATUS_INVALID_PARAMETER;
317 local_ctx = talloc_named(call, 0, "rootdse_Search local memory context");
318 NT_STATUS_HAVE_NO_MEMORY(local_ctx);
320 rootdsedb = rootdse_db_connect(local_ctx);
321 NT_STATUS_HAVE_NO_MEMORY(rootdsedb);
323 if (r->num_attributes >= 1) {
324 attrs = talloc_array_p(rootdsedb, const char *, r->num_attributes+1);
325 NT_STATUS_HAVE_NO_MEMORY(attrs);
327 for (j=0; j < r->num_attributes; j++) {
328 DEBUG(10,("rootDSE_Search: attrs: [%s]\n",r->attributes[j]));
329 attrs[j] = r->attributes[j];
334 count = ldb_search(rootdsedb->ldb, "", 0, "dn=cn=rootDSE", attrs, &res);
335 talloc_steal(rootdsedb, res);
338 ent_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultEntry);
339 NT_STATUS_HAVE_NO_MEMORY(ent_r);
341 ent = &ent_r->msg.r.SearchResultEntry;
343 ent->num_attributes = 0;
344 ent->attributes = NULL;
345 if (res[0]->num_elements == 0) {
348 ent->num_attributes = res[0]->num_elements;
349 ent->attributes = talloc_array_p(ent_r, struct ldap_attribute, ent->num_attributes);
350 NT_STATUS_HAVE_NO_MEMORY(ent->attributes);
351 for (j=0; j < ent->num_attributes; j++) {
352 ent->attributes[j].name = talloc_steal(ent->attributes, res[0]->elements[j].name);
353 ent->attributes[j].num_values = 0;
354 ent->attributes[j].values = NULL;
355 ent->attributes[j].num_values = res[0]->elements[j].num_values;
356 if (ent->attributes[j].num_values == 1 &&
357 strncmp(res[0]->elements[j].values[0].data, "_DYNAMIC_", 9) == 0) {
358 status = fill_dynamic_values(ent->attributes, &(ent->attributes[j]));
359 if (!NT_STATUS_IS_OK(status)) {
363 ent->attributes[j].values = talloc_array_p(ent->attributes,
364 DATA_BLOB, ent->attributes[j].num_values);
365 NT_STATUS_HAVE_NO_MEMORY(ent->attributes[j].values);
366 for (y=0; y < ent->attributes[j].num_values; y++) {
367 ent->attributes[j].values[y].length = res[0]->elements[j].values[y].length;
368 ent->attributes[j].values[y].data = talloc_steal(ent->attributes[j].values,
369 res[0]->elements[j].values[y].data);
374 status = ldapsrv_queue_reply(call, ent_r);
375 if (!NT_STATUS_IS_OK(status)) {
380 done_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultDone);
381 NT_STATUS_HAVE_NO_MEMORY(done_r);
384 DEBUG(10,("rootdse_Search: results: [%d]\n",count));
385 result = LDAP_SUCCESS;
387 } else if (count == 0) {
388 DEBUG(10,("rootdse_Search: no results\n"));
389 result = LDAP_NO_SUCH_OBJECT;
390 errstr = ldb_errstring(rootdsedb->ldb);
391 } else if (count > 1) {
392 DEBUG(10,("rootdse_Search: too many results[%d]\n", count));
394 errstr = "internal error";
395 } else if (count == -1) {
396 DEBUG(10,("rootdse_Search: error\n"));
398 errstr = ldb_errstring(rootdsedb->ldb);
401 done = &done_r->msg.r.SearchResultDone;
403 done->resultcode = result;
404 done->errormessage = (errstr?talloc_strdup(done_r,errstr):NULL);;
405 done->referral = NULL;
407 talloc_free(local_ctx);
409 return ldapsrv_queue_reply(call, done_r);
412 static const struct ldapsrv_partition_ops rootdse_ops = {
413 .Search = rootdse_Search
416 const struct ldapsrv_partition_ops *ldapsrv_get_rootdse_partition_ops(void)