r11567: Ldb API change patch.
[kai/samba-autobuild/.git] / source4 / ldap_server / ldap_rootdse.c
1 /* 
2    Unix SMB/CIFS implementation.
3    LDAP server ROOT DSE
4    Copyright (C) Stefan Metzmacher 2004
5    
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.
10    
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.
15    
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.
19 */
20
21 #include "includes.h"
22 #include "ldap_server/ldap_server.h"
23 #include "system/time.h"
24 #include "lib/ldb/include/ldb.h"
25 #include "lib/ldb/include/ldb_errors.h"
26
27 #define ATTR_BLOB_CONST(val) data_blob_talloc(mem_ctx, val, sizeof(val)-1)
28
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; \
33         attr->values = blob;\
34 } while(0)
35
36 /*
37   this is used to catch debug messages from ldb
38 */
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)
41 {
42         char *s = NULL;
43         if (DEBUGLEVEL < 4 && level > LDB_DEBUG_WARNING) {
44                 return;
45         }
46         vasprintf(&s, fmt, ap);
47         if (!s) return;
48         DEBUG(level, ("rootdse: %s\n", s));
49         free(s);
50 }
51
52
53 /*
54   connect to the SAM database
55  */
56 NTSTATUS rootdse_Init(struct ldapsrv_partition *partition, struct ldapsrv_connection *conn)
57 {
58         char *db_path;
59         struct ldb_context *ldb;
60         TALLOC_CTX *mem_ctx = talloc_new(partition);
61
62         db_path = talloc_asprintf(mem_ctx, "tdb://%s", 
63                                   private_path(mem_ctx, "rootdse.ldb"));
64         if (db_path == NULL) {
65                 return NT_STATUS_NO_MEMORY;
66         }
67
68         ldb = ldb_wrap_connect(mem_ctx, db_path, 0, NULL);
69         if (ldb == NULL) {
70                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
71         }
72
73         ldb_set_debug(ldb, rootdse_db_debug, NULL);
74
75         talloc_steal(partition, ldb);
76         partition->private = ldb;
77         return NT_STATUS_OK;
78 }
79
80
81 static NTSTATUS fill_dynamic_values(void *mem_ctx, struct ldb_message_element *attrs)
82 {
83         /* 
84          * currentTime
85          * 20040918090350.0Z
86          */
87
88         DEBUG(10, ("fill_dynamic_values for %s\n", attrs[0].name));
89
90         if (strcasecmp(attrs->name, "currentTime") == 0)
91         {
92                 int num_currentTime = 1;
93                 DATA_BLOB *currentTime = talloc_array(mem_ctx, DATA_BLOB, num_currentTime);
94                 char *str = ldb_timestring(mem_ctx, time(NULL));
95                 NT_STATUS_HAVE_NO_MEMORY(str);
96                 currentTime[0].data = (uint8_t *)str;
97                 currentTime[0].length = strlen(str);
98                 ATTR_SINGLE_NOVAL(mem_ctx, attrs, currentTime, num_currentTime, "currentTime");
99                 return NT_STATUS_OK;
100         }
101
102         /* 
103          * subschemaSubentry 
104          * CN=Aggregate,CN=Schema,CN=Configuration,DC=DOM,DC=TLD
105          */
106
107         /* 
108          * dsServiceName
109          * CN=NTDS Settings,CN=NETBIOSNAME,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=DOM,DC=TLD
110          */
111
112         /* 
113          * namingContexts
114          * DC=DOM,DC=TLD
115          * CN=Configuration,DC=DOM,DC=TLD
116          * CN=Schema,CN=Configuration,DC=DOM,DC=TLD
117          * DC=DomainDnsZones,DC=DOM,DC=TLD
118          * DC=ForestDnsZones,DC=DOM,DC=TLD
119          */
120
121         /* 
122          * defaultNamingContext
123          * DC=DOM,DC=TLD
124          */
125
126         /* 
127          * schemaNamingContext
128          * CN=Schema,CN=Configuration,DC=DOM,DC=TLD
129          */
130
131         /* 
132          * configurationNamingContext
133          * CN=Configuration,DC=DOM,DC=TLD
134          */
135
136         /* 
137          * rootDomainNamingContext
138          * DC=DOM,DC=TLD
139          */
140
141         /* 
142          * supportedControl
143          * 1.2.840.113556.1.4.319
144          * 1.2.840.113556.1.4.801
145          * 1.2.840.113556.1.4.473
146          * 1.2.840.113556.1.4.528
147          * 1.2.840.113556.1.4.417
148          * 1.2.840.113556.1.4.619
149          * 1.2.840.113556.1.4.841
150          * 1.2.840.113556.1.4.529
151          * 1.2.840.113556.1.4.805
152          * 1.2.840.113556.1.4.521
153          * 1.2.840.113556.1.4.970
154          * 1.2.840.113556.1.4.1338
155          * 1.2.840.113556.1.4.474
156          * 1.2.840.113556.1.4.1339
157          * 1.2.840.113556.1.4.1340
158          * 1.2.840.113556.1.4.1413
159          * 2.16.840.1.113730.3.4.9
160          * 2.16.840.1.113730.3.4.10
161          * 1.2.840.113556.1.4.1504
162          * 1.2.840.113556.1.4.1852
163          * 1.2.840.113556.1.4.802
164          */
165
166         /* 
167          * supportedLDAPVersion 
168          * 3
169          * 2
170          */
171         if (strcasecmp(attrs->name, "supportedLDAPVersion") == 0)
172         {
173                 int num_supportedLDAPVersion = 1;
174                 DATA_BLOB *supportedLDAPVersion = talloc_array(mem_ctx, DATA_BLOB, num_supportedLDAPVersion);
175                 supportedLDAPVersion[0] = ATTR_BLOB_CONST("3");
176                 ATTR_SINGLE_NOVAL(mem_ctx, attrs, supportedLDAPVersion, num_supportedLDAPVersion, "supportedLDAPVersion");
177                 return NT_STATUS_OK;
178         }
179
180         /* 
181          * supportedLDAPPolicies
182          * MaxPoolThreads
183          * MaxDatagramRecv
184          * MaxReceiveBuffer
185          * InitRecvTimeout
186          * MaxConnections
187          * MaxConnIdleTime
188          * MaxPageSize
189          * MaxQueryDuration
190          * MaxTempTableSize
191          * MaxResultSetSize
192          * MaxNotificationPerConn
193          * MaxValRange
194          */
195
196         /* 
197          * highestCommittedUSN 
198          * 4555
199          */
200
201         /* 
202          * supportedSASLMechanisms
203          * GSSAPI
204          * GSS-SPNEGO
205          * EXTERNAL
206          * DIGEST-MD5
207          */
208
209         /* 
210          * dnsHostName
211          * netbiosname.dom.tld
212          */
213
214         /* 
215          * ldapServiceName
216          * dom.tld:netbiosname$@DOM.TLD
217          */
218
219         /* 
220          * serverName:
221          * CN=NETBIOSNAME,CN=Servers,CN=Default-First-Site,CN=Sites,CN=Configuration,DC=DOM,DC=TLD
222          */
223
224         /* 
225          * supportedCapabilities
226          * 1.2.840.113556.1.4.800
227          * 1.2.840.113556.1.4.1670
228          * 1.2.840.113556.1.4.1791
229          */
230
231         /* 
232          * isSynchronized:
233          * TRUE/FALSE
234          */
235
236         /* 
237          * isGlobalCatalogReady
238          * TRUE/FALSE
239          */
240
241         /* 
242          * domainFunctionality
243          * 0
244          */
245
246         /* 
247          * forestFunctionality
248          * 0
249          */
250
251         /* 
252          * domainControllerFunctionality
253          * 2
254          */
255
256         {
257                 DATA_BLOB *x = talloc_array(mem_ctx, DATA_BLOB, 1);
258                 x[0] = ATTR_BLOB_CONST("0");
259                 ATTR_SINGLE_NOVAL(mem_ctx, attrs, x, 1, attrs->name);
260         }
261         return NT_STATUS_OK;
262 }
263
264 static NTSTATUS rootdse_Search(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
265                                struct ldap_SearchRequest *r)
266 {
267         NTSTATUS status;
268         void *local_ctx;
269         struct ldap_SearchResEntry *ent;
270         struct ldap_Result *done;
271         struct ldb_result *res = NULL;
272         int result = LDAP_SUCCESS;
273         struct ldapsrv_reply *ent_r, *done_r;
274         struct ldb_context *ldb;
275         const char *errstr = NULL;
276         int ret, j;
277         const char **attrs = NULL;
278
279         if (r->scope != LDAP_SEARCH_SCOPE_BASE) {
280                 return NT_STATUS_INVALID_PARAMETER;
281         }
282
283         local_ctx = talloc_named(call, 0, "rootdse_Search local memory context");
284         NT_STATUS_HAVE_NO_MEMORY(local_ctx);
285
286         ldb = talloc_get_type(partition->private, struct ldb_context);
287
288         if (r->num_attributes >= 1) {
289                 attrs = talloc_array(ldb, const char *, r->num_attributes+1);
290                 NT_STATUS_HAVE_NO_MEMORY(attrs);
291
292                 for (j=0; j < r->num_attributes; j++) {
293                         DEBUG(10,("rootDSE_Search: attrs: [%s]\n",r->attributes[j]));
294                         attrs[j] = r->attributes[j];
295                 }
296                 attrs[j] = NULL;
297         }
298
299         ret = ldb_search(ldb, ldb_dn_explode(local_ctx, "cn=rootDSE"), 0, NULL, attrs, &res);
300         talloc_steal(local_ctx, res);
301
302         if (ret == LDB_SUCCESS && res->count == 1) {
303                 ent_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultEntry);
304                 NT_STATUS_HAVE_NO_MEMORY(ent_r);
305
306                 ent = &ent_r->msg->r.SearchResultEntry;
307                 ent->dn = "";
308                 ent->num_attributes = 0;
309                 ent->attributes = NULL;
310                 if (res->msgs[0]->num_elements == 0) {
311                         goto queue_reply;
312                 }
313                 ent->num_attributes = res->msgs[0]->num_elements;
314                 ent->attributes = talloc_steal(ent_r, res->msgs[0]->elements);
315
316                 for (j=0; j < ent->num_attributes; j++) {
317                         if (ent->attributes[j].num_values == 1 &&
318                             ent->attributes[j].values[0].length >= 9 &&
319                             strncmp((char *)ent->attributes[j].values[0].data, "_DYNAMIC_", 9) == 0) {
320                                 status = fill_dynamic_values(ent->attributes, &(ent->attributes[j]));
321                                 if (!NT_STATUS_IS_OK(status)) {
322                                         return status;
323                                 }
324                         }
325                 }
326 queue_reply:
327                 ldapsrv_queue_reply(call, ent_r);
328         }
329
330         done_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultDone);
331         NT_STATUS_HAVE_NO_MEMORY(done_r);
332
333         if (ret != LDB_SUCCESS) {
334                 DEBUG(10,("rootdse_Search: error\n"));
335                 result = LDAP_OTHER;
336                 errstr = ldb_errstring(ldb);
337         } else if (res->count == 0) {
338                 DEBUG(10,("rootdse_Search: no results\n"));
339                 result = LDAP_NO_SUCH_OBJECT;
340                 errstr = ldb_errstring(ldb);
341         } else if (res->count == 1) {
342                 DEBUG(10,("rootdse_Search: results: [%d]\n", res->count));
343                 result = LDAP_SUCCESS;
344                 errstr = NULL;
345         } else if (res->count > 1) {
346                 DEBUG(10,("rootdse_Search: too many results[%d]\n", res->count));
347                 result = LDAP_OTHER; 
348                 errstr = "internal error";      
349         }
350
351         done = &done_r->msg->r.SearchResultDone;
352         done->dn = NULL;
353         done->resultcode = result;
354         done->errormessage = (errstr?talloc_strdup(done_r,errstr):NULL);;
355         done->referral = NULL;
356
357         talloc_free(local_ctx);
358
359         ldapsrv_queue_reply(call, done_r);
360         return NT_STATUS_OK;
361 }
362
363 static const struct ldapsrv_partition_ops rootdse_ops = {
364         .Init           = rootdse_Init,
365         .Search         = rootdse_Search
366 };
367
368 const struct ldapsrv_partition_ops *ldapsrv_get_rootdse_partition_ops(void)
369 {
370         return &rootdse_ops;
371 }