r12733: Merge ldap/ldb controls into main tree
[ira/wip.git] / source4 / dsdb / samdb / ldb_modules / rootdse.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    rootDSE ldb module
5
6    Copyright (C) Andrew Tridgell 2005
7    Copyright (C) Simo Sorce 2005
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "lib/ldb/include/ldb.h"
26 #include "lib/ldb/include/ldb_errors.h"
27 #include "lib/ldb/include/ldb_private.h"
28 #include "auth/gensec/gensec.h"
29 #include <time.h>
30
31 struct private_data {
32         int num_controls;
33         char **controls;
34 };
35
36 /*
37   return 1 if a specific attribute has been requested
38 */
39 static int do_attribute(const char * const *attrs, const char *name)
40 {
41         return attrs == NULL ||
42                 ldb_attr_in_list(attrs, name) ||
43                 ldb_attr_in_list(attrs, "*");
44 }
45
46 /*
47   add dynamically generated attributes to rootDSE result
48 */
49 static int rootdse_add_dynamic(struct ldb_module *module, struct ldb_request *req)
50 {
51         struct private_data *priv = talloc_get_type(module->private_data, struct private_data);
52         struct ldb_search *s = &req->op.search;
53         struct ldb_message *msg;
54         struct cli_credentials *server_creds;
55
56         /* this is gross, and will be removed when I change ldb_result not
57            to be so pointer crazy :-) */
58         if (s->res->msgs == NULL) {
59                 return LDB_SUCCESS;
60         }
61
62         msg = s->res->msgs[0];
63
64         msg->dn = ldb_dn_explode(msg, "");
65
66         if (do_attribute(s->attrs, "currentTime")) {
67                 if (ldb_msg_add_string(msg, "currentTime", 
68                                        ldb_timestring(msg, time(NULL))) != 0) {
69                         goto failed;
70                 }
71         }
72
73         if (do_attribute(s->attrs, "supportedControl")) {
74                 int i;
75                 for (i = 0; i < priv->num_controls; i++) {
76                         if (ldb_msg_add_string(msg, "supportedControl",
77                                                 priv->controls[i]) != 0) {
78                                 goto failed;
79                         }
80                 }
81         }
82
83         server_creds = talloc_get_type(ldb_get_opaque(module->ldb, "server_credentials"), 
84                                        struct cli_credentials);
85         if (do_attribute(s->attrs, "supportedSASLMechanisms")) {
86                 const struct gensec_security_ops **ops = cli_credentials_gensec_list(server_creds);
87                 int i;
88                 for (i = 0; ops && ops[i]; i++) {
89                         if (ops[i]->sasl_name) {
90                                 const char *sasl_name = talloc_strdup(msg, ops[i]->sasl_name);
91                                 if (!sasl_name) {
92                                         goto failed;
93                                 }
94                                 if (ldb_msg_add_string(msg, "supportedSASLMechanisms",
95                                                        sasl_name) != 0) {
96                                         goto failed;
97                                 }
98                         }
99                 }
100         }
101         
102         /* TODO: lots more dynamic attributes should be added here */
103
104         return 0;
105
106 failed:
107         return LDB_ERR_OPERATIONS_ERROR;
108 }
109
110 /*
111   handle search requests
112 */
113 static int rootdse_search_bytree(struct ldb_module *module, struct ldb_request *req)
114 {
115         struct ldb_search *s = &req->op.search;
116         int ret;
117         TALLOC_CTX *tmp_ctx;
118
119         /* see if its for the rootDSE */
120         if (s->scope != LDB_SCOPE_BASE ||
121             (s->base && s->base->comp_num != 0)) {
122                 return ldb_next_request(module, req);
123         }
124
125         tmp_ctx = talloc_new(module);
126
127         /* in our db we store the rootDSE with a DN of cn=rootDSE */
128         s->base = ldb_dn_explode(tmp_ctx, "cn=rootDSE");
129         s->tree = ldb_parse_tree(tmp_ctx, "dn=*");
130         if (s->base == NULL || s->tree == NULL) {
131                 ldb_oom(module->ldb);
132                 talloc_free(tmp_ctx);
133                 return LDB_ERR_OPERATIONS_ERROR;
134         }
135
136         /* grab the static contents of the record */
137         ret = ldb_next_request(module, req);
138
139         req->op.search.res = s->res;
140
141         if (ret == LDB_SUCCESS) {
142                 ret = rootdse_add_dynamic(module, req);
143         }
144
145         talloc_free(tmp_ctx);
146
147         return ret;
148 }
149
150 static int rootdse_register_control(struct ldb_module *module, struct ldb_request *req)
151 {
152         struct private_data *priv = talloc_get_type(module->private_data, struct private_data);
153         char **list;
154
155         list = talloc_realloc(priv, priv->controls, char *, priv->num_controls + 1);
156         if (!list) {
157                 return LDB_ERR_OPERATIONS_ERROR;
158         }
159
160         list[priv->num_controls] = talloc_strdup(list, req->op.reg.oid);
161         if (!list[priv->num_controls]) {
162                 return LDB_ERR_OPERATIONS_ERROR;
163         }
164
165         priv->num_controls += 1;
166         priv->controls = list;
167
168         return LDB_SUCCESS;
169 }
170  
171
172 static int rootdse_request(struct ldb_module *module, struct ldb_request *req)
173 {
174         switch (req->operation) {
175         case LDB_REQ_SEARCH:
176                 return rootdse_search_bytree(module, req);
177         case LDB_REQ_REGISTER:
178                 return rootdse_register_control(module, req);
179         default:
180                 break;
181         }
182         return ldb_next_request(module, req);
183 }
184
185 static const struct ldb_module_ops rootdse_ops = {
186         .name           = "rootdse",
187         .request        = rootdse_request
188 };
189
190 struct ldb_module *rootdse_module_init(struct ldb_context *ldb, int stage, const char *options[])
191 {
192         struct ldb_module *ctx;
193         struct private_data *data;
194
195         if (stage != LDB_MODULES_INIT_STAGE_1) return NULL;
196
197         ctx = talloc(ldb, struct ldb_module);
198         if (!ctx)
199                 return NULL;
200
201         data = talloc(ctx, struct private_data);
202         if (data == NULL) {
203                 talloc_free(ctx);
204                 return NULL;
205         }
206
207         data->num_controls = 0;
208         data->controls = NULL;
209         ctx->private_data = data;
210
211         ctx->ldb = ldb;
212         ctx->prev = ctx->next = NULL;
213         ctx->ops = &rootdse_ops;
214
215         return ctx;
216 }
217