libads: record session expiry for spnego sasl binds
[samba.git] / source3 / libads / sasl.c
1 /* 
2    Unix SMB/CIFS implementation.
3    ads sasl code
4    Copyright (C) Andrew Tridgell 2001
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "../libcli/auth/spnego.h"
22 #include "auth/credentials/credentials.h"
23 #include "auth/gensec/gensec.h"
24 #include "auth_generic.h"
25 #include "ads.h"
26 #include "smb_krb5.h"
27 #include "system/gssapi.h"
28 #include "lib/param/loadparm.h"
29
30 #ifdef HAVE_LDAP
31
32 static ADS_STATUS ads_sasl_gensec_wrap(ADS_STRUCT *ads, uint8_t *buf, uint32_t len)
33 {
34         struct gensec_security *gensec_security =
35                 talloc_get_type_abort(ads->ldap.wrap_private_data,
36                 struct gensec_security);
37         NTSTATUS nt_status;
38         DATA_BLOB unwrapped, wrapped;
39         TALLOC_CTX *frame = talloc_stackframe();
40
41         unwrapped = data_blob_const(buf, len);
42
43         nt_status = gensec_wrap(gensec_security, frame, &unwrapped, &wrapped);
44         if (!NT_STATUS_IS_OK(nt_status)) {
45                 TALLOC_FREE(frame);
46                 return ADS_ERROR_NT(nt_status);
47         }
48
49         if ((ads->ldap.out.size - 4) < wrapped.length) {
50                 TALLOC_FREE(frame);
51                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
52         }
53
54         /* copy the wrapped blob to the right location */
55         memcpy(ads->ldap.out.buf + 4, wrapped.data, wrapped.length);
56
57         /* set how many bytes must be written to the underlying socket */
58         ads->ldap.out.left = 4 + wrapped.length;
59
60         TALLOC_FREE(frame);
61
62         return ADS_SUCCESS;
63 }
64
65 static ADS_STATUS ads_sasl_gensec_unwrap(ADS_STRUCT *ads)
66 {
67         struct gensec_security *gensec_security =
68                 talloc_get_type_abort(ads->ldap.wrap_private_data,
69                 struct gensec_security);
70         NTSTATUS nt_status;
71         DATA_BLOB unwrapped, wrapped;
72         TALLOC_CTX *frame = talloc_stackframe();
73
74         wrapped = data_blob_const(ads->ldap.in.buf + 4, ads->ldap.in.ofs - 4);
75
76         nt_status = gensec_unwrap(gensec_security, frame, &wrapped, &unwrapped);
77         if (!NT_STATUS_IS_OK(nt_status)) {
78                 TALLOC_FREE(frame);
79                 return ADS_ERROR_NT(nt_status);
80         }
81
82         if (wrapped.length < unwrapped.length) {
83                 TALLOC_FREE(frame);
84                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
85         }
86
87         /* copy the wrapped blob to the right location */
88         memcpy(ads->ldap.in.buf + 4, unwrapped.data, unwrapped.length);
89
90         /* set how many bytes must be written to the underlying socket */
91         ads->ldap.in.left       = unwrapped.length;
92         ads->ldap.in.ofs        = 4;
93
94         TALLOC_FREE(frame);
95
96         return ADS_SUCCESS;
97 }
98
99 static void ads_sasl_gensec_disconnect(ADS_STRUCT *ads)
100 {
101         struct gensec_security *gensec_security =
102                 talloc_get_type_abort(ads->ldap.wrap_private_data,
103                 struct gensec_security);
104
105         TALLOC_FREE(gensec_security);
106
107         ads->ldap.wrap_ops = NULL;
108         ads->ldap.wrap_private_data = NULL;
109 }
110
111 static const struct ads_saslwrap_ops ads_sasl_gensec_ops = {
112         .name           = "gensec",
113         .wrap           = ads_sasl_gensec_wrap,
114         .unwrap         = ads_sasl_gensec_unwrap,
115         .disconnect     = ads_sasl_gensec_disconnect
116 };
117
118 /* 
119    perform a LDAP/SASL/SPNEGO/{NTLMSSP,KRB5} bind (just how many layers can
120    we fit on one socket??)
121 */
122 static ADS_STATUS ads_sasl_spnego_gensec_bind(ADS_STRUCT *ads,
123                                 const char *sasl,
124                                 enum credentials_use_kerberos krb5_state,
125                                 const char *target_service,
126                                 const char *target_hostname,
127                                 const DATA_BLOB server_blob)
128 {
129         DATA_BLOB blob_in = data_blob_null;
130         DATA_BLOB blob_out = data_blob_null;
131         int rc;
132         NTSTATUS nt_status;
133         ADS_STATUS status;
134         struct auth_generic_state *auth_generic_state;
135         bool use_spnego_principal = lp_client_use_spnego_principal();
136         const char *sasl_list[] = { sasl, NULL };
137         NTTIME end_nt_time;
138
139         nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
140         if (!NT_STATUS_IS_OK(nt_status)) {
141                 return ADS_ERROR_NT(nt_status);
142         }
143
144         if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) {
145                 return ADS_ERROR_NT(nt_status);
146         }
147         if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) {
148                 return ADS_ERROR_NT(nt_status);
149         }
150         if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) {
151                 return ADS_ERROR_NT(nt_status);
152         }
153
154         if (server_blob.length == 0) {
155                 use_spnego_principal = false;
156         }
157
158         if (krb5_state == CRED_DONT_USE_KERBEROS) {
159                 use_spnego_principal = false;
160         }
161
162         cli_credentials_set_kerberos_state(auth_generic_state->credentials,
163                                            krb5_state);
164
165         if (target_service != NULL) {
166                 nt_status = gensec_set_target_service(
167                                         auth_generic_state->gensec_security,
168                                         target_service);
169                 if (!NT_STATUS_IS_OK(nt_status)) {
170                         return ADS_ERROR_NT(nt_status);
171                 }
172         }
173
174         if (target_hostname != NULL) {
175                 nt_status = gensec_set_target_hostname(
176                                         auth_generic_state->gensec_security,
177                                         target_hostname);
178                 if (!NT_STATUS_IS_OK(nt_status)) {
179                         return ADS_ERROR_NT(nt_status);
180                 }
181         }
182
183         if (target_service != NULL && target_hostname != NULL) {
184                 use_spnego_principal = false;
185         }
186
187         switch (ads->ldap.wrap_type) {
188         case ADS_SASLWRAP_TYPE_SEAL:
189                 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
190                 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
191                 break;
192         case ADS_SASLWRAP_TYPE_SIGN:
193                 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
194                         gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
195                 } else {
196                         /*
197                          * windows servers are broken with sign only,
198                          * so we let the NTLMSSP backend to seal here,
199                          * via GENSEC_FEATURE_LDAP_STYLE.
200                          */
201                         gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
202                         gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_LDAP_STYLE);
203                 }
204                 break;
205         case ADS_SASLWRAP_TYPE_PLAIN:
206                 break;
207         }
208
209         nt_status = auth_generic_client_start_by_sasl(auth_generic_state,
210                                                       sasl_list);
211         if (!NT_STATUS_IS_OK(nt_status)) {
212                 return ADS_ERROR_NT(nt_status);
213         }
214
215         rc = LDAP_SASL_BIND_IN_PROGRESS;
216         nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
217         if (use_spnego_principal) {
218                 blob_in = data_blob_dup_talloc(talloc_tos(), server_blob);
219                 if (blob_in.length == 0) {
220                         TALLOC_FREE(auth_generic_state);
221                         return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
222                 }
223         } else {
224                 blob_in = data_blob_null;
225         }
226         blob_out = data_blob_null;
227
228         while (true) {
229                 struct berval cred, *scred = NULL;
230
231                 nt_status = gensec_update(auth_generic_state->gensec_security,
232                                           talloc_tos(), blob_in, &blob_out);
233                 data_blob_free(&blob_in);
234                 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
235                     && !NT_STATUS_IS_OK(nt_status))
236                 {
237                         TALLOC_FREE(auth_generic_state);
238                         data_blob_free(&blob_out);
239                         return ADS_ERROR_NT(nt_status);
240                 }
241
242                 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_out.length == 0) {
243                         break;
244                 }
245
246                 cred.bv_val = (char *)blob_out.data;
247                 cred.bv_len = blob_out.length;
248                 scred = NULL;
249                 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, sasl, &cred, NULL, NULL, &scred);
250                 data_blob_free(&blob_out);
251                 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
252                         if (scred) {
253                                 ber_bvfree(scred);
254                         }
255
256                         TALLOC_FREE(auth_generic_state);
257                         return ADS_ERROR(rc);
258                 }
259                 if (scred) {
260                         blob_in = data_blob_talloc(talloc_tos(),
261                                                    scred->bv_val,
262                                                    scred->bv_len);
263                         if (blob_in.length != scred->bv_len) {
264                                 ber_bvfree(scred);
265                                 TALLOC_FREE(auth_generic_state);
266                                 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
267                         }
268                         ber_bvfree(scred);
269                 } else {
270                         blob_in = data_blob_null;
271                 }
272                 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_in.length == 0) {
273                         break;
274                 }
275         }
276
277         data_blob_free(&blob_in);
278         data_blob_free(&blob_out);
279
280         if (ads->ldap.wrap_type >= ADS_SASLWRAP_TYPE_SEAL) {
281                 bool ok;
282
283                 ok = gensec_have_feature(auth_generic_state->gensec_security,
284                                          GENSEC_FEATURE_SEAL);
285                 if (!ok) {
286                         DEBUG(0,("The gensec feature sealing request, but unavailable\n"));
287                         TALLOC_FREE(auth_generic_state);
288                         return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
289                 }
290
291                 ok = gensec_have_feature(auth_generic_state->gensec_security,
292                                          GENSEC_FEATURE_SIGN);
293                 if (!ok) {
294                         DEBUG(0,("The gensec feature signing request, but unavailable\n"));
295                         TALLOC_FREE(auth_generic_state);
296                         return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
297                 }
298
299         } else if (ads->ldap.wrap_type >= ADS_SASLWRAP_TYPE_SIGN) {
300                 bool ok;
301
302                 ok = gensec_have_feature(auth_generic_state->gensec_security,
303                                          GENSEC_FEATURE_SIGN);
304                 if (!ok) {
305                         DEBUG(0,("The gensec feature signing request, but unavailable\n"));
306                         TALLOC_FREE(auth_generic_state);
307                         return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
308                 }
309         }
310
311         ads->auth.tgs_expire = LONG_MAX;
312         end_nt_time = gensec_expire_time(auth_generic_state->gensec_security);
313         if (end_nt_time != GENSEC_EXPIRE_TIME_INFINITY) {
314                 struct timeval tv;
315                 nttime_to_timeval(&tv, end_nt_time);
316                 ads->auth.tgs_expire = tv.tv_sec;
317         }
318
319         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
320                 size_t max_wrapped = gensec_max_wrapped_size(auth_generic_state->gensec_security);
321                 ads->ldap.out.max_unwrapped = gensec_max_input_size(auth_generic_state->gensec_security);
322
323                 ads->ldap.out.sig_size = max_wrapped - ads->ldap.out.max_unwrapped;
324                 /*
325                  * Note that we have to truncate this to 0x2C
326                  * (taken from a capture with LDAP unbind), as the
327                  * signature size is not constant for Kerberos with
328                  * arcfour-hmac-md5.
329                  */
330                 ads->ldap.in.min_wrapped = MIN(ads->ldap.out.sig_size, 0x2C);
331                 ads->ldap.in.max_wrapped = max_wrapped;
332                 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gensec_ops, auth_generic_state->gensec_security);
333                 if (!ADS_ERR_OK(status)) {
334                         DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
335                                 ads_errstr(status)));
336                         TALLOC_FREE(auth_generic_state);
337                         return status;
338                 }
339                 /* Only keep the gensec_security element around long-term */
340                 talloc_steal(NULL, auth_generic_state->gensec_security);
341         }
342         TALLOC_FREE(auth_generic_state);
343
344         return ADS_ERROR(rc);
345 }
346
347 #ifdef HAVE_KRB5
348 static ADS_STATUS ads_init_gssapi_cred(ADS_STRUCT *ads, gss_cred_id_t *cred)
349 {
350         ADS_STATUS status;
351         krb5_context kctx;
352         krb5_error_code kerr;
353         krb5_ccache kccache = NULL;
354         uint32_t maj, min;
355
356         *cred = GSS_C_NO_CREDENTIAL;
357
358         if (!ads->auth.ccache_name) {
359                 return ADS_SUCCESS;
360         }
361
362         kerr = krb5_init_context(&kctx);
363         if (kerr) {
364                 return ADS_ERROR_KRB5(kerr);
365         }
366
367 #ifdef HAVE_GSS_KRB5_IMPORT_CRED
368         kerr = krb5_cc_resolve(kctx, ads->auth.ccache_name, &kccache);
369         if (kerr) {
370                 status = ADS_ERROR_KRB5(kerr);
371                 goto done;
372         }
373
374         maj = gss_krb5_import_cred(&min, kccache, NULL, NULL, cred);
375         if (maj != GSS_S_COMPLETE) {
376                 status = ADS_ERROR_GSS(maj, min);
377                 goto done;
378         }
379 #else
380         /* We need to fallback to overriding the default creds.
381          * This operation is not thread safe as it changes the process
382          * environment variable, but we do not have any better option
383          * with older kerberos libraries */
384         {
385                 const char *oldccname = NULL;
386
387                 oldccname = getenv("KRB5CCNAME");
388                 setenv("KRB5CCNAME", ads->auth.ccache_name, 1);
389
390                 maj = gss_acquire_cred(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE,
391                                        NULL, GSS_C_INITIATE, cred, NULL, NULL);
392
393                 if (oldccname) {
394                         setenv("KRB5CCNAME", oldccname, 1);
395                 } else {
396                         unsetenv("KRB5CCNAME");
397                 }
398
399                 if (maj != GSS_S_COMPLETE) {
400                         status = ADS_ERROR_GSS(maj, min);
401                         goto done;
402                 }
403         }
404 #endif
405
406         status = ADS_SUCCESS;
407
408 done:
409         if (!ADS_ERR_OK(status) && kccache != NULL) {
410                 krb5_cc_close(kctx, kccache);
411         }
412         krb5_free_context(kctx);
413         return status;
414 }
415
416 static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8_t *buf, uint32_t len)
417 {
418         gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
419         ADS_STATUS status;
420         int gss_rc;
421         uint32_t minor_status;
422         gss_buffer_desc unwrapped, wrapped;
423         int conf_req_flag, conf_state;
424
425         unwrapped.value         = buf;
426         unwrapped.length        = len;
427
428         /* for now request sign and seal */
429         conf_req_flag   = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
430
431         gss_rc = gss_wrap(&minor_status, context_handle,
432                           conf_req_flag, GSS_C_QOP_DEFAULT,
433                           &unwrapped, &conf_state,
434                           &wrapped);
435         status = ADS_ERROR_GSS(gss_rc, minor_status);
436         if (!ADS_ERR_OK(status)) return status;
437
438         if (conf_req_flag && conf_state == 0) {
439                 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
440         }
441
442         if ((ads->ldap.out.size - 4) < wrapped.length) {
443                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
444         }
445
446         /* copy the wrapped blob to the right location */
447         memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
448
449         /* set how many bytes must be written to the underlying socket */
450         ads->ldap.out.left = 4 + wrapped.length;
451
452         gss_release_buffer(&minor_status, &wrapped);
453
454         return ADS_SUCCESS;
455 }
456
457 static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
458 {
459         gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
460         ADS_STATUS status;
461         int gss_rc;
462         uint32_t minor_status;
463         gss_buffer_desc unwrapped, wrapped;
464         int conf_state;
465
466         wrapped.value   = ads->ldap.in.buf + 4;
467         wrapped.length  = ads->ldap.in.ofs - 4;
468
469         gss_rc = gss_unwrap(&minor_status, context_handle,
470                             &wrapped, &unwrapped,
471                             &conf_state, GSS_C_QOP_DEFAULT);
472         status = ADS_ERROR_GSS(gss_rc, minor_status);
473         if (!ADS_ERR_OK(status)) return status;
474
475         if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
476                 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
477         }
478
479         if (wrapped.length < unwrapped.length) {
480                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
481         }
482
483         /* copy the wrapped blob to the right location */
484         memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
485
486         /* set how many bytes must be written to the underlying socket */
487         ads->ldap.in.left       = unwrapped.length;
488         ads->ldap.in.ofs        = 4;
489
490         gss_release_buffer(&minor_status, &unwrapped);
491
492         return ADS_SUCCESS;
493 }
494
495 static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
496 {
497         gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
498         uint32_t minor_status;
499
500         gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
501
502         ads->ldap.wrap_ops = NULL;
503         ads->ldap.wrap_private_data = NULL;
504 }
505
506 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
507         .name           = "gssapi",
508         .wrap           = ads_sasl_gssapi_wrap,
509         .unwrap         = ads_sasl_gssapi_unwrap,
510         .disconnect     = ads_sasl_gssapi_disconnect
511 };
512
513 #endif /* HAVE_KRB5 */
514
515 #ifdef HAVE_KRB5
516 struct ads_service_principal {
517         char *service;
518         char *hostname;
519         char *string;
520 #ifdef HAVE_KRB5
521         gss_name_t name;
522 #endif
523 };
524
525 static void ads_free_service_principal(struct ads_service_principal *p)
526 {
527         SAFE_FREE(p->service);
528         SAFE_FREE(p->hostname);
529         SAFE_FREE(p->string);
530
531 #ifdef HAVE_KRB5
532         if (p->name) {
533                 uint32_t minor_status;
534                 gss_release_name(&minor_status, &p->name);
535         }
536 #endif
537         ZERO_STRUCTP(p);
538 }
539
540 static ADS_STATUS ads_guess_target(ADS_STRUCT *ads,
541                                    char **service,
542                                    char **hostname,
543                                    char **principal)
544 {
545         ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY);
546         char *princ = NULL;
547         TALLOC_CTX *frame;
548         char *server = NULL;
549         char *realm = NULL;
550         int rc;
551
552         frame = talloc_stackframe();
553         if (frame == NULL) {
554                 return ADS_ERROR(LDAP_NO_MEMORY);
555         }
556
557         if (ads->server.realm && ads->server.ldap_server) {
558                 server = strlower_talloc(frame, ads->server.ldap_server);
559                 if (server == NULL) {
560                         goto out;
561                 }
562
563                 realm = strupper_talloc(frame, ads->server.realm);
564                 if (realm == NULL) {
565                         goto out;
566                 }
567
568                 /*
569                  * If we got a name which is bigger than a NetBIOS name,
570                  * but isn't a FQDN, create one.
571                  */
572                 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
573                         char *dnsdomain;
574
575                         dnsdomain = strlower_talloc(frame, ads->server.realm);
576                         if (dnsdomain == NULL) {
577                                 goto out;
578                         }
579
580                         server = talloc_asprintf(frame,
581                                                  "%s.%s",
582                                                  server, dnsdomain);
583                         if (server == NULL) {
584                                 goto out;
585                         }
586                 }
587         } else if (ads->config.realm && ads->config.ldap_server_name) {
588                 server = strlower_talloc(frame, ads->config.ldap_server_name);
589                 if (server == NULL) {
590                         goto out;
591                 }
592
593                 realm = strupper_talloc(frame, ads->config.realm);
594                 if (realm == NULL) {
595                         goto out;
596                 }
597
598                 /*
599                  * If we got a name which is bigger than a NetBIOS name,
600                  * but isn't a FQDN, create one.
601                  */
602                 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
603                         char *dnsdomain;
604
605                         dnsdomain = strlower_talloc(frame, ads->server.realm);
606                         if (dnsdomain == NULL) {
607                                 goto out;
608                         }
609
610                         server = talloc_asprintf(frame,
611                                                  "%s.%s",
612                                                  server, dnsdomain);
613                         if (server == NULL) {
614                                 goto out;
615                         }
616                 }
617         }
618
619         if (server == NULL || realm == NULL) {
620                 goto out;
621         }
622
623         *service = SMB_STRDUP("ldap");
624         if (*service == NULL) {
625                 status = ADS_ERROR(LDAP_PARAM_ERROR);
626                 goto out;
627         }
628         *hostname = SMB_STRDUP(server);
629         if (*hostname == NULL) {
630                 SAFE_FREE(*service);
631                 status = ADS_ERROR(LDAP_PARAM_ERROR);
632                 goto out;
633         }
634         rc = asprintf(&princ, "ldap/%s@%s", server, realm);
635         if (rc == -1 || princ == NULL) {
636                 SAFE_FREE(*service);
637                 SAFE_FREE(*hostname);
638                 status = ADS_ERROR(LDAP_PARAM_ERROR);
639                 goto out;
640         }
641
642         *principal = princ;
643
644         status = ADS_SUCCESS;
645 out:
646         TALLOC_FREE(frame);
647         return status;
648 }
649
650 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
651                                                  struct ads_service_principal *p)
652 {
653         ADS_STATUS status;
654 #ifdef HAVE_KRB5
655         gss_buffer_desc input_name;
656         /* GSS_KRB5_NT_PRINCIPAL_NAME */
657         gss_OID_desc nt_principal =
658         {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
659         uint32_t minor_status;
660         int gss_rc;
661 #endif
662
663         ZERO_STRUCTP(p);
664
665         status = ads_guess_target(ads,
666                                   &p->service,
667                                   &p->hostname,
668                                   &p->string);
669         if (!ADS_ERR_OK(status)) {
670                 return status;
671         }
672
673 #ifdef HAVE_KRB5
674         input_name.value = p->string;
675         input_name.length = strlen(p->string);
676
677         gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
678         if (gss_rc) {
679                 ads_free_service_principal(p);
680                 return ADS_ERROR_GSS(gss_rc, minor_status);
681         }
682 #endif
683
684         return ADS_SUCCESS;
685 }
686
687 #endif /* HAVE_KRB5 */
688
689 /* 
690    this performs a SASL/SPNEGO bind
691 */
692 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
693 {
694         TALLOC_CTX *frame = talloc_stackframe();
695         struct ads_service_principal p = {0};
696         struct berval *scred=NULL;
697         int rc, i;
698         ADS_STATUS status;
699         DATA_BLOB blob;
700         char *given_principal = NULL;
701         char *OIDs[ASN1_MAX_OIDS];
702 #ifdef HAVE_KRB5
703         bool got_kerberos_mechanism = False;
704 #endif
705
706         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
707
708         if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
709                 status = ADS_ERROR(rc);
710                 goto done;
711         }
712
713         blob = data_blob(scred->bv_val, scred->bv_len);
714
715         ber_bvfree(scred);
716
717 #if 0
718         file_save("sasl_spnego.dat", blob.data, blob.length);
719 #endif
720
721         /* the server sent us the first part of the SPNEGO exchange in the negprot 
722            reply */
723         if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
724                         OIDs[0] == NULL) {
725                 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
726                 goto done;
727         }
728         TALLOC_FREE(given_principal);
729
730         /* make sure the server understands kerberos */
731         for (i=0;OIDs[i];i++) {
732                 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
733 #ifdef HAVE_KRB5
734                 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
735                     strcmp(OIDs[i], OID_KERBEROS5) == 0) {
736                         got_kerberos_mechanism = True;
737                 }
738 #endif
739                 talloc_free(OIDs[i]);
740         }
741
742         status = ads_generate_service_principal(ads, &p);
743         if (!ADS_ERR_OK(status)) {
744                 goto done;
745         }
746
747 #ifdef HAVE_KRB5
748         if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
749             got_kerberos_mechanism) 
750         {
751                 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
752                                                      CRED_MUST_USE_KERBEROS,
753                                                      p.service, p.hostname,
754                                                      blob);
755                 if (ADS_ERR_OK(status)) {
756                         ads_free_service_principal(&p);
757                         goto done;
758                 }
759
760                 DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
761                           "calling kinit\n", ads_errstr(status)));
762
763                 status = ADS_ERROR_KRB5(ads_kinit_password(ads)); 
764
765                 if (ADS_ERR_OK(status)) {
766                         status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
767                                                         CRED_MUST_USE_KERBEROS,
768                                                         p.service, p.hostname,
769                                                         blob);
770                         if (!ADS_ERR_OK(status)) {
771                                 DEBUG(0,("kinit succeeded but "
772                                         "ads_sasl_spnego_gensec_bind(KRB5) failed: %s\n",
773                                         ads_errstr(status)));
774                         }
775                 }
776
777                 /* only fallback to NTLMSSP if allowed */
778                 if (ADS_ERR_OK(status) || 
779                     !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
780                         goto done;
781                 }
782         }
783 #endif
784
785         /* lets do NTLMSSP ... this has the big advantage that we don't need
786            to sync clocks, and we don't rely on special versions of the krb5 
787            library for HMAC_MD4 encryption */
788         status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
789                                              CRED_DONT_USE_KERBEROS,
790                                              p.service, p.hostname,
791                                              data_blob_null);
792 done:
793         ads_free_service_principal(&p);
794         TALLOC_FREE(frame);
795         return status;
796 }
797
798 #ifdef HAVE_KRB5
799 #define MAX_GSS_PASSES 3
800
801 /* this performs a SASL/gssapi bind
802    we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
803    is very dependent on correctly configured DNS whereas
804    this routine is much less fragile
805    see RFC2078 and RFC2222 for details
806 */
807 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
808 {
809         uint32_t minor_status;
810         gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
811         gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
812         gss_OID mech_type = GSS_C_NULL_OID;
813         gss_buffer_desc output_token, input_token;
814         uint32_t req_flags, ret_flags;
815         int conf_state;
816         struct berval cred;
817         struct berval *scred = NULL;
818         int i=0;
819         int gss_rc, rc;
820         uint8_t *p;
821         uint32_t max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
822         uint8_t wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
823         ADS_STATUS status;
824
825         input_token.value = NULL;
826         input_token.length = 0;
827
828         status = ads_init_gssapi_cred(ads, &gss_cred);
829         if (!ADS_ERR_OK(status)) {
830                 goto failed;
831         }
832
833         /*
834          * Note: here we always ask the gssapi for sign and seal
835          *       as this is negotiated later after the mutal
836          *       authentication
837          */
838         req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
839
840         for (i=0; i < MAX_GSS_PASSES; i++) {
841                 gss_rc = gss_init_sec_context(&minor_status,
842                                           gss_cred,
843                                           &context_handle,
844                                           serv_name,
845                                           mech_type,
846                                           req_flags,
847                                           0,
848                                           NULL,
849                                           &input_token,
850                                           NULL,
851                                           &output_token,
852                                           &ret_flags,
853                                           NULL);
854                 if (scred) {
855                         ber_bvfree(scred);
856                         scred = NULL;
857                 }
858                 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
859                         status = ADS_ERROR_GSS(gss_rc, minor_status);
860                         goto failed;
861                 }
862
863                 cred.bv_val = (char *)output_token.value;
864                 cred.bv_len = output_token.length;
865
866                 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL, 
867                                       &scred);
868                 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
869                         status = ADS_ERROR(rc);
870                         goto failed;
871                 }
872
873                 if (output_token.value) {
874                         gss_release_buffer(&minor_status, &output_token);
875                 }
876
877                 if (scred) {
878                         input_token.value = scred->bv_val;
879                         input_token.length = scred->bv_len;
880                 } else {
881                         input_token.value = NULL;
882                         input_token.length = 0;
883                 }
884
885                 if (gss_rc == 0) break;
886         }
887
888         gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
889                             &conf_state,NULL);
890         if (scred) {
891                 ber_bvfree(scred);
892                 scred = NULL;
893         }
894         if (gss_rc) {
895                 status = ADS_ERROR_GSS(gss_rc, minor_status);
896                 goto failed;
897         }
898
899         p = (uint8_t *)output_token.value;
900
901 #if 0
902         file_save("sasl_gssapi.dat", output_token.value, output_token.length);
903 #endif
904
905         if (p) {
906                 wrap_type = CVAL(p,0);
907                 SCVAL(p,0,0);
908                 max_msg_size = RIVAL(p,0);
909         }
910
911         gss_release_buffer(&minor_status, &output_token);
912
913         if (!(wrap_type & ads->ldap.wrap_type)) {
914                 /*
915                  * the server doesn't supports the wrap
916                  * type we want :-(
917                  */
918                 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
919                         ads->ldap.wrap_type, wrap_type));
920                 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
921                 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
922                 goto failed;
923         }
924
925         /* 0x58 is the minimum windows accepts */
926         if (max_msg_size < 0x58) {
927                 max_msg_size = 0x58;
928         }
929
930         output_token.length = 4;
931         output_token.value = SMB_MALLOC(output_token.length);
932         if (!output_token.value) {
933                 output_token.length = 0;
934                 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
935                 goto failed;
936         }
937         p = (uint8_t *)output_token.value;
938
939         RSIVAL(p,0,max_msg_size);
940         SCVAL(p,0,ads->ldap.wrap_type);
941
942         /*
943          * we used to add sprintf("dn:%s", ads->config.bind_path) here.
944          * but using ads->config.bind_path is the wrong! It should be
945          * the DN of the user object!
946          *
947          * w2k3 gives an error when we send an incorrect DN, but sending nothing
948          * is ok and matches the information flow used in GSS-SPNEGO.
949          */
950
951         gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
952                         &output_token, /* used as *input* here. */
953                         &conf_state,
954                         &input_token); /* Used as *output* here. */
955         if (gss_rc) {
956                 status = ADS_ERROR_GSS(gss_rc, minor_status);
957                 output_token.length = 0;
958                 SAFE_FREE(output_token.value);
959                 goto failed;
960         }
961
962         /* We've finished with output_token. */
963         SAFE_FREE(output_token.value);
964         output_token.length = 0;
965
966         cred.bv_val = (char *)input_token.value;
967         cred.bv_len = input_token.length;
968
969         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL, 
970                               &scred);
971         gss_release_buffer(&minor_status, &input_token);
972         status = ADS_ERROR(rc);
973         if (!ADS_ERR_OK(status)) {
974                 goto failed;
975         }
976
977         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
978                 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
979                                              (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
980                                              GSS_C_QOP_DEFAULT,
981                                              max_msg_size, &ads->ldap.out.max_unwrapped);
982                 if (gss_rc) {
983                         status = ADS_ERROR_GSS(gss_rc, minor_status);
984                         goto failed;
985                 }
986
987                 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
988                 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
989                 ads->ldap.in.max_wrapped = max_msg_size;
990                 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
991                 if (!ADS_ERR_OK(status)) {
992                         DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
993                                 ads_errstr(status)));
994                         goto failed;
995                 }
996                 /* make sure we don't free context_handle */
997                 context_handle = GSS_C_NO_CONTEXT;
998         }
999
1000 failed:
1001         if (gss_cred != GSS_C_NO_CREDENTIAL)
1002                 gss_release_cred(&minor_status, &gss_cred);
1003         if (context_handle != GSS_C_NO_CONTEXT)
1004                 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1005
1006         if(scred)
1007                 ber_bvfree(scred);
1008         return status;
1009 }
1010
1011 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1012 {
1013         ADS_STATUS status;
1014         struct ads_service_principal p;
1015
1016         status = ads_generate_service_principal(ads, &p);
1017         if (!ADS_ERR_OK(status)) {
1018                 return status;
1019         }
1020
1021         status = ads_sasl_gssapi_do_bind(ads, p.name);
1022         if (ADS_ERR_OK(status)) {
1023                 ads_free_service_principal(&p);
1024                 return status;
1025         }
1026
1027         DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1028                   "calling kinit\n", ads_errstr(status)));
1029
1030         status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1031
1032         if (ADS_ERR_OK(status)) {
1033                 status = ads_sasl_gssapi_do_bind(ads, p.name);
1034         }
1035
1036         ads_free_service_principal(&p);
1037
1038         return status;
1039 }
1040
1041 #endif /* HAVE_KRB5 */
1042
1043 /* mapping between SASL mechanisms and functions */
1044 static struct {
1045         const char *name;
1046         ADS_STATUS (*fn)(ADS_STRUCT *);
1047 } sasl_mechanisms[] = {
1048         {"GSS-SPNEGO", ads_sasl_spnego_bind},
1049 #ifdef HAVE_KRB5
1050         {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1051 #endif
1052         {NULL, NULL}
1053 };
1054
1055 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1056 {
1057         const char *attrs[] = {"supportedSASLMechanisms", NULL};
1058         char **values;
1059         ADS_STATUS status;
1060         int i, j;
1061         LDAPMessage *res;
1062
1063         /* get a list of supported SASL mechanisms */
1064         status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1065         if (!ADS_ERR_OK(status)) return status;
1066
1067         values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1068
1069         if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1070                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1071         } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1072                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1073         } else {
1074                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1075         }
1076
1077         /* try our supported mechanisms in order */
1078         for (i=0;sasl_mechanisms[i].name;i++) {
1079                 /* see if the server supports it */
1080                 for (j=0;values && values[j];j++) {
1081                         if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1082                                 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1083 retry:
1084                                 status = sasl_mechanisms[i].fn(ads);
1085                                 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
1086                                     status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
1087                                     ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
1088                                 {
1089                                         DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1090                                                  "retrying with signing enabled\n"));
1091                                         ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1092                                         goto retry;
1093                                 }
1094                                 ldap_value_free(values);
1095                                 ldap_msgfree(res);
1096                                 return status;
1097                         }
1098                 }
1099         }
1100
1101         ldap_value_free(values);
1102         ldap_msgfree(res);
1103         return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1104 }
1105
1106 #endif /* HAVE_LDAP */
1107