5f5b362c536a0c2fd9a3662a88b1e9f161e43bdd
[samba.git] / source / 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   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 (server_creds && do_attribute(s->attrs, "supportedSASLMechanisms")) {
86                 struct gensec_security_ops **backends = gensec_security_all();
87                 enum credentials_use_kerberos use_kerberos
88                         = cli_credentials_get_kerberos_state(server_creds);
89                 struct gensec_security_ops **ops
90                         = gensec_use_kerberos_mechs(req, backends, use_kerberos);
91                 int i;
92                 for (i = 0; ops && ops[i]; i++) {
93                         if (ops[i]->sasl_name) {
94                                 const char *sasl_name = talloc_strdup(msg, ops[i]->sasl_name);
95                                 if (!sasl_name) {
96                                         goto failed;
97                                 }
98                                 if (ldb_msg_add_string(msg, "supportedSASLMechanisms",
99                                                        sasl_name) != 0) {
100                                         goto failed;
101                                 }
102                         }
103                 }
104         }
105         
106         /* TODO: lots more dynamic attributes should be added here */
107
108         return 0;
109
110 failed:
111         return LDB_ERR_OPERATIONS_ERROR;
112 }
113
114 /*
115   handle search requests
116 */
117 static int rootdse_search_bytree(struct ldb_module *module, struct ldb_request *req)
118 {
119         struct ldb_search *s = &req->op.search;
120         int ret;
121         TALLOC_CTX *tmp_ctx;
122
123         /* see if its for the rootDSE */
124         if (s->scope != LDB_SCOPE_BASE ||
125             (s->base && s->base->comp_num != 0)) {
126                 return ldb_next_request(module, req);
127         }
128
129         tmp_ctx = talloc_new(module);
130
131         /* in our db we store the rootDSE with a DN of cn=rootDSE */
132         s->base = ldb_dn_explode(tmp_ctx, "cn=rootDSE");
133         s->tree = ldb_parse_tree(tmp_ctx, "dn=*");
134         if (s->base == NULL || s->tree == NULL) {
135                 ldb_oom(module->ldb);
136                 talloc_free(tmp_ctx);
137                 return LDB_ERR_OPERATIONS_ERROR;
138         }
139
140         /* grab the static contents of the record */
141         ret = ldb_next_request(module, req);
142
143         req->op.search.res = s->res;
144
145         if (ret == LDB_SUCCESS) {
146                 ret = rootdse_add_dynamic(module, req);
147         }
148
149         talloc_free(tmp_ctx);
150
151         return ret;
152 }
153
154 static int rootdse_register_control(struct ldb_module *module, struct ldb_request *req)
155 {
156         struct private_data *priv = talloc_get_type(module->private_data, struct private_data);
157         char **list;
158
159         list = talloc_realloc(priv, priv->controls, char *, priv->num_controls + 1);
160         if (!list) {
161                 return LDB_ERR_OPERATIONS_ERROR;
162         }
163
164         list[priv->num_controls] = talloc_strdup(list, req->op.reg.oid);
165         if (!list[priv->num_controls]) {
166                 return LDB_ERR_OPERATIONS_ERROR;
167         }
168
169         priv->num_controls += 1;
170         priv->controls = list;
171
172         return LDB_SUCCESS;
173 }
174  
175
176 static int rootdse_request(struct ldb_module *module, struct ldb_request *req)
177 {
178         switch (req->operation) {
179         case LDB_REQ_SEARCH:
180                 return rootdse_search_bytree(module, req);
181         case LDB_REQ_REGISTER:
182                 return rootdse_register_control(module, req);
183         default:
184                 break;
185         }
186         return ldb_next_request(module, req);
187 }
188
189 static const struct ldb_module_ops rootdse_ops = {
190         .name           = "rootdse",
191         .request        = rootdse_request
192 };
193
194 struct ldb_module *rootdse_module_init(struct ldb_context *ldb, const char *options[])
195 {
196         struct ldb_module *ctx;
197         struct private_data *data;
198
199         ctx = talloc(ldb, struct ldb_module);
200         if (!ctx)
201                 return NULL;
202
203         data = talloc(ctx, struct private_data);
204         if (data == NULL) {
205                 talloc_free(ctx);
206                 return NULL;
207         }
208
209         data->num_controls = 0;
210         data->controls = NULL;
211         ctx->private_data = data;
212
213         ctx->ldb = ldb;
214         ctx->prev = ctx->next = NULL;
215         ctx->ops = &rootdse_ops;
216
217         return ctx;
218 }
219