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.
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);\
27 return NT_STATUS_NO_MEMORY;\
29 attr->num_values = num; \
32 #define ALLOC_CHECK(ptr) do {\
34 return NT_STATUS_NO_MEMORY;\
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)
50 if (DEBUGLEVEL
< 4 && level
> LDB_DEBUG_WARNING
) {
53 vasprintf(&s
, fmt
, ap
);
55 DEBUG(level
, ("rootdse: %s\n", 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
;
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
;
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.
86 return talloc_reference(mem_ctx
, ctx
);
89 ctx
= talloc_p(mem_ctx
, struct rootdse_db_context
);
95 ctx
->static_ptr
= &ctx
;
97 db_path
= talloc_asprintf(ctx
, "tdb://%s/rootdse.ldb", dyn_PRIVATE_DIR
);
98 if (db_path
== NULL
) {
103 DEBUG(10, ("opening %s\n", db_path
));
104 ctx
->ldb
= ldb_connect(db_path
, 0, NULL
);
105 if (ctx
->ldb
== NULL
) {
110 talloc_set_destructor(ctx
, rootdse_db_destructor
);
111 ldb_set_debug(ctx
->ldb
, rootdse_db_debug
, NULL
);
117 static NTSTATUS
fill_dynamic_values(void *mem_ctx
, struct ldap_attribute
*attrs
)
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
));
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");
142 * CN=Aggregate,CN=Schema,CN=Configuration,DC=DOM,DC=TLD
147 * CN=NTDS Settings,CN=NETBIOSNAME,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,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
165 * schemaNamingContext
166 * CN=Schema,CN=Configuration,DC=DOM,DC=TLD
170 * configurationNamingContext
171 * CN=Configuration,DC=DOM,DC=TLD
175 * rootDomainNamingContext
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");
219 * supportedLDAPPolicies
230 * MaxNotificationPerConn
235 * highestCommittedUSN
240 * supportedSASLMechanisms
249 * netbiosname.dom.tld
254 * dom.tld:netbiosname$@DOM.TLD
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
275 * isGlobalCatalogReady
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
);
302 static NTSTATUS
rootdse_Search(struct ldapsrv_partition
*partition
, struct ldapsrv_call
*call
,
303 struct ldap_SearchRequest
*r
)
307 struct ldap_SearchResEntry
*ent
;
308 struct ldap_Result
*done
;
309 struct ldb_message
**res
;
311 struct ldapsrv_reply
*ent_r
, *done_r
;
312 struct rootdse_db_context
*rootdsedb
;
313 const char *errstr
= NULL
;
315 const char **attrs
= NULL
;
317 if (r
->scope
!= LDAP_SEARCH_SCOPE_BASE
) {
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);
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
];
339 ldb_set_alloc(rootdsedb
->ldb
, talloc_realloc_fn
, rootdsedb
);
340 count
= ldb_search(rootdsedb
->ldb
, "", 0, "dn=cn=rootDSE", attrs
, &res
);
343 ent_r
= ldapsrv_init_reply(call
, LDAP_TAG_SearchResultEntry
);
345 return NT_STATUS_NO_MEMORY
;
348 ent
= &ent_r
->msg
.r
.SearchResultEntry
;
350 ent
->num_attributes
= 0;
351 ent
->attributes
= NULL
;
352 if (res
[0]->num_elements
== 0) {
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"));
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
);
381 status
= ldapsrv_queue_reply(call
, ent_r
);
382 if (!NT_STATUS_IS_OK(status
)) {
391 done_r
= ldapsrv_init_reply(call
, LDAP_TAG_SearchResultDone
);
393 return NT_STATUS_NO_MEMORY
;
397 DEBUG(10,("rootdse_Search: results: [%d]\n",count
));
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"));
411 errstr
= talloc_strdup(done_r
, ldb_errstring(rootdsedb
->ldb
));
414 done
= &done_r
->msg
.r
.SearchResultDone
;
415 done
->resultcode
= result
;
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)