Remove use of fstring and pstring in dynconfig.c
[samba-svnmirror.git] / source / 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 static struct ldb_context *rootdse_db_connect(TALLOC_CTX *mem_ctx)
56 {
57         char *db_path;
58         struct ldb_context *ldb;
59
60         db_path = talloc_asprintf(mem_ctx, "tdb://%s", 
61                                   private_path(mem_ctx, "rootdse.ldb"));
62         if (db_path == NULL) {
63                 return NULL;
64         }
65
66         ldb = ldb_wrap_connect(mem_ctx, db_path, 0, NULL);
67         if (ldb == NULL) {
68                 return NULL;
69         }
70
71         ldb_set_debug(ldb, rootdse_db_debug, NULL);
72
73         return ldb;
74 }
75
76
77 static NTSTATUS fill_dynamic_values(void *mem_ctx, struct ldb_message_element *attrs)
78 {
79         /* 
80          * currentTime
81          * 20040918090350.0Z
82          */
83
84         DEBUG(10, ("fill_dynamic_values for %s\n", attrs[0].name));
85
86         if (strcasecmp(attrs->name, "currentTime") == 0)
87         {
88                 int num_currentTime = 1;
89                 DATA_BLOB *currentTime = talloc_array(mem_ctx, DATA_BLOB, num_currentTime);
90                 char *str = ldap_timestring(mem_ctx, time(NULL));
91                 NT_STATUS_HAVE_NO_MEMORY(str);
92                 currentTime[0].data = (uint8_t *)str;
93                 currentTime[0].length = strlen(str);
94                 ATTR_SINGLE_NOVAL(mem_ctx, attrs, currentTime, num_currentTime, "currentTime");
95                 return NT_STATUS_OK;
96         }
97
98         /* 
99          * subschemaSubentry 
100          * CN=Aggregate,CN=Schema,CN=Configuration,DC=DOM,DC=TLD
101          */
102
103         /* 
104          * dsServiceName
105          * CN=NTDS Settings,CN=NETBIOSNAME,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=DOM,DC=TLD
106          */
107
108         /* 
109          * namingContexts
110          * DC=DOM,DC=TLD
111          * CN=Configuration,DC=DOM,DC=TLD
112          * CN=Schema,CN=Configuration,DC=DOM,DC=TLD
113          * DC=DomainDnsZones,DC=DOM,DC=TLD
114          * DC=ForestDnsZones,DC=DOM,DC=TLD
115          */
116
117         /* 
118          * defaultNamingContext
119          * DC=DOM,DC=TLD
120          */
121
122         /* 
123          * schemaNamingContext
124          * CN=Schema,CN=Configuration,DC=DOM,DC=TLD
125          */
126
127         /* 
128          * configurationNamingContext
129          * CN=Configuration,DC=DOM,DC=TLD
130          */
131
132         /* 
133          * rootDomainNamingContext
134          * DC=DOM,DC=TLD
135          */
136
137         /* 
138          * supportedControl
139          * 1.2.840.113556.1.4.319
140          * 1.2.840.113556.1.4.801
141          * 1.2.840.113556.1.4.473
142          * 1.2.840.113556.1.4.528
143          * 1.2.840.113556.1.4.417
144          * 1.2.840.113556.1.4.619
145          * 1.2.840.113556.1.4.841
146          * 1.2.840.113556.1.4.529
147          * 1.2.840.113556.1.4.805
148          * 1.2.840.113556.1.4.521
149          * 1.2.840.113556.1.4.970
150          * 1.2.840.113556.1.4.1338
151          * 1.2.840.113556.1.4.474
152          * 1.2.840.113556.1.4.1339
153          * 1.2.840.113556.1.4.1340
154          * 1.2.840.113556.1.4.1413
155          * 2.16.840.1.113730.3.4.9
156          * 2.16.840.1.113730.3.4.10
157          * 1.2.840.113556.1.4.1504
158          * 1.2.840.113556.1.4.1852
159          * 1.2.840.113556.1.4.802
160          */
161
162         /* 
163          * supportedLDAPVersion 
164          * 3
165          * 2
166          */
167         if (strcasecmp(attrs->name, "supportedLDAPVersion") == 0)
168         {
169                 int num_supportedLDAPVersion = 1;
170                 DATA_BLOB *supportedLDAPVersion = talloc_array(mem_ctx, DATA_BLOB, num_supportedLDAPVersion);
171                 supportedLDAPVersion[0] = ATTR_BLOB_CONST("3");
172                 ATTR_SINGLE_NOVAL(mem_ctx, attrs, supportedLDAPVersion, num_supportedLDAPVersion, "supportedLDAPVersion");
173                 return NT_STATUS_OK;
174         }
175
176         /* 
177          * supportedLDAPPolicies
178          * MaxPoolThreads
179          * MaxDatagramRecv
180          * MaxReceiveBuffer
181          * InitRecvTimeout
182          * MaxConnections
183          * MaxConnIdleTime
184          * MaxPageSize
185          * MaxQueryDuration
186          * MaxTempTableSize
187          * MaxResultSetSize
188          * MaxNotificationPerConn
189          * MaxValRange
190          */
191
192         /* 
193          * highestCommittedUSN 
194          * 4555
195          */
196
197         /* 
198          * supportedSASLMechanisms
199          * GSSAPI
200          * GSS-SPNEGO
201          * EXTERNAL
202          * DIGEST-MD5
203          */
204
205         /* 
206          * dnsHostName
207          * netbiosname.dom.tld
208          */
209
210         /* 
211          * ldapServiceName
212          * dom.tld:netbiosname$@DOM.TLD
213          */
214
215         /* 
216          * serverName:
217          * CN=NETBIOSNAME,CN=Servers,CN=Default-First-Site,CN=Sites,CN=Configuration,DC=DOM,DC=TLD
218          */
219
220         /* 
221          * supportedCapabilities
222          * 1.2.840.113556.1.4.800
223          * 1.2.840.113556.1.4.1670
224          * 1.2.840.113556.1.4.1791
225          */
226
227         /* 
228          * isSynchronized:
229          * TRUE/FALSE
230          */
231
232         /* 
233          * isGlobalCatalogReady
234          * TRUE/FALSE
235          */
236
237         /* 
238          * domainFunctionality
239          * 0
240          */
241
242         /* 
243          * forestFunctionality
244          * 0
245          */
246
247         /* 
248          * domainControllerFunctionality
249          * 2
250          */
251
252         {
253                 DATA_BLOB *x = talloc_array(mem_ctx, DATA_BLOB, 1);
254                 x[0] = ATTR_BLOB_CONST("0");
255                 ATTR_SINGLE_NOVAL(mem_ctx, attrs, x, 1, attrs->name);
256         }
257         return NT_STATUS_OK;
258 }
259
260 static NTSTATUS rootdse_Search(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
261                                      struct ldap_SearchRequest *r)
262 {
263         NTSTATUS status;
264         void *local_ctx;
265         struct ldap_SearchResEntry *ent;
266         struct ldap_Result *done;
267         struct ldb_message **res = NULL;
268         int result = LDAP_SUCCESS;
269         struct ldapsrv_reply *ent_r, *done_r;
270         struct ldb_context *ldb;
271         const char *errstr = NULL;
272         int count, j;
273         const char **attrs = NULL;
274
275         if (r->scope != LDAP_SEARCH_SCOPE_BASE) {
276                 return NT_STATUS_INVALID_PARAMETER;
277         }
278
279         local_ctx = talloc_named(call, 0, "rootdse_Search local memory context");
280         NT_STATUS_HAVE_NO_MEMORY(local_ctx);
281
282         ldb = rootdse_db_connect(local_ctx);
283         NT_STATUS_HAVE_NO_MEMORY(ldb);
284
285         if (r->num_attributes >= 1) {
286                 attrs = talloc_array(ldb, const char *, r->num_attributes+1);
287                 NT_STATUS_HAVE_NO_MEMORY(attrs);
288
289                 for (j=0; j < r->num_attributes; j++) {
290                         DEBUG(10,("rootDSE_Search: attrs: [%s]\n",r->attributes[j]));
291                         attrs[j] = r->attributes[j];
292                 }
293                 attrs[j] = NULL;
294         }
295
296         count = ldb_search(ldb, ldb_dn_explode(local_ctx, "cn=rootDSE"), 0, 
297                            NULL, 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_steal(ent_r, res[0]->elements);
313
314                 for (j=0; j < ent->num_attributes; j++) {
315                         if (ent->attributes[j].num_values == 1 &&
316                             ent->attributes[j].values[0].length >= 9 &&
317                             strncmp(ent->attributes[j].values[0].data, "_DYNAMIC_", 9) == 0) {
318                                 status = fill_dynamic_values(ent->attributes, &(ent->attributes[j]));
319                                 if (!NT_STATUS_IS_OK(status)) {
320                                         return status;
321                                 }
322                         }
323                 }
324 queue_reply:
325                 ldapsrv_queue_reply(call, ent_r);
326         }
327
328         done_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultDone);
329         NT_STATUS_HAVE_NO_MEMORY(done_r);
330
331         if (count == 1) {
332                 DEBUG(10,("rootdse_Search: results: [%d]\n",count));
333                 result = LDAP_SUCCESS;
334                 errstr = NULL;
335         } else if (count == 0) {
336                 DEBUG(10,("rootdse_Search: no results\n"));
337                 result = LDAP_NO_SUCH_OBJECT;
338                 errstr = ldb_errstring(ldb);
339         } else if (count > 1) {
340                 DEBUG(10,("rootdse_Search: too many results[%d]\n", count));
341                 result = LDAP_OTHER; 
342                 errstr = "internal error";      
343         } else if (count == -1) {
344                 DEBUG(10,("rootdse_Search: error\n"));
345                 result = LDAP_OTHER;
346                 errstr = ldb_errstring(ldb);
347         }
348
349         done = &done_r->msg->r.SearchResultDone;
350         done->dn = NULL;
351         done->resultcode = result;
352         done->errormessage = (errstr?talloc_strdup(done_r,errstr):NULL);;
353         done->referral = NULL;
354
355         talloc_free(local_ctx);
356
357         ldapsrv_queue_reply(call, done_r);
358         return NT_STATUS_OK;
359 }
360
361 static const struct ldapsrv_partition_ops rootdse_ops = {
362         .Search         = rootdse_Search
363 };
364
365 const struct ldapsrv_partition_ops *ldapsrv_get_rootdse_partition_ops(void)
366 {
367         return &rootdse_ops;
368 }