r4460: Add a new GENSEC module: gensec_gssapi
[samba.git] / source / libcli / ldap / ldap_client.c
1 /* 
2    Unix SMB/CIFS mplementation.
3    LDAP protocol helper functions for SAMBA
4    
5    Copyright (C) Andrew Tridgell  2004
6    Copyright (C) Volker Lendecke 2004
7    Copyright (C) Stefan Metzmacher 2004
8    Copyright (C) Simo Sorce 2004
9     
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23    
24 */
25
26 #include "includes.h"
27 #include "system/network.h"
28 #include "auth/auth.h"
29 #include "asn_1.h"
30 #include "dlinklist.h"
31
32 #if 0
33 static struct ldap_message *new_ldap_search_message(struct ldap_connection *conn,
34                                              const char *base,
35                                              enum ldap_scope scope,
36                                              char *filter,
37                                              int num_attributes,
38                                              const char **attributes)
39 {
40         struct ldap_message *res;
41
42         res = new_ldap_message(conn);
43         if (!res) {
44                 return NULL;
45         }
46
47         res->type = LDAP_TAG_SearchRequest;
48         res->r.SearchRequest.basedn = base;
49         res->r.SearchRequest.scope = scope;
50         res->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
51         res->r.SearchRequest.timelimit = 0;
52         res->r.SearchRequest.sizelimit = 0;
53         res->r.SearchRequest.attributesonly = False;
54         res->r.SearchRequest.filter = filter;
55         res->r.SearchRequest.num_attributes = num_attributes;
56         res->r.SearchRequest.attributes = attributes;
57
58         return res;
59 }
60 #endif
61
62 static struct ldap_message *new_ldap_simple_bind_msg(struct ldap_connection *conn, const char *dn, const char *pw)
63 {
64         struct ldap_message *res;
65
66         res = new_ldap_message(conn);
67         if (!res) {
68                 return NULL;
69         }
70
71         res->type = LDAP_TAG_BindRequest;
72         res->r.BindRequest.version = 3;
73         res->r.BindRequest.dn = talloc_strdup(res->mem_ctx, dn);
74         res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SIMPLE;
75         res->r.BindRequest.creds.password = talloc_strdup(res->mem_ctx, pw);
76
77         return res;
78 }
79
80 static struct ldap_message *new_ldap_sasl_bind_msg(struct ldap_connection *conn, const char *sasl_mechanism, DATA_BLOB *secblob)
81 {
82         struct ldap_message *res;
83
84         res = new_ldap_message(conn);
85         if (!res) {
86                 return NULL;
87         }
88
89         res->type = LDAP_TAG_BindRequest;
90         res->r.BindRequest.version = 3;
91         res->r.BindRequest.dn = "";
92         res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SASL;
93         res->r.BindRequest.creds.SASL.mechanism = talloc_strdup(res->mem_ctx, sasl_mechanism);
94         res->r.BindRequest.creds.SASL.secblob = *secblob;
95
96         return res;
97 }
98
99 static struct ldap_connection *new_ldap_connection(TALLOC_CTX *mem_ctx)
100 {
101         struct ldap_connection *result;
102
103         result = talloc_p(mem_ctx, struct ldap_connection);
104
105         if (!result) {
106                 return NULL;
107         }
108
109         result->mem_ctx = result;
110         result->next_msgid = 1;
111         result->outstanding = NULL;
112         result->searchid = 0;
113         result->search_entries = NULL;
114         result->auth_dn = NULL;
115         result->simple_pw = NULL;
116         result->gensec = NULL;
117
118         return result;
119 }
120
121 struct ldap_connection *ldap_connect(TALLOC_CTX *mem_ctx, const char *url)
122 {
123         struct hostent *hp;
124         struct ipv4_addr ip;
125         struct ldap_connection *conn;
126         BOOL ret;
127
128         conn = new_ldap_connection(mem_ctx);
129         if (!conn) {
130                 return NULL;
131         }
132
133         ret = ldap_parse_basic_url(conn->mem_ctx, url, &conn->host,
134                                   &conn->port, &conn->ldaps);
135         if (!ret) {
136                 talloc_free(conn);
137                 return NULL;
138         }
139
140         hp = sys_gethostbyname(conn->host);
141         if (!hp || !hp->h_addr) {
142                 talloc_free(conn);
143                 return NULL;
144         }
145
146         putip((char *)&ip, (char *)hp->h_addr);
147
148         conn->sock = open_socket_out(SOCK_STREAM, &ip, conn->port, LDAP_CONNECTION_TIMEOUT);
149         if (conn->sock < 0) {
150                 talloc_free(conn);
151                 return NULL;
152         }
153
154         return conn;
155 }
156
157 struct ldap_message *new_ldap_message(TALLOC_CTX *mem_ctx)
158 {
159         struct ldap_message *result;
160
161         result = talloc_p(mem_ctx, struct ldap_message);
162
163         if (!result) {
164                 return NULL;
165         }
166
167         result->mem_ctx = result;
168
169         return result;
170 }
171
172 BOOL ldap_send_msg(struct ldap_connection *conn, struct ldap_message *msg,
173                    const struct timeval *endtime)
174 {
175         DATA_BLOB request;
176         BOOL result;
177         struct ldap_queue_entry *entry;
178
179         msg->messageid = conn->next_msgid++;
180
181         if (!ldap_encode(msg, &request))
182                 return False;
183
184         result = (write_data_until(conn->sock, request.data, request.length,
185                                    endtime) == request.length);
186
187         data_blob_free(&request);
188
189         if (!result)
190                 return result;
191
192         /* abandon and unbind don't expect results */
193
194         if ((msg->type == LDAP_TAG_AbandonRequest) ||
195             (msg->type == LDAP_TAG_UnbindRequest))
196                 return True;
197
198         entry = malloc_p(struct ldap_queue_entry);
199
200         if (entry == NULL)
201                 return False;
202
203         entry->msgid = msg->messageid;
204         entry->msg = NULL;
205         DLIST_ADD(conn->outstanding, entry);
206
207         return True;
208 }
209
210 BOOL ldap_receive_msg(struct ldap_connection *conn, struct ldap_message *msg,
211                       const struct timeval *endtime)
212 {
213         struct asn1_data data;
214         BOOL result;
215
216         if (!asn1_read_sequence_until(conn->sock, &data, endtime))
217                 return False;
218
219         result = ldap_decode(&data, msg);
220
221         asn1_free(&data);
222         return result;
223 }
224
225 static struct ldap_message *recv_from_queue(struct ldap_connection *conn,
226                                             int msgid)
227 {
228         struct ldap_queue_entry *e;
229
230         for (e = conn->outstanding; e != NULL; e = e->next) {
231
232                 if (e->msgid == msgid) {
233                         struct ldap_message *result = e->msg;
234                         DLIST_REMOVE(conn->outstanding, e);
235                         SAFE_FREE(e);
236                         return result;
237                 }
238         }
239
240         return NULL;
241 }
242
243 static void add_search_entry(struct ldap_connection *conn,
244                              struct ldap_message *msg)
245 {
246         struct ldap_queue_entry *e = malloc_p(struct ldap_queue_entry);
247
248         if (e == NULL)
249                 return;
250
251         e->msg = msg;
252         DLIST_ADD_END(conn->search_entries, e, struct ldap_queue_entry *);
253         return;
254 }
255
256 static void fill_outstanding_request(struct ldap_connection *conn,
257                                      struct ldap_message *msg)
258 {
259         struct ldap_queue_entry *e;
260
261         for (e = conn->outstanding; e != NULL; e = e->next) {
262                 if (e->msgid == msg->messageid) {
263                         e->msg = msg;
264                         return;
265                 }
266         }
267
268         /* This reply has not been expected, destroy the incoming msg */
269         talloc_free(msg);
270         return;
271 }
272
273 struct ldap_message *ldap_receive(struct ldap_connection *conn, int msgid,
274                                   const struct timeval *endtime)
275 {
276         struct ldap_message *result = recv_from_queue(conn, msgid);
277
278         if (result != NULL)
279                 return result;
280
281         while (True) {
282                 struct asn1_data data;
283                 BOOL res;
284
285                 result = new_ldap_message(conn);
286
287                 if (!asn1_read_sequence_until(conn->sock, &data, endtime))
288                         return NULL;
289
290                 res = ldap_decode(&data, result);
291                 asn1_free(&data);
292
293                 if (!res)
294                         return NULL;
295
296                 if (result->messageid == msgid)
297                         return result;
298
299                 if (result->type == LDAP_TAG_SearchResultEntry) {
300                         add_search_entry(conn, result);
301                 } else {
302                         fill_outstanding_request(conn, result);
303                 }
304         }
305
306         return NULL;
307 }
308
309 struct ldap_message *ldap_transaction(struct ldap_connection *conn,
310                                       struct ldap_message *request)
311 {
312         if (!ldap_send_msg(conn, request, NULL))
313                 return False;
314
315         return ldap_receive(conn, request->messageid, NULL);
316 }
317
318 int ldap_bind_simple(struct ldap_connection *conn, const char *userdn, const char *password)
319 {
320         struct ldap_message *response;
321         struct ldap_message *msg;
322         const char *dn, *pw;
323         int result = LDAP_OTHER;
324
325         if (conn == NULL)
326                 return result;
327
328         if (userdn) {
329                 dn = userdn;
330         } else {
331                 if (conn->auth_dn) {
332                         dn = conn->auth_dn;
333                 } else {
334                         dn = "";
335                 }
336         }
337
338         if (password) {
339                 pw = password;
340         } else {
341                 if (conn->simple_pw) {
342                         pw = conn->simple_pw;
343                 } else {
344                         pw = "";
345                 }
346         }
347
348         msg =  new_ldap_simple_bind_msg(conn, dn, pw);
349         if (!msg)
350                 return result;
351
352         response = ldap_transaction(conn, msg);
353         if (!response) {
354                 talloc_free(msg);
355                 return result;
356         }
357                 
358         result = response->r.BindResponse.response.resultcode;
359
360         talloc_free(msg);
361         talloc_free(response);
362
363         return result;
364 }
365
366 int ldap_bind_sasl(struct ldap_connection *conn, const char *username, const char *domain, const char *password)
367 {
368         NTSTATUS status;
369         TALLOC_CTX *mem_ctx = NULL;
370         struct ldap_message *response;
371         struct ldap_message *msg;
372         DATA_BLOB input = data_blob(NULL, 0);
373         DATA_BLOB output = data_blob(NULL, 0);
374         int result = LDAP_OTHER;
375
376         if (conn == NULL)
377                 return result;
378
379         status = gensec_client_start(conn, &conn->gensec);
380         if (!NT_STATUS_IS_OK(status)) {
381                 DEBUG(0, ("Failed to start GENSEC engine (%s)\n", nt_errstr(status)));
382                 return result;
383         }
384
385         gensec_want_feature(conn->gensec, GENSEC_FEATURE_SIGN | GENSEC_FEATURE_SEAL);
386
387         status = gensec_set_domain(conn->gensec, domain);
388         if (!NT_STATUS_IS_OK(status)) {
389                 DEBUG(1, ("Failed to start set GENSEC client domain to %s: %s\n", 
390                           domain, nt_errstr(status)));
391                 goto done;
392         }
393
394         status = gensec_set_username(conn->gensec, username);
395         if (!NT_STATUS_IS_OK(status)) {
396                 DEBUG(1, ("Failed to start set GENSEC client username to %s: %s\n", 
397                           username, nt_errstr(status)));
398                 goto done;
399         }
400
401         status = gensec_set_password(conn->gensec, password);
402         if (!NT_STATUS_IS_OK(status)) {
403                 DEBUG(1, ("Failed to start set GENSEC client password: %s\n", 
404                           nt_errstr(status)));
405                 goto done;
406         }
407
408         status = gensec_set_target_hostname(conn->gensec, conn->host);
409         if (!NT_STATUS_IS_OK(status)) {
410                 DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n", 
411                           nt_errstr(status)));
412                 goto done;
413         }
414
415         status = gensec_set_target_service(conn->gensec, "ldap");
416         if (!NT_STATUS_IS_OK(status)) {
417                 DEBUG(1, ("Failed to start set GENSEC target service: %s\n", 
418                           nt_errstr(status)));
419                 goto done;
420         }
421
422         status = gensec_start_mech_by_sasl_name(conn->gensec, "GSS-SPNEGO");
423         if (!NT_STATUS_IS_OK(status)) {
424                 DEBUG(1, ("Failed to start set GENSEC client SPNEGO mechanism: %s\n",
425                           nt_errstr(status)));
426                 goto done;
427         }
428
429         mem_ctx = talloc_init("ldap_bind_sasl");
430         if (!mem_ctx)
431                 goto done;
432
433         status = gensec_update(conn->gensec, mem_ctx,
434                                input,
435                                &output);
436
437         while(1) {
438                 if (NT_STATUS_IS_OK(status) && output.length == 0) {
439                         break;
440                 }
441                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
442                         break;
443                 }
444
445                 msg =  new_ldap_sasl_bind_msg(conn, "GSS-SPNEGO", &output);
446                 if (!msg)
447                         goto done;
448
449                 response = ldap_transaction(conn, msg);
450                 talloc_free(msg);
451
452                 if (!response) {
453                         goto done;
454                 }
455
456                 result = response->r.BindResponse.response.resultcode;
457
458                 if (result != LDAP_SUCCESS && result != LDAP_SASL_BIND_IN_PROGRESS) {
459                         break;
460                 }
461
462                 if (!NT_STATUS_IS_OK(status)) {
463                         status = gensec_update(conn->gensec, mem_ctx,
464                                                response->r.BindResponse.SASL.secblob,
465                                                &output);
466                 } else {
467                         output.length = 0;
468                 }
469
470                 talloc_free(response);
471         }
472
473 done:
474         if (mem_ctx)
475                 talloc_destroy(mem_ctx);
476
477         return result;
478 }
479
480 struct ldap_connection *ldap_setup_connection(TALLOC_CTX *mem_ctx, const char *url, 
481                                                 const char *userdn, const char *password)
482 {
483         struct ldap_connection *conn;
484         int result;
485
486         conn =ldap_connect(mem_ctx, url);
487         if (!conn) {
488                 return NULL;
489         }
490
491         result = ldap_bind_simple(conn, userdn, password);
492         if (result != LDAP_SUCCESS) {
493                 talloc_free(conn);
494                 return NULL;
495         }
496
497         return conn;
498 }
499
500 struct ldap_connection *ldap_setup_connection_with_sasl(TALLOC_CTX *mem_ctx, const char *url,
501                                                         const char *username, const char *domain, const char *password)
502 {
503         struct ldap_connection *conn;
504         int result;
505
506         conn =ldap_connect(mem_ctx, url);
507         if (!conn) {
508                 return NULL;
509         }
510
511         result = ldap_bind_sasl(conn, username, domain, password);
512         if (result != LDAP_SUCCESS) {
513                 talloc_free(conn);
514                 return NULL;
515         }
516
517         return conn;
518 }
519
520 BOOL ldap_abandon_message(struct ldap_connection *conn, int msgid,
521                                  const struct timeval *endtime)
522 {
523         struct ldap_message *msg = new_ldap_message(conn);
524         BOOL result;
525
526         if (msg == NULL)
527                 return False;
528
529         msg->type = LDAP_TAG_AbandonRequest;
530         msg->r.AbandonRequest.messageid = msgid;
531
532         result = ldap_send_msg(conn, msg, endtime);
533         talloc_free(msg);
534         return result;
535 }
536
537 BOOL ldap_setsearchent(struct ldap_connection *conn, struct ldap_message *msg,
538                        const struct timeval *endtime)
539 {
540         if ((conn->searchid != 0) &&
541             (!ldap_abandon_message(conn, conn->searchid, endtime)))
542                 return False;
543
544         conn->searchid = conn->next_msgid;
545         return ldap_send_msg(conn, msg, endtime);
546 }
547
548 struct ldap_message *ldap_getsearchent(struct ldap_connection *conn,
549                                        const struct timeval *endtime)
550 {
551         struct ldap_message *result;
552
553         if (conn->search_entries != NULL) {
554                 struct ldap_queue_entry *e = conn->search_entries;
555
556                 result = e->msg;
557                 DLIST_REMOVE(conn->search_entries, e);
558                 SAFE_FREE(e);
559                 return result;
560         }
561
562         result = ldap_receive(conn, conn->searchid, endtime);
563         if (!result) {
564                 return NULL;
565         }
566
567         if (result->type == LDAP_TAG_SearchResultEntry)
568                 return result;
569
570         if (result->type == LDAP_TAG_SearchResultDone) {
571                 /* TODO: Handle Paged Results */
572                 talloc_free(result);
573                 return NULL;
574         }
575
576         /* TODO: Handle Search References here */
577         return NULL;
578 }
579
580 void ldap_endsearchent(struct ldap_connection *conn,
581                        const struct timeval *endtime)
582 {
583         struct ldap_queue_entry *e;
584
585         e = conn->search_entries;
586
587         while (e != NULL) {
588                 struct ldap_queue_entry *next = e->next;
589                 DLIST_REMOVE(conn->search_entries, e);
590                 SAFE_FREE(e);
591                 e = next;
592         }
593 }
594
595 struct ldap_message *ldap_searchone(struct ldap_connection *conn,
596                                     struct ldap_message *msg,
597                                     const struct timeval *endtime)
598 {
599         struct ldap_message *res1, *res2 = NULL;
600         if (!ldap_setsearchent(conn, msg, endtime))
601                 return NULL;
602
603         res1 = ldap_getsearchent(conn, endtime);
604
605         if (res1 != NULL)
606                 res2 = ldap_getsearchent(conn, endtime);
607
608         ldap_endsearchent(conn, endtime);
609
610         if (res1 == NULL)
611                 return NULL;
612
613         if (res2 != NULL) {
614                 /* More than one entry */
615                 talloc_free(res1);
616                 talloc_free(res2);
617                 return NULL;
618         }
619
620         return res1;
621 }
622
623 BOOL ldap_find_single_value(struct ldap_message *msg, const char *attr,
624                             DATA_BLOB *value)
625 {
626         int i;
627         struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
628
629         if (msg->type != LDAP_TAG_SearchResultEntry)
630                 return False;
631
632         for (i=0; i<r->num_attributes; i++) {
633                 if (strequal(attr, r->attributes[i].name)) {
634                         if (r->attributes[i].num_values != 1)
635                                 return False;
636
637                         *value = r->attributes[i].values[0];
638                         return True;
639                 }
640         }
641         return False;
642 }
643
644 BOOL ldap_find_single_string(struct ldap_message *msg, const char *attr,
645                              TALLOC_CTX *mem_ctx, char **value)
646 {
647         DATA_BLOB blob;
648
649         if (!ldap_find_single_value(msg, attr, &blob))
650                 return False;
651
652         *value = talloc(mem_ctx, blob.length+1);
653
654         if (*value == NULL)
655                 return False;
656
657         memcpy(*value, blob.data, blob.length);
658         (*value)[blob.length] = '\0';
659         return True;
660 }
661
662 BOOL ldap_find_single_int(struct ldap_message *msg, const char *attr,
663                           int *value)
664 {
665         DATA_BLOB blob;
666         char *val;
667         int errno_save;
668         BOOL res;
669
670         if (!ldap_find_single_value(msg, attr, &blob))
671                 return False;
672
673         val = malloc(blob.length+1);
674         if (val == NULL)
675                 return False;
676
677         memcpy(val, blob.data, blob.length);
678         val[blob.length] = '\0';
679
680         errno_save = errno;
681         errno = 0;
682
683         *value = strtol(val, NULL, 10);
684
685         res = (errno == 0);
686
687         free(val);
688         errno = errno_save;
689
690         return res;
691 }
692
693 int ldap_error(struct ldap_connection *conn)
694 {
695         return 0;
696 }
697
698 NTSTATUS ldap2nterror(int ldaperror)
699 {
700         return NT_STATUS_OK;
701 }