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