r26277: Move loadparm context higher up the stack.
[metze/samba/wip.git] / source4 / libcli / ldap / ldap_bind.c
1 /* 
2    Unix SMB/CIFS mplementation.
3
4    LDAP bind calls
5    
6    Copyright (C) Andrew Tridgell  2005
7    Copyright (C) Volker Lendecke  2004
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 3 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, see <http://www.gnu.org/licenses/>.
21    
22 */
23
24 #include "includes.h"
25 #include "libcli/ldap/ldap.h"
26 #include "libcli/ldap/ldap_client.h"
27 #include "lib/tls/tls.h"
28 #include "auth/gensec/gensec.h"
29 #include "auth/gensec/socket.h"
30 #include "auth/credentials/credentials.h"
31 #include "lib/stream/packet.h"
32 #include "param/param.h"
33
34 struct ldap_simple_creds {
35         const char *dn;
36         const char *pw;
37 };
38
39 NTSTATUS ldap_rebind(struct ldap_connection *conn)
40 {
41         NTSTATUS status;
42         struct ldap_simple_creds *creds;
43
44         switch (conn->bind.type) {
45         case LDAP_BIND_SASL:
46                 status = ldap_bind_sasl(conn, (struct cli_credentials *)conn->bind.creds);
47                 break;
48                 
49         case LDAP_BIND_SIMPLE:
50                 creds = (struct ldap_simple_creds *)conn->bind.creds;
51
52                 if (creds == NULL) {
53                         return NT_STATUS_UNSUCCESSFUL;
54                 }
55
56                 status = ldap_bind_simple(conn, creds->dn, creds->pw);
57                 break;
58
59         default:
60                 return NT_STATUS_UNSUCCESSFUL;
61         }
62
63         return status;
64 }
65
66
67 static struct ldap_message *new_ldap_simple_bind_msg(struct ldap_connection *conn, 
68                                                      const char *dn, const char *pw)
69 {
70         struct ldap_message *res;
71
72         res = new_ldap_message(conn);
73         if (!res) {
74                 return NULL;
75         }
76
77         res->type = LDAP_TAG_BindRequest;
78         res->r.BindRequest.version = 3;
79         res->r.BindRequest.dn = talloc_strdup(res, dn);
80         res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SIMPLE;
81         res->r.BindRequest.creds.password = talloc_strdup(res, pw);
82         res->controls = NULL;
83
84         return res;
85 }
86
87
88 /*
89   perform a simple username/password bind
90 */
91 NTSTATUS ldap_bind_simple(struct ldap_connection *conn, 
92                           const char *userdn, const char *password)
93 {
94         struct ldap_request *req;
95         struct ldap_message *msg;
96         const char *dn, *pw;
97         NTSTATUS status;
98
99         if (conn == NULL) {
100                 return NT_STATUS_INVALID_CONNECTION;
101         }
102
103         if (userdn) {
104                 dn = userdn;
105         } else {
106                 if (conn->auth_dn) {
107                         dn = conn->auth_dn;
108                 } else {
109                         dn = "";
110                 }
111         }
112
113         if (password) {
114                 pw = password;
115         } else {
116                 if (conn->simple_pw) {
117                         pw = conn->simple_pw;
118                 } else {
119                         pw = "";
120                 }
121         }
122
123         msg = new_ldap_simple_bind_msg(conn, dn, pw);
124         NT_STATUS_HAVE_NO_MEMORY(msg);
125
126         /* send the request */
127         req = ldap_request_send(conn, msg);
128         talloc_free(msg);
129         NT_STATUS_HAVE_NO_MEMORY(req);
130
131         /* wait for replies */
132         status = ldap_request_wait(req);
133         if (!NT_STATUS_IS_OK(status)) {
134                 talloc_free(req);
135                 return status;
136         }
137
138         /* check its a valid reply */
139         msg = req->replies[0];
140         if (msg->type != LDAP_TAG_BindResponse) {
141                 talloc_free(req);
142                 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
143         }
144
145         status = ldap_check_response(conn, &msg->r.BindResponse.response);
146
147         talloc_free(req);
148
149         if (NT_STATUS_IS_OK(status)) {
150                 struct ldap_simple_creds *creds = talloc(conn, struct ldap_simple_creds);
151                 if (creds == NULL) {
152                         return NT_STATUS_NO_MEMORY;
153                 }
154                 creds->dn = talloc_strdup(creds, dn);
155                 creds->pw = talloc_strdup(creds, pw);
156                 if (creds->dn == NULL || creds->pw == NULL) {
157                         return NT_STATUS_NO_MEMORY;
158                 }
159                 conn->bind.type = LDAP_BIND_SIMPLE;
160                 conn->bind.creds = creds;
161         }
162
163         return status;
164 }
165
166
167 static struct ldap_message *new_ldap_sasl_bind_msg(struct ldap_connection *conn, 
168                                                    const char *sasl_mechanism, 
169                                                    DATA_BLOB *secblob)
170 {
171         struct ldap_message *res;
172
173         res = new_ldap_message(conn);
174         if (!res) {
175                 return NULL;
176         }
177
178         res->type = LDAP_TAG_BindRequest;
179         res->r.BindRequest.version = 3;
180         res->r.BindRequest.dn = "";
181         res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SASL;
182         res->r.BindRequest.creds.SASL.mechanism = talloc_strdup(res, sasl_mechanism);
183         if (secblob) {
184                 res->r.BindRequest.creds.SASL.secblob = talloc(res, DATA_BLOB);
185                 if (!res->r.BindRequest.creds.SASL.secblob) {
186                         talloc_free(res);
187                         return NULL;
188                 }
189                 *res->r.BindRequest.creds.SASL.secblob = *secblob;
190         } else {
191                 res->r.BindRequest.creds.SASL.secblob = NULL;
192         }
193         res->controls = NULL;
194
195         return res;
196 }
197
198
199 /*
200   perform a sasl bind using the given credentials
201 */
202 NTSTATUS ldap_bind_sasl(struct ldap_connection *conn, 
203                         struct cli_credentials *creds)
204 {
205         NTSTATUS status;
206         TALLOC_CTX *tmp_ctx = NULL;
207
208         DATA_BLOB input = data_blob(NULL, 0);
209         DATA_BLOB output = data_blob(NULL, 0);
210
211         struct ldap_message **sasl_mechs_msgs;
212         struct ldap_SearchResEntry *search;
213         int count, i;
214
215         const char **sasl_names;
216         uint32_t old_gensec_features;
217         static const char *supported_sasl_mech_attrs[] = {
218                 "supportedSASLMechanisms", 
219                 NULL 
220         };
221
222         status = gensec_client_start(conn, &conn->gensec, NULL, global_loadparm);
223         if (!NT_STATUS_IS_OK(status)) {
224                 DEBUG(0, ("Failed to start GENSEC engine (%s)\n", nt_errstr(status)));
225                 goto failed;
226         }
227
228         /* require Kerberos SIGN/SEAL only if we don't use SSL
229          * Windows seem not to like double encryption */
230         old_gensec_features = cli_credentials_get_gensec_features(creds);
231         if (tls_enabled(conn->sock)) {
232                 cli_credentials_set_gensec_features(creds, 0);
233         }
234
235         /* this call also sets the gensec_want_features */
236         status = gensec_set_credentials(conn->gensec, creds);
237         if (!NT_STATUS_IS_OK(status)) {
238                 DEBUG(1, ("Failed to set GENSEC creds: %s\n", 
239                           nt_errstr(status)));
240                 goto failed;
241         }
242
243         /* reset the original gensec_features */
244         cli_credentials_set_gensec_features(creds, old_gensec_features);
245
246         if (conn->host) {
247                 status = gensec_set_target_hostname(conn->gensec, conn->host);
248                 if (!NT_STATUS_IS_OK(status)) {
249                         DEBUG(1, ("Failed to set GENSEC target hostname: %s\n", 
250                                   nt_errstr(status)));
251                         goto failed;
252                 }
253         }
254
255         status = gensec_set_target_service(conn->gensec, "ldap");
256         if (!NT_STATUS_IS_OK(status)) {
257                 DEBUG(1, ("Failed to set GENSEC target service: %s\n", 
258                           nt_errstr(status)));
259                 goto failed;
260         }
261
262         status = ildap_search(conn, "", LDAP_SEARCH_SCOPE_BASE, "", supported_sasl_mech_attrs, 
263                               false, NULL, NULL, &sasl_mechs_msgs);
264         if (!NT_STATUS_IS_OK(status)) {
265                 DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: %s\n", 
266                           nt_errstr(status)));
267                 goto failed;
268         }
269         
270         count = ildap_count_entries(conn, sasl_mechs_msgs);
271         if (count != 1) {
272                 DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: wrong number of replies: %d\n",
273                           count));
274                 goto failed;
275         }
276
277         tmp_ctx = talloc_new(conn);
278         if (tmp_ctx == NULL) goto failed;
279
280         search = &sasl_mechs_msgs[0]->r.SearchResultEntry;
281         if (search->num_attributes != 1) {
282                 DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: wrong number of attributes: %d\n",
283                           search->num_attributes));
284                 goto failed;
285         }
286
287         sasl_names = talloc_array(tmp_ctx, const char *, search->attributes[0].num_values + 1);
288         if (!sasl_names) {
289                 DEBUG(1, ("talloc_arry(char *, %d) failed\n",
290                           count));
291                 goto failed;
292         }
293                 
294         for (i=0; i<search->attributes[0].num_values; i++) {
295                 sasl_names[i] = (const char *)search->attributes[0].values[i].data;
296         }
297         sasl_names[i] = NULL;
298         
299         status = gensec_start_mech_by_sasl_list(conn->gensec, sasl_names);
300         if (!NT_STATUS_IS_OK(status)) {
301                 DEBUG(1, ("None of the %d proposed SASL mechs were acceptable: %s\n",
302                           count, nt_errstr(status)));
303                 goto failed;
304         }
305
306         while (1) {
307                 NTSTATUS gensec_status;
308                 struct ldap_message *response;
309                 struct ldap_message *msg;
310                 struct ldap_request *req;
311                 int result = LDAP_OTHER;
312         
313                 status = gensec_update(conn->gensec, tmp_ctx,
314                                        input,
315                                        &output);
316                 /* The status value here, from GENSEC is vital to the security
317                  * of the system.  Even if the other end accepts, if GENSEC
318                  * claims 'MORE_PROCESSING_REQUIRED' then you must keep
319                  * feeding it blobs, or else the remote host/attacker might
320                  * avoid mutal authentication requirements.
321                  *
322                  * Likewise, you must not feed GENSEC too much (after the OK),
323                  * it doesn't like that either
324                  */
325
326                 gensec_status = status;
327
328                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && 
329                     !NT_STATUS_IS_OK(status)) {
330                         break;
331                 }
332                 if (NT_STATUS_IS_OK(status) && output.length == 0) {
333                         break;
334                 }
335
336                 /* Perhaps we should make gensec_start_mech_by_sasl_list() return the name we got? */
337                 msg = new_ldap_sasl_bind_msg(tmp_ctx, conn->gensec->ops->sasl_name, (output.data?&output:NULL));
338                 if (msg == NULL) {
339                         status = NT_STATUS_NO_MEMORY;
340                         goto failed;
341                 }
342
343                 req = ldap_request_send(conn, msg);
344                 if (req == NULL) {
345                         status = NT_STATUS_NO_MEMORY;
346                         goto failed;
347                 }
348                 talloc_steal(tmp_ctx, req);
349
350                 status = ldap_result_n(req, 0, &response);
351                 if (!NT_STATUS_IS_OK(status)) {
352                         goto failed;
353                 }
354                 
355                 if (response->type != LDAP_TAG_BindResponse) {
356                         status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
357                         goto failed;
358                 }
359
360                 result = response->r.BindResponse.response.resultcode;
361
362                 if (result != LDAP_SUCCESS && result != LDAP_SASL_BIND_IN_PROGRESS) {
363                         status = ldap_check_response(conn, 
364                                                      &response->r.BindResponse.response);
365                         break;
366                 }
367
368                 /* This is where we check if GENSEC wanted to be fed more data */
369                 if (!NT_STATUS_EQUAL(gensec_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
370                         break;
371                 }
372                 if (response->r.BindResponse.SASL.secblob) {
373                         input = *response->r.BindResponse.SASL.secblob;
374                 } else {
375                         input = data_blob(NULL, 0);
376                 }
377         }
378
379         talloc_free(tmp_ctx);
380
381         if (NT_STATUS_IS_OK(status)) {
382                 struct socket_context *sasl_socket;
383                 status = gensec_socket_init(conn->gensec, 
384                                             conn->sock,
385                                             conn->event.event_ctx, 
386                                             ldap_read_io_handler,
387                                             conn,
388                                             &sasl_socket);
389                 if (!NT_STATUS_IS_OK(status)) goto failed;
390
391                 talloc_steal(conn->sock, sasl_socket);
392                 talloc_unlink(conn, conn->sock);
393                 conn->sock = sasl_socket;
394                 packet_set_socket(conn->packet, conn->sock);
395
396                 conn->bind.type = LDAP_BIND_SASL;
397                 conn->bind.creds = creds;
398         }
399
400         return status;
401
402 failed:
403         talloc_free(tmp_ctx);
404         talloc_free(conn->gensec);
405         conn->gensec = NULL;
406         return status;
407 }