r7711: update callers of ldb_connect() for new syntax
[gd/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 "dynconfig.h"
23 #include "ldap_server/ldap_server.h"
24 #include "system/time.h"
25 #include "lib/ldb/include/ldb.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 static struct ldb_context *rootdse_db_connect(TALLOC_CTX *mem_ctx)
57 {
58         char *db_path;
59         struct ldb_context *ldb;
60
61         db_path = talloc_asprintf(mem_ctx, "tdb://%s", 
62                                   private_path(mem_ctx, "rootdse.ldb"));
63         if (db_path == NULL) {
64                 return NULL;
65         }
66
67         ldb = ldb_wrap_connect(mem_ctx, db_path, 0, NULL);
68         if (ldb == NULL) {
69                 return NULL;
70         }
71
72         ldb_set_debug(ldb, rootdse_db_debug, NULL);
73
74         return ldb;
75 }
76
77
78 static NTSTATUS fill_dynamic_values(void *mem_ctx, struct ldb_message_element *attrs)
79 {
80         /* 
81          * currentTime
82          * 20040918090350.0Z
83          */
84
85         DEBUG(10, ("fill_dynamic_values for %s\n", attrs[0].name));
86
87         if (strcasecmp(attrs->name, "currentTime") == 0)
88         {
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");
96                 return NT_STATUS_OK;
97         }
98
99         /* 
100          * subschemaSubentry 
101          * CN=Aggregate,CN=Schema,CN=Configuration,DC=DOM,DC=TLD
102          */
103
104         /* 
105          * dsServiceName
106          * CN=NTDS Settings,CN=NETBIOSNAME,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=DOM,DC=TLD
107          */
108
109         /* 
110          * namingContexts
111          * 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
116          */
117
118         /* 
119          * defaultNamingContext
120          * DC=DOM,DC=TLD
121          */
122
123         /* 
124          * schemaNamingContext
125          * CN=Schema,CN=Configuration,DC=DOM,DC=TLD
126          */
127
128         /* 
129          * configurationNamingContext
130          * CN=Configuration,DC=DOM,DC=TLD
131          */
132
133         /* 
134          * rootDomainNamingContext
135          * DC=DOM,DC=TLD
136          */
137
138         /* 
139          * supportedControl
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
161          */
162
163         /* 
164          * supportedLDAPVersion 
165          * 3
166          * 2
167          */
168         if (strcasecmp(attrs->name, "supportedLDAPVersion") == 0)
169         {
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");
174                 return NT_STATUS_OK;
175         }
176
177         /* 
178          * supportedLDAPPolicies
179          * MaxPoolThreads
180          * MaxDatagramRecv
181          * MaxReceiveBuffer
182          * InitRecvTimeout
183          * MaxConnections
184          * MaxConnIdleTime
185          * MaxPageSize
186          * MaxQueryDuration
187          * MaxTempTableSize
188          * MaxResultSetSize
189          * MaxNotificationPerConn
190          * MaxValRange
191          */
192
193         /* 
194          * highestCommittedUSN 
195          * 4555
196          */
197
198         /* 
199          * supportedSASLMechanisms
200          * GSSAPI
201          * GSS-SPNEGO
202          * EXTERNAL
203          * DIGEST-MD5
204          */
205
206         /* 
207          * dnsHostName
208          * netbiosname.dom.tld
209          */
210
211         /* 
212          * ldapServiceName
213          * dom.tld:netbiosname$@DOM.TLD
214          */
215
216         /* 
217          * serverName:
218          * CN=NETBIOSNAME,CN=Servers,CN=Default-First-Site,CN=Sites,CN=Configuration,DC=DOM,DC=TLD
219          */
220
221         /* 
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
226          */
227
228         /* 
229          * isSynchronized:
230          * TRUE/FALSE
231          */
232
233         /* 
234          * isGlobalCatalogReady
235          * TRUE/FALSE
236          */
237
238         /* 
239          * domainFunctionality
240          * 0
241          */
242
243         /* 
244          * forestFunctionality
245          * 0
246          */
247
248         /* 
249          * domainControllerFunctionality
250          * 2
251          */
252
253         {
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);
257         }
258         return NT_STATUS_OK;
259 }
260
261 static NTSTATUS rootdse_Search(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
262                                      struct ldap_SearchRequest *r)
263 {
264         NTSTATUS status;
265         void *local_ctx;
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;
273         int count, j, y;
274         const char **attrs = NULL;
275
276         if (r->scope != LDAP_SEARCH_SCOPE_BASE) {
277                 return NT_STATUS_INVALID_PARAMETER;
278         }
279
280         local_ctx = talloc_named(call, 0, "rootdse_Search local memory context");
281         NT_STATUS_HAVE_NO_MEMORY(local_ctx);
282
283         ldb = rootdse_db_connect(local_ctx);
284         NT_STATUS_HAVE_NO_MEMORY(ldb);
285
286         if (r->num_attributes >= 1) {
287                 attrs = talloc_array(ldb, const char *, r->num_attributes+1);
288                 NT_STATUS_HAVE_NO_MEMORY(attrs);
289
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];
293                 }
294                 attrs[j] = NULL;
295         }
296
297         count = ldb_search(ldb, NULL, 0, "dn=cn=rootDSE", attrs, &res);
298         talloc_steal(local_ctx, res);
299
300         if (count == 1) {
301                 ent_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultEntry);
302                 NT_STATUS_HAVE_NO_MEMORY(ent_r);
303
304                 ent = &ent_r->msg->r.SearchResultEntry;
305                 ent->dn = "";
306                 ent->num_attributes = 0;
307                 ent->attributes = NULL;
308                 if (res[0]->num_elements == 0) {
309                         goto queue_reply;
310                 }
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)) {
323                                         return status;
324                                 }
325                         } else {
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);
333                                 }
334                         }
335                 }
336 queue_reply:
337                 status = ldapsrv_queue_reply(call, ent_r);
338                 if (!NT_STATUS_IS_OK(status)) {
339                         return status;
340                 }
341         }
342
343         done_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultDone);
344         NT_STATUS_HAVE_NO_MEMORY(done_r);
345
346         if (count == 1) {
347                 DEBUG(10,("rootdse_Search: results: [%d]\n",count));
348                 result = LDAP_SUCCESS;
349                 errstr = NULL;
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));
356                 result = LDAP_OTHER; 
357                 errstr = "internal error";      
358         } else if (count == -1) {
359                 DEBUG(10,("rootdse_Search: error\n"));
360                 result = LDAP_OTHER;
361                 errstr = ldb_errstring(ldb);
362         }
363
364         done = &done_r->msg->r.SearchResultDone;
365         done->dn = NULL;
366         done->resultcode = result;
367         done->errormessage = (errstr?talloc_strdup(done_r,errstr):NULL);;
368         done->referral = NULL;
369
370         talloc_free(local_ctx);
371
372         return ldapsrv_queue_reply(call, done_r);
373 }
374
375 static const struct ldapsrv_partition_ops rootdse_ops = {
376         .Search         = rootdse_Search
377 };
378
379 const struct ldapsrv_partition_ops *ldapsrv_get_rootdse_partition_ops(void)
380 {
381         return &rootdse_ops;
382 }