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; \
37 this is used to catch debug messages from ldb
39 static void rootdse_db_debug(void *context, enum ldb_debug_level level, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
40 static void rootdse_db_debug(void *context, enum ldb_debug_level level, const char *fmt, va_list ap)
43 if (DEBUGLEVEL < 4 && level > LDB_DEBUG_WARNING) {
46 vasprintf(&s, fmt, ap);
48 DEBUG(level, ("rootdse: %s\n", s));
54 connect to the SAM database
56 static struct ldb_context *rootdse_db_connect(TALLOC_CTX *mem_ctx)
59 struct ldb_context *ldb;
61 db_path = talloc_asprintf(mem_ctx, "tdb://%s",
62 private_path(mem_ctx, "rootdse.ldb"));
63 if (db_path == NULL) {
67 ldb = ldb_wrap_connect(mem_ctx, db_path, 0, NULL);
72 ldb_set_debug(ldb, rootdse_db_debug, NULL);
78 static NTSTATUS fill_dynamic_values(void *mem_ctx, struct ldb_message_element *attrs)
85 DEBUG(10, ("fill_dynamic_values for %s\n", attrs[0].name));
87 if (strcasecmp(attrs->name, "currentTime") == 0)
89 int num_currentTime = 1;
90 DATA_BLOB *currentTime = talloc_array(mem_ctx, DATA_BLOB, num_currentTime);
91 char *str = ldap_timestring(mem_ctx, time(NULL));
92 NT_STATUS_HAVE_NO_MEMORY(str);
93 currentTime[0].data = (uint8_t *)str;
94 currentTime[0].length = strlen(str);
95 ATTR_SINGLE_NOVAL(mem_ctx, attrs, currentTime, num_currentTime, "currentTime");
101 * CN=Aggregate,CN=Schema,CN=Configuration,DC=DOM,DC=TLD
106 * CN=NTDS Settings,CN=NETBIOSNAME,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=DOM,DC=TLD
112 * CN=Configuration,DC=DOM,DC=TLD
113 * CN=Schema,CN=Configuration,DC=DOM,DC=TLD
114 * DC=DomainDnsZones,DC=DOM,DC=TLD
115 * DC=ForestDnsZones,DC=DOM,DC=TLD
119 * defaultNamingContext
124 * schemaNamingContext
125 * CN=Schema,CN=Configuration,DC=DOM,DC=TLD
129 * configurationNamingContext
130 * CN=Configuration,DC=DOM,DC=TLD
134 * rootDomainNamingContext
140 * 1.2.840.113556.1.4.319
141 * 1.2.840.113556.1.4.801
142 * 1.2.840.113556.1.4.473
143 * 1.2.840.113556.1.4.528
144 * 1.2.840.113556.1.4.417
145 * 1.2.840.113556.1.4.619
146 * 1.2.840.113556.1.4.841
147 * 1.2.840.113556.1.4.529
148 * 1.2.840.113556.1.4.805
149 * 1.2.840.113556.1.4.521
150 * 1.2.840.113556.1.4.970
151 * 1.2.840.113556.1.4.1338
152 * 1.2.840.113556.1.4.474
153 * 1.2.840.113556.1.4.1339
154 * 1.2.840.113556.1.4.1340
155 * 1.2.840.113556.1.4.1413
156 * 2.16.840.1.113730.3.4.9
157 * 2.16.840.1.113730.3.4.10
158 * 1.2.840.113556.1.4.1504
159 * 1.2.840.113556.1.4.1852
160 * 1.2.840.113556.1.4.802
164 * supportedLDAPVersion
168 if (strcasecmp(attrs->name, "supportedLDAPVersion") == 0)
170 int num_supportedLDAPVersion = 1;
171 DATA_BLOB *supportedLDAPVersion = talloc_array(mem_ctx, DATA_BLOB, num_supportedLDAPVersion);
172 supportedLDAPVersion[0] = ATTR_BLOB_CONST("3");
173 ATTR_SINGLE_NOVAL(mem_ctx, attrs, supportedLDAPVersion, num_supportedLDAPVersion, "supportedLDAPVersion");
178 * supportedLDAPPolicies
189 * MaxNotificationPerConn
194 * highestCommittedUSN
199 * supportedSASLMechanisms
208 * netbiosname.dom.tld
213 * dom.tld:netbiosname$@DOM.TLD
218 * CN=NETBIOSNAME,CN=Servers,CN=Default-First-Site,CN=Sites,CN=Configuration,DC=DOM,DC=TLD
222 * supportedCapabilities
223 * 1.2.840.113556.1.4.800
224 * 1.2.840.113556.1.4.1670
225 * 1.2.840.113556.1.4.1791
234 * isGlobalCatalogReady
239 * domainFunctionality
244 * forestFunctionality
249 * domainControllerFunctionality
254 DATA_BLOB *x = talloc_array(mem_ctx, DATA_BLOB, 1);
255 x[0] = ATTR_BLOB_CONST("0");
256 ATTR_SINGLE_NOVAL(mem_ctx, attrs, x, 1, attrs->name);
261 static NTSTATUS rootdse_Search(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
262 struct ldap_SearchRequest *r)
266 struct ldap_SearchResEntry *ent;
267 struct ldap_Result *done;
268 struct ldb_message **res = NULL;
269 int result = LDAP_SUCCESS;
270 struct ldapsrv_reply *ent_r, *done_r;
271 struct ldb_context *ldb;
272 const char *errstr = NULL;
274 const char **attrs = NULL;
276 if (r->scope != LDAP_SEARCH_SCOPE_BASE) {
277 return NT_STATUS_INVALID_PARAMETER;
280 local_ctx = talloc_named(call, 0, "rootdse_Search local memory context");
281 NT_STATUS_HAVE_NO_MEMORY(local_ctx);
283 ldb = rootdse_db_connect(local_ctx);
284 NT_STATUS_HAVE_NO_MEMORY(ldb);
286 if (r->num_attributes >= 1) {
287 attrs = talloc_array(ldb, const char *, r->num_attributes+1);
288 NT_STATUS_HAVE_NO_MEMORY(attrs);
290 for (j=0; j < r->num_attributes; j++) {
291 DEBUG(10,("rootDSE_Search: attrs: [%s]\n",r->attributes[j]));
292 attrs[j] = r->attributes[j];
297 count = ldb_search(ldb, NULL, 0, "dn=cn=rootDSE", attrs, &res);
298 talloc_steal(local_ctx, res);
301 ent_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultEntry);
302 NT_STATUS_HAVE_NO_MEMORY(ent_r);
304 ent = &ent_r->msg->r.SearchResultEntry;
306 ent->num_attributes = 0;
307 ent->attributes = NULL;
308 if (res[0]->num_elements == 0) {
311 ent->num_attributes = res[0]->num_elements;
312 ent->attributes = talloc_array(ent_r, struct ldb_message_element, ent->num_attributes);
313 NT_STATUS_HAVE_NO_MEMORY(ent->attributes);
314 for (j=0; j < ent->num_attributes; j++) {
315 ent->attributes[j].name = talloc_steal(ent->attributes, res[0]->elements[j].name);
316 ent->attributes[j].num_values = 0;
317 ent->attributes[j].values = NULL;
318 ent->attributes[j].num_values = res[0]->elements[j].num_values;
319 if (ent->attributes[j].num_values == 1 &&
320 strncmp(res[0]->elements[j].values[0].data, "_DYNAMIC_", 9) == 0) {
321 status = fill_dynamic_values(ent->attributes, &(ent->attributes[j]));
322 if (!NT_STATUS_IS_OK(status)) {
326 ent->attributes[j].values = talloc_array(ent->attributes,
327 DATA_BLOB, ent->attributes[j].num_values);
328 NT_STATUS_HAVE_NO_MEMORY(ent->attributes[j].values);
329 for (y=0; y < ent->attributes[j].num_values; y++) {
330 ent->attributes[j].values[y].length = res[0]->elements[j].values[y].length;
331 ent->attributes[j].values[y].data = talloc_steal(ent->attributes[j].values,
332 res[0]->elements[j].values[y].data);
337 status = ldapsrv_queue_reply(call, ent_r);
338 if (!NT_STATUS_IS_OK(status)) {
343 done_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultDone);
344 NT_STATUS_HAVE_NO_MEMORY(done_r);
347 DEBUG(10,("rootdse_Search: results: [%d]\n",count));
348 result = LDAP_SUCCESS;
350 } else if (count == 0) {
351 DEBUG(10,("rootdse_Search: no results\n"));
352 result = LDAP_NO_SUCH_OBJECT;
353 errstr = ldb_errstring(ldb);
354 } else if (count > 1) {
355 DEBUG(10,("rootdse_Search: too many results[%d]\n", count));
357 errstr = "internal error";
358 } else if (count == -1) {
359 DEBUG(10,("rootdse_Search: error\n"));
361 errstr = ldb_errstring(ldb);
364 done = &done_r->msg->r.SearchResultDone;
366 done->resultcode = result;
367 done->errormessage = (errstr?talloc_strdup(done_r,errstr):NULL);;
368 done->referral = NULL;
370 talloc_free(local_ctx);
372 return ldapsrv_queue_reply(call, done_r);
375 static const struct ldapsrv_partition_ops rootdse_ops = {
376 .Search = rootdse_Search
379 const struct ldapsrv_partition_ops *ldapsrv_get_rootdse_partition_ops(void)