987fd7a7f1c6444dbdf4680b58a426a4e3d23886
[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 "system/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 /*
48   add dynamically generated attributes to rootDSE result
49 */
50 static int rootdse_add_dynamic(struct ldb_module *module, struct ldb_request *req)
51 {
52         struct private_data *priv = talloc_get_type(module->private_data, struct private_data);
53         struct ldb_search *s = &req->op.search;
54         struct ldb_message *msg;
55         struct cli_credentials *server_creds;
56
57         /* this is gross, and will be removed when I change ldb_result not
58            to be so pointer crazy :-) */
59         if (s->res->msgs == NULL) {
60                 return LDB_SUCCESS;
61         }
62
63         msg = s->res->msgs[0];
64
65         msg->dn = ldb_dn_explode(msg, "");
66
67         if (do_attribute(s->attrs, "currentTime")) {
68                 if (ldb_msg_add_steal_string(msg, "currentTime", 
69                                              ldb_timestring(msg, time(NULL))) != 0) {
70                         goto failed;
71                 }
72         }
73
74         if (do_attribute(s->attrs, "supportedControl")) {
75                 int i;
76                 for (i = 0; i < priv->num_controls; i++) {
77                         char *control = talloc_strdup(msg, priv->controls[i]);
78                         if (!control) {
79                                 goto failed;
80                         }
81                         if (ldb_msg_add_steal_string(msg, "supportedControl",
82                                                      control) != 0) {
83                                 goto failed;
84                         }
85                 }
86         }
87
88         server_creds = talloc_get_type(ldb_get_opaque(module->ldb, "server_credentials"), 
89                                        struct cli_credentials);
90         if (server_creds && do_attribute(s->attrs, "supportedSASLMechanisms")) {
91                 struct gensec_security_ops **backends = gensec_security_all();
92                 enum credentials_use_kerberos use_kerberos
93                         = cli_credentials_get_kerberos_state(server_creds);
94                 struct gensec_security_ops **ops
95                         = gensec_use_kerberos_mechs(req, backends, use_kerberos);
96                 int i;
97                 for (i = 0; ops && ops[i]; i++) {
98                         if (ops[i]->sasl_name) {
99                                 char *sasl_name = talloc_strdup(msg, ops[i]->sasl_name);
100                                 if (!sasl_name) {
101                                         goto failed;
102                                 }
103                                 if (ldb_msg_add_steal_string(msg, "supportedSASLMechanisms",
104                                                              sasl_name) != 0) {
105                                         goto failed;
106                                 }
107                         }
108                 }
109         }
110
111         if (do_attribute(s->attrs, "highestCommittedUSN")) {
112                 if (module->ldb->sequence_number != NULL && 
113                     ldb_msg_add_fmt(msg, "highestCommittedUSN", 
114                                     "%llu", module->ldb->sequence_number(module->ldb)) != 0) {
115                         goto failed;
116                 }
117         }
118         
119         /* TODO: lots more dynamic attributes should be added here */
120
121         return 0;
122
123 failed:
124         return LDB_ERR_OPERATIONS_ERROR;
125 }
126
127 /*
128   handle search requests
129 */
130 static int rootdse_search_bytree(struct ldb_module *module, struct ldb_request *req)
131 {
132         struct ldb_search *s = &req->op.search;
133         int ret;
134         TALLOC_CTX *tmp_ctx;
135
136         /* see if its for the rootDSE */
137         if (s->scope != LDB_SCOPE_BASE ||
138             (s->base && s->base->comp_num != 0)) {
139                 return ldb_next_request(module, req);
140         }
141
142         tmp_ctx = talloc_new(module);
143
144         /* in our db we store the rootDSE with a DN of cn=rootDSE */
145         s->base = ldb_dn_explode(tmp_ctx, "cn=rootDSE");
146         s->tree = ldb_parse_tree(tmp_ctx, "dn=*");
147         if (s->base == NULL || s->tree == NULL) {
148                 ldb_oom(module->ldb);
149                 talloc_free(tmp_ctx);
150                 return LDB_ERR_OPERATIONS_ERROR;
151         }
152
153         /* grab the static contents of the record */
154         ret = ldb_next_request(module, req);
155
156         req->op.search.res = s->res;
157
158         if (ret == LDB_SUCCESS) {
159                 ret = rootdse_add_dynamic(module, req);
160         }
161
162         talloc_free(tmp_ctx);
163
164         return ret;
165 }
166
167 static int rootdse_register_control(struct ldb_module *module, struct ldb_request *req)
168 {
169         struct private_data *priv = talloc_get_type(module->private_data, struct private_data);
170         char **list;
171
172         list = talloc_realloc(priv, priv->controls, char *, priv->num_controls + 1);
173         if (!list) {
174                 return LDB_ERR_OPERATIONS_ERROR;
175         }
176
177         list[priv->num_controls] = talloc_strdup(list, req->op.reg.oid);
178         if (!list[priv->num_controls]) {
179                 return LDB_ERR_OPERATIONS_ERROR;
180         }
181
182         priv->num_controls += 1;
183         priv->controls = list;
184
185         return LDB_SUCCESS;
186 }
187  
188
189 static int rootdse_request(struct ldb_module *module, struct ldb_request *req)
190 {
191         switch (req->operation) {
192         case LDB_REQ_SEARCH:
193                 return rootdse_search_bytree(module, req);
194         case LDB_REQ_REGISTER:
195                 return rootdse_register_control(module, req);
196         default:
197                 break;
198         }
199         return ldb_next_request(module, req);
200 }
201
202 static const struct ldb_module_ops rootdse_ops = {
203         .name           = "rootdse",
204         .request        = rootdse_request
205 };
206
207 struct ldb_module *rootdse_module_init(struct ldb_context *ldb, const char *options[])
208 {
209         struct ldb_module *ctx;
210         struct private_data *data;
211
212         ctx = talloc(ldb, struct ldb_module);
213         if (!ctx)
214                 return NULL;
215
216         data = talloc(ctx, struct private_data);
217         if (data == NULL) {
218                 talloc_free(ctx);
219                 return NULL;
220         }
221
222         data->num_controls = 0;
223         data->controls = NULL;
224         ctx->private_data = data;
225
226         ctx->ldb = ldb;
227         ctx->prev = ctx->next = NULL;
228         ctx->ops = &rootdse_ops;
229
230         return ctx;
231 }
232