r2876: - more than one rootDSE entry in the database is an error!
[Samba/gebeck_regimport.git] / source4 / ldap_server / ldap_rootdse.c
blob631b38d383dde919188e7b0ff9991d1eb5283cb1
1 /*
2 Unix SMB/CIFS implementation.
3 LDAP server ROOT DSE
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.
21 #include "includes.h"
23 #define ATTR_BLOB_CONST(val) data_blob_talloc(mem_ctx, val, sizeof(val)-1)
24 #define ATTR_SINGLE_NOVAL(ctx, attr, blob, num, nam) do { \
25 attr->name = talloc_strdup(ctx, nam);\
26 if (!attr->name) {\
27 return NT_STATUS_NO_MEMORY;\
29 attr->num_values = num; \
30 attr->values = blob;\
31 } while(0)
32 #define ALLOC_CHECK(ptr) do {\
33 if (!(ptr)) {\
34 return NT_STATUS_NO_MEMORY;\
36 } while(0)
39 struct rootdse_db_context {
40 struct ldb_context *ldb;
41 struct rootdse_db_context **static_ptr;
45 this is used to catch debug messages from ldb
47 void rootdse_db_debug(void *context, enum ldb_debug_level level, const char *fmt, va_list ap) _PRINTF_ATTRIBUTE(3,0)
49 char *s = NULL;
50 if (DEBUGLEVEL < 4 && level > LDB_DEBUG_WARNING) {
51 return;
53 vasprintf(&s, fmt, ap);
54 if (!s) return;
55 DEBUG(level, ("rootdse: %s\n", s));
56 free(s);
60 /* destroy the last connection to the sam */
61 static int rootdse_db_destructor(void *ctx)
63 struct rootdse_db_context *rd_ctx = ctx;
64 ldb_close(rd_ctx->ldb);
65 *(rd_ctx->static_ptr) = NULL;
66 return 0;
70 connect to the SAM database
71 return an opaque context pointer on success, or NULL on failure
73 void *rootdse_db_connect(TALLOC_CTX *mem_ctx)
75 static struct rootdse_db_context *ctx;
76 char *db_path;
78 the way that unix fcntl locking works forces us to have a
79 static ldb handle here rather than a much more sensible
80 approach of having the ldb handle as part of the
81 ldap base structures. Otherwise we would try to open
82 the ldb more than once, and tdb would rightly refuse the
83 second open due to the broken nature of unix locking.
85 if (ctx != NULL) {
86 return talloc_reference(mem_ctx, ctx);
89 ctx = talloc_p(mem_ctx, struct rootdse_db_context);
90 if (ctx == NULL) {
91 errno = ENOMEM;
92 return NULL;
95 ctx->static_ptr = &ctx;
97 db_path = talloc_asprintf(ctx, "tdb://%s/rootdse.ldb", dyn_PRIVATE_DIR);
98 if (db_path == NULL) {
99 errno = ENOMEM;
100 return NULL;
103 DEBUG(10, ("opening %s\n", db_path));
104 ctx->ldb = ldb_connect(db_path, 0, NULL);
105 if (ctx->ldb == NULL) {
106 talloc_free(ctx);
107 return NULL;
110 talloc_set_destructor(ctx, rootdse_db_destructor);
111 ldb_set_debug(ctx->ldb, rootdse_db_debug, NULL);
113 return ctx;
117 static NTSTATUS fill_dynamic_values(void *mem_ctx, struct ldap_attribute *attrs)
120 * currentTime
121 * 20040918090350.0Z
124 DEBUG(10, ("fill_dynamic_values for %s\n", attrs[0].name));
126 if (strcasecmp(attrs->name, "currentTime") == 0)
128 int num_currentTime = 1;
129 DATA_BLOB *currentTime = talloc_array_p(mem_ctx, DATA_BLOB, num_currentTime);
130 char *str = ldap_timestring(mem_ctx, time(NULL));
131 if (!str) {
132 return NT_STATUS_NO_MEMORY;
134 currentTime[0].data = str;
135 currentTime[0].length = strlen(str);
136 ATTR_SINGLE_NOVAL(mem_ctx, attrs, currentTime, num_currentTime, "currentTime");
137 return NT_STATUS_OK;
141 * subschemaSubentry
142 * CN=Aggregate,CN=Schema,CN=Configuration,DC=DOM,DC=TLD
146 * dsServiceName
147 * CN=NTDS Settings,CN=NETBIOSNAME,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=DOM,DC=TLD
151 * namingContexts
152 * DC=DOM,DC=TLD
153 * CN=Configuration,DC=DOM,DC=TLD
154 * CN=Schema,CN=Configuration,DC=DOM,DC=TLD
155 * DC=DomainDnsZones,DC=DOM,DC=TLD
156 * DC=ForestDnsZones,DC=DOM,DC=TLD
160 * defaultNamingContext
161 * DC=DOM,DC=TLD
165 * schemaNamingContext
166 * CN=Schema,CN=Configuration,DC=DOM,DC=TLD
170 * configurationNamingContext
171 * CN=Configuration,DC=DOM,DC=TLD
175 * rootDomainNamingContext
176 * DC=DOM,DC=TLD
180 * supportedControl
181 * 1.2.840.113556.1.4.319
182 * 1.2.840.113556.1.4.801
183 * 1.2.840.113556.1.4.473
184 * 1.2.840.113556.1.4.528
185 * 1.2.840.113556.1.4.417
186 * 1.2.840.113556.1.4.619
187 * 1.2.840.113556.1.4.841
188 * 1.2.840.113556.1.4.529
189 * 1.2.840.113556.1.4.805
190 * 1.2.840.113556.1.4.521
191 * 1.2.840.113556.1.4.970
192 * 1.2.840.113556.1.4.1338
193 * 1.2.840.113556.1.4.474
194 * 1.2.840.113556.1.4.1339
195 * 1.2.840.113556.1.4.1340
196 * 1.2.840.113556.1.4.1413
197 * 2.16.840.1.113730.3.4.9
198 * 2.16.840.1.113730.3.4.10
199 * 1.2.840.113556.1.4.1504
200 * 1.2.840.113556.1.4.1852
201 * 1.2.840.113556.1.4.802
205 * supportedLDAPVersion
209 if (strcasecmp(attrs->name, "supportedLDAPVersion") == 0)
211 int num_supportedLDAPVersion = 1;
212 DATA_BLOB *supportedLDAPVersion = talloc_array_p(mem_ctx, DATA_BLOB, num_supportedLDAPVersion);
213 supportedLDAPVersion[0] = ATTR_BLOB_CONST("3");
214 ATTR_SINGLE_NOVAL(mem_ctx, attrs, supportedLDAPVersion, num_supportedLDAPVersion, "supportedLDAPVersion");
215 return NT_STATUS_OK;
219 * supportedLDAPPolicies
220 * MaxPoolThreads
221 * MaxDatagramRecv
222 * MaxReceiveBuffer
223 * InitRecvTimeout
224 * MaxConnections
225 * MaxConnIdleTime
226 * MaxPageSize
227 * MaxQueryDuration
228 * MaxTempTableSize
229 * MaxResultSetSize
230 * MaxNotificationPerConn
231 * MaxValRange
235 * highestCommittedUSN
236 * 4555
240 * supportedSASLMechanisms
241 * GSSAPI
242 * GSS-SPNEGO
243 * EXTERNAL
244 * DIGEST-MD5
248 * dnsHostName
249 * netbiosname.dom.tld
253 * ldapServiceName
254 * dom.tld:netbiosname$@DOM.TLD
258 * serverName:
259 * CN=NETBIOSNAME,CN=Servers,CN=Default-First-Site,CN=Sites,CN=Configuration,DC=DOM,DC=TLD
263 * supportedCapabilities
264 * 1.2.840.113556.1.4.800
265 * 1.2.840.113556.1.4.1670
266 * 1.2.840.113556.1.4.1791
270 * isSynchronized:
271 * TRUE/FALSE
275 * isGlobalCatalogReady
276 * TRUE/FALSE
280 * domainFunctionality
285 * forestFunctionality
290 * domainControllerFunctionality
295 DATA_BLOB *x = talloc_array_p(mem_ctx, DATA_BLOB, 1);
296 x[0] = ATTR_BLOB_CONST("0");
297 ATTR_SINGLE_NOVAL(mem_ctx, attrs, x, 1, attrs->name);
299 return NT_STATUS_OK;
302 static NTSTATUS rootdse_Search(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
303 struct ldap_SearchRequest *r)
305 NTSTATUS status;
306 void *local_ctx;
307 struct ldap_SearchResEntry *ent;
308 struct ldap_Result *done;
309 struct ldb_message **res;
310 int result = 0;
311 struct ldapsrv_reply *ent_r, *done_r;
312 struct rootdse_db_context *rootdsedb;
313 const char *errstr = NULL;
314 int count, j, y;
315 const char **attrs = NULL;
317 if (r->scope != LDAP_SEARCH_SCOPE_BASE) {
318 count = -1;
319 goto no_base_scope;
322 local_ctx = talloc_named(call, 0, "rootdse_Search local memory context");
323 ALLOC_CHECK(local_ctx);
325 rootdsedb = rootdse_db_connect(local_ctx);
326 ALLOC_CHECK(rootdsedb);
328 if (r->num_attributes >= 1) {
329 attrs = talloc_array_p(rootdsedb, const char *, r->num_attributes+1);
330 ALLOC_CHECK(attrs);
332 for (j=0; j < r->num_attributes; j++) {
333 DEBUG(10,("rootDSE_Search: attrs: [%s]\n",r->attributes[j]));
334 attrs[j] = r->attributes[j];
336 attrs[j] = NULL;
339 ldb_set_alloc(rootdsedb->ldb, talloc_realloc_fn, rootdsedb);
340 count = ldb_search(rootdsedb->ldb, "", 0, "dn=cn=rootDSE", attrs, &res);
342 if (count == 1) {
343 ent_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultEntry);
344 if (!ent_r) {
345 return NT_STATUS_NO_MEMORY;
348 ent = &ent_r->msg.r.SearchResultEntry;
349 ent->dn = "";
350 ent->num_attributes = 0;
351 ent->attributes = NULL;
352 if (res[0]->num_elements == 0) {
353 goto queue_reply;
355 ent->num_attributes = res[0]->num_elements;
356 ent->attributes = talloc_array_p(ent_r, struct ldap_attribute, ent->num_attributes);
357 ALLOC_CHECK(ent->attributes);
358 for (j=0; j < ent->num_attributes; j++) {
359 ent->attributes[j].name = talloc_steal(ent->attributes, res[0]->elements[j].name);
360 ent->attributes[j].num_values = 0;
361 ent->attributes[j].values = NULL;
362 ent->attributes[j].num_values = res[0]->elements[j].num_values;
363 if (ent->attributes[j].num_values == 1 &&
364 strncmp(res[0]->elements[j].values[0].data, "_DYNAMIC_", 9) == 0) {
365 fill_dynamic_values(ent->attributes, &(ent->attributes[j]));
366 if (ent->attributes[j].values[0].data == NULL) {
367 DEBUG (10, ("ARRGHH!\n"));
369 } else {
370 ent->attributes[j].values = talloc_array_p(ent->attributes,
371 DATA_BLOB, ent->attributes[j].num_values);
372 ALLOC_CHECK(ent->attributes[j].values);
373 for (y=0; y < ent->attributes[j].num_values; y++) {
374 ent->attributes[j].values[y].length = res[0]->elements[j].values[y].length;
375 ent->attributes[j].values[y].data = talloc_steal(ent->attributes[j].values,
376 res[0]->elements[j].values[y].data);
380 queue_reply:
381 status = ldapsrv_queue_reply(call, ent_r);
382 if (!NT_STATUS_IS_OK(status)) {
383 return status;
389 no_base_scope:
391 done_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultDone);
392 if (!done_r) {
393 return NT_STATUS_NO_MEMORY;
396 if (count == 1) {
397 DEBUG(10,("rootdse_Search: results: [%d]\n",count));
398 result = 0;
399 errstr = NULL;
400 } else if (count > 1) {
401 DEBUG(10,("rootdse_Search: to many results[%d]\n", count));
402 result = 80; /* nosuchobject */
403 errstr = talloc_strdup(done_r, "internal error");
404 } else if (count == 0) {
405 DEBUG(10,("rootdse_Search: no results\n"));
406 result = 32; /* nosuchobject */
407 errstr = talloc_strdup(done_r, ldb_errstring(rootdsedb->ldb));
408 } else if (count == -1) {
409 DEBUG(10,("rootdse_Search: error\n"));
410 result = 1;
411 errstr = talloc_strdup(done_r, ldb_errstring(rootdsedb->ldb));
414 done = &done_r->msg.r.SearchResultDone;
415 done->resultcode = result;
416 done->dn = NULL;
417 done->errormessage = NULL;
418 done->referral = NULL;
420 talloc_free(local_ctx);
422 return ldapsrv_queue_reply(call, done_r);
425 static const struct ldapsrv_partition_ops rootdse_ops = {
426 .Search = rootdse_Search
429 const struct ldapsrv_partition_ops *ldapsrv_get_rootdse_partition_ops(void)
431 return &rootdse_ops;