264a6b39eeb96c89e7a3ceb5b69fa0fb0249c5b0
[kai/samba.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/credentials/credentials.h"
30 #include "lib/stream/packet.h"
31 #include "param/param.h"
32
33 struct ldap_simple_creds {
34         const char *dn;
35         const char *pw;
36 };
37
38 NTSTATUS ldap_rebind(struct ldap_connection *conn)
39 {
40         NTSTATUS status;
41         struct ldap_simple_creds *creds;
42
43         switch (conn->bind.type) {
44         case LDAP_BIND_SASL:
45                 status = ldap_bind_sasl(conn, (struct cli_credentials *)conn->bind.creds,
46                                         conn->lp_ctx);
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                         struct loadparm_context *lp_ctx)
205 {
206         NTSTATUS status;
207         TALLOC_CTX *tmp_ctx = NULL;
208
209         DATA_BLOB input = data_blob(NULL, 0);
210         DATA_BLOB output = data_blob(NULL, 0);
211
212         struct ldap_message **sasl_mechs_msgs;
213         struct ldap_SearchResEntry *search;
214         int count, i;
215
216         const char **sasl_names;
217         uint32_t old_gensec_features;
218         const char *supported_sasl_mech_attrs[] = {
219                 "supportedSASLMechanisms", 
220                 NULL 
221         };
222
223         gensec_init(lp_ctx);
224
225         status = gensec_client_start(conn, &conn->gensec, NULL, lp_ctx);
226         if (!NT_STATUS_IS_OK(status)) {
227                 DEBUG(0, ("Failed to start GENSEC engine (%s)\n", nt_errstr(status)));
228                 goto failed;
229         }
230
231         /* require Kerberos SIGN/SEAL only if we don't use SSL
232          * Windows seem not to like double encryption */
233         old_gensec_features = cli_credentials_get_gensec_features(creds);
234         if (tls_enabled(conn->sock)) {
235                 cli_credentials_set_gensec_features(creds, 0);
236         }
237
238         /* this call also sets the gensec_want_features */
239         status = gensec_set_credentials(conn->gensec, creds);
240         if (!NT_STATUS_IS_OK(status)) {
241                 DEBUG(1, ("Failed to set GENSEC creds: %s\n", 
242                           nt_errstr(status)));
243                 goto failed;
244         }
245
246         /* reset the original gensec_features */
247         cli_credentials_set_gensec_features(creds, old_gensec_features);
248
249         if (conn->host) {
250                 status = gensec_set_target_hostname(conn->gensec, conn->host);
251                 if (!NT_STATUS_IS_OK(status)) {
252                         DEBUG(1, ("Failed to set GENSEC target hostname: %s\n", 
253                                   nt_errstr(status)));
254                         goto failed;
255                 }
256         }
257
258         status = gensec_set_target_service(conn->gensec, "ldap");
259         if (!NT_STATUS_IS_OK(status)) {
260                 DEBUG(1, ("Failed to set GENSEC target service: %s\n", 
261                           nt_errstr(status)));
262                 goto failed;
263         }
264
265         status = ildap_search(conn, "", LDAP_SEARCH_SCOPE_BASE, "", supported_sasl_mech_attrs, 
266                               false, NULL, NULL, &sasl_mechs_msgs);
267         if (!NT_STATUS_IS_OK(status)) {
268                 DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: %s\n", 
269                           nt_errstr(status)));
270                 goto failed;
271         }
272         
273         count = ildap_count_entries(conn, sasl_mechs_msgs);
274         if (count != 1) {
275                 DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: wrong number of replies: %d\n",
276                           count));
277                 goto failed;
278         }
279
280         tmp_ctx = talloc_new(conn);
281         if (tmp_ctx == NULL) goto failed;
282
283         search = &sasl_mechs_msgs[0]->r.SearchResultEntry;
284         if (search->num_attributes != 1) {
285                 DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: wrong number of attributes: %d\n",
286                           search->num_attributes));
287                 goto failed;
288         }
289
290         sasl_names = talloc_array(tmp_ctx, const char *, search->attributes[0].num_values + 1);
291         if (!sasl_names) {
292                 DEBUG(1, ("talloc_arry(char *, %d) failed\n",
293                           count));
294                 goto failed;
295         }
296                 
297         for (i=0; i<search->attributes[0].num_values; i++) {
298                 sasl_names[i] = (const char *)search->attributes[0].values[i].data;
299         }
300         sasl_names[i] = NULL;
301         
302         status = gensec_start_mech_by_sasl_list(conn->gensec, sasl_names);
303         if (!NT_STATUS_IS_OK(status)) {
304                 DEBUG(1, ("None of the %d proposed SASL mechs were acceptable: %s\n",
305                           count, nt_errstr(status)));
306                 goto failed;
307         }
308
309         while (1) {
310                 NTSTATUS gensec_status;
311                 struct ldap_message *response;
312                 struct ldap_message *msg;
313                 struct ldap_request *req;
314                 int result = LDAP_OTHER;
315         
316                 status = gensec_update(conn->gensec, tmp_ctx,
317                                        input,
318                                        &output);
319                 /* The status value here, from GENSEC is vital to the security
320                  * of the system.  Even if the other end accepts, if GENSEC
321                  * claims 'MORE_PROCESSING_REQUIRED' then you must keep
322                  * feeding it blobs, or else the remote host/attacker might
323                  * avoid mutal authentication requirements.
324                  *
325                  * Likewise, you must not feed GENSEC too much (after the OK),
326                  * it doesn't like that either
327                  */
328
329                 gensec_status = status;
330
331                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && 
332                     !NT_STATUS_IS_OK(status)) {
333                         break;
334                 }
335                 if (NT_STATUS_IS_OK(status) && output.length == 0) {
336                         break;
337                 }
338
339                 /* Perhaps we should make gensec_start_mech_by_sasl_list() return the name we got? */
340                 msg = new_ldap_sasl_bind_msg(tmp_ctx, conn->gensec->ops->sasl_name, (output.data?&output:NULL));
341                 if (msg == NULL) {
342                         status = NT_STATUS_NO_MEMORY;
343                         goto failed;
344                 }
345
346                 req = ldap_request_send(conn, msg);
347                 if (req == NULL) {
348                         status = NT_STATUS_NO_MEMORY;
349                         goto failed;
350                 }
351                 talloc_steal(tmp_ctx, req);
352
353                 status = ldap_result_n(req, 0, &response);
354                 if (!NT_STATUS_IS_OK(status)) {
355                         goto failed;
356                 }
357                 
358                 if (response->type != LDAP_TAG_BindResponse) {
359                         status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
360                         goto failed;
361                 }
362
363                 result = response->r.BindResponse.response.resultcode;
364
365                 if (result != LDAP_SUCCESS && result != LDAP_SASL_BIND_IN_PROGRESS) {
366                         status = ldap_check_response(conn, 
367                                                      &response->r.BindResponse.response);
368                         break;
369                 }
370
371                 /* This is where we check if GENSEC wanted to be fed more data */
372                 if (!NT_STATUS_EQUAL(gensec_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
373                         break;
374                 }
375                 if (response->r.BindResponse.SASL.secblob) {
376                         input = *response->r.BindResponse.SASL.secblob;
377                 } else {
378                         input = data_blob(NULL, 0);
379                 }
380         }
381
382         talloc_free(tmp_ctx);
383
384         if (NT_STATUS_IS_OK(status)) {
385                 struct socket_context *sasl_socket;
386                 status = gensec_socket_init(conn->gensec, 
387                                             conn->sock,
388                                             conn->event.event_ctx, 
389                                             ldap_read_io_handler,
390                                             conn,
391                                             &sasl_socket);
392                 if (!NT_STATUS_IS_OK(status)) goto failed;
393
394                 talloc_steal(conn->sock, sasl_socket);
395                 talloc_unlink(conn, conn->sock);
396                 conn->sock = sasl_socket;
397                 packet_set_socket(conn->packet, conn->sock);
398
399                 conn->bind.type = LDAP_BIND_SASL;
400                 conn->bind.creds = creds;
401         }
402
403         return status;
404
405 failed:
406         talloc_free(tmp_ctx);
407         talloc_free(conn->gensec);
408         conn->gensec = NULL;
409         return status;
410 }