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