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