Revert "smbd: make use of smbd_impersonate_{conn_vuid,conn_sess,root,guest}_create...
[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 #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 = smb_krb5_init_context_common(&kctx);
370         if (kerr) {
371             DBG_ERR("kerberos init context failed (%s)\n",
372                     error_message(kerr));
373                 return ADS_ERROR_KRB5(kerr);
374         }
375
376         kerr = krb5_cc_resolve(kctx, ads->auth.ccache_name, &kccache);
377         if (kerr) {
378                 status = ADS_ERROR_KRB5(kerr);
379                 goto done;
380         }
381
382         maj = smb_gss_krb5_import_cred(&min, kctx, kccache, NULL, NULL, cred);
383         if (maj != GSS_S_COMPLETE) {
384                 status = ADS_ERROR_GSS(maj, min);
385                 goto done;
386         }
387
388         status = ADS_SUCCESS;
389
390 done:
391         if (!ADS_ERR_OK(status) && kccache != NULL) {
392                 krb5_cc_close(kctx, kccache);
393         }
394         krb5_free_context(kctx);
395         return status;
396 }
397
398 static ADS_STATUS ads_sasl_gssapi_wrap(struct ads_saslwrap *wrap, uint8_t *buf, uint32_t len)
399 {
400         gss_ctx_id_t context_handle = (gss_ctx_id_t)wrap->wrap_private_data;
401         ADS_STATUS status;
402         int gss_rc;
403         uint32_t minor_status;
404         gss_buffer_desc unwrapped, wrapped;
405         int conf_req_flag, conf_state;
406
407         unwrapped.value         = buf;
408         unwrapped.length        = len;
409
410         /* for now request sign and seal */
411         conf_req_flag   = (wrap->wrap_type == ADS_SASLWRAP_TYPE_SEAL);
412
413         gss_rc = gss_wrap(&minor_status, context_handle,
414                           conf_req_flag, GSS_C_QOP_DEFAULT,
415                           &unwrapped, &conf_state,
416                           &wrapped);
417         status = ADS_ERROR_GSS(gss_rc, minor_status);
418         if (!ADS_ERR_OK(status)) return status;
419
420         if (conf_req_flag && conf_state == 0) {
421                 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
422         }
423
424         if ((wrap->out.size - 4) < wrapped.length) {
425                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
426         }
427
428         /* copy the wrapped blob to the right location */
429         memcpy(wrap->out.buf + 4, wrapped.value, wrapped.length);
430
431         /* set how many bytes must be written to the underlying socket */
432         wrap->out.left = 4 + wrapped.length;
433
434         gss_release_buffer(&minor_status, &wrapped);
435
436         return ADS_SUCCESS;
437 }
438
439 static ADS_STATUS ads_sasl_gssapi_unwrap(struct ads_saslwrap *wrap)
440 {
441         gss_ctx_id_t context_handle = (gss_ctx_id_t)wrap->wrap_private_data;
442         ADS_STATUS status;
443         int gss_rc;
444         uint32_t minor_status;
445         gss_buffer_desc unwrapped, wrapped;
446         int conf_state;
447
448         wrapped.value   = wrap->in.buf + 4;
449         wrapped.length  = wrap->in.ofs - 4;
450
451         gss_rc = gss_unwrap(&minor_status, context_handle,
452                             &wrapped, &unwrapped,
453                             &conf_state, GSS_C_QOP_DEFAULT);
454         status = ADS_ERROR_GSS(gss_rc, minor_status);
455         if (!ADS_ERR_OK(status)) return status;
456
457         if (wrap->wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
458                 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
459         }
460
461         if (wrapped.length < unwrapped.length) {
462                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
463         }
464
465         /* copy the wrapped blob to the right location */
466         memcpy(wrap->in.buf + 4, unwrapped.value, unwrapped.length);
467
468         /* set how many bytes must be written to the underlying socket */
469         wrap->in.left   = unwrapped.length;
470         wrap->in.ofs    = 4;
471
472         gss_release_buffer(&minor_status, &unwrapped);
473
474         return ADS_SUCCESS;
475 }
476
477 static void ads_sasl_gssapi_disconnect(struct ads_saslwrap *wrap)
478 {
479         gss_ctx_id_t context_handle = (gss_ctx_id_t)wrap->wrap_private_data;
480         uint32_t minor_status;
481
482         gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
483
484         wrap->wrap_ops = NULL;
485         wrap->wrap_private_data = NULL;
486 }
487
488 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
489         .name           = "gssapi",
490         .wrap           = ads_sasl_gssapi_wrap,
491         .unwrap         = ads_sasl_gssapi_unwrap,
492         .disconnect     = ads_sasl_gssapi_disconnect
493 };
494
495 #endif /* HAVE_KRB5 */
496
497 #ifdef HAVE_KRB5
498 struct ads_service_principal {
499         char *service;
500         char *hostname;
501         char *string;
502 #ifdef HAVE_KRB5
503         gss_name_t name;
504 #endif
505 };
506
507 static void ads_free_service_principal(struct ads_service_principal *p)
508 {
509         SAFE_FREE(p->service);
510         SAFE_FREE(p->hostname);
511         SAFE_FREE(p->string);
512
513 #ifdef HAVE_KRB5
514         if (p->name) {
515                 uint32_t minor_status;
516                 gss_release_name(&minor_status, &p->name);
517         }
518 #endif
519         ZERO_STRUCTP(p);
520 }
521
522 static ADS_STATUS ads_guess_target(ADS_STRUCT *ads,
523                                    char **service,
524                                    char **hostname,
525                                    char **principal)
526 {
527         ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY);
528         char *princ = NULL;
529         TALLOC_CTX *frame;
530         char *server = NULL;
531         char *realm = NULL;
532         int rc;
533
534         frame = talloc_stackframe();
535         if (frame == NULL) {
536                 return ADS_ERROR(LDAP_NO_MEMORY);
537         }
538
539         if (ads->server.realm && ads->server.ldap_server) {
540                 server = strlower_talloc(frame, ads->server.ldap_server);
541                 if (server == NULL) {
542                         goto out;
543                 }
544
545                 realm = strupper_talloc(frame, ads->server.realm);
546                 if (realm == NULL) {
547                         goto out;
548                 }
549
550                 /*
551                  * If we got a name which is bigger than a NetBIOS name,
552                  * but isn't a FQDN, create one.
553                  */
554                 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
555                         char *dnsdomain;
556
557                         dnsdomain = strlower_talloc(frame, ads->server.realm);
558                         if (dnsdomain == NULL) {
559                                 goto out;
560                         }
561
562                         server = talloc_asprintf(frame,
563                                                  "%s.%s",
564                                                  server, dnsdomain);
565                         if (server == NULL) {
566                                 goto out;
567                         }
568                 }
569         } else if (ads->config.realm && ads->config.ldap_server_name) {
570                 server = strlower_talloc(frame, ads->config.ldap_server_name);
571                 if (server == NULL) {
572                         goto out;
573                 }
574
575                 realm = strupper_talloc(frame, ads->config.realm);
576                 if (realm == NULL) {
577                         goto out;
578                 }
579
580                 /*
581                  * If we got a name which is bigger than a NetBIOS name,
582                  * but isn't a FQDN, create one.
583                  */
584                 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
585                         char *dnsdomain;
586
587                         dnsdomain = strlower_talloc(frame, ads->server.realm);
588                         if (dnsdomain == NULL) {
589                                 goto out;
590                         }
591
592                         server = talloc_asprintf(frame,
593                                                  "%s.%s",
594                                                  server, dnsdomain);
595                         if (server == NULL) {
596                                 goto out;
597                         }
598                 }
599         }
600
601         if (server == NULL || realm == NULL) {
602                 goto out;
603         }
604
605         *service = SMB_STRDUP("ldap");
606         if (*service == NULL) {
607                 status = ADS_ERROR(LDAP_PARAM_ERROR);
608                 goto out;
609         }
610         *hostname = SMB_STRDUP(server);
611         if (*hostname == NULL) {
612                 SAFE_FREE(*service);
613                 status = ADS_ERROR(LDAP_PARAM_ERROR);
614                 goto out;
615         }
616         rc = asprintf(&princ, "ldap/%s@%s", server, realm);
617         if (rc == -1 || princ == NULL) {
618                 SAFE_FREE(*service);
619                 SAFE_FREE(*hostname);
620                 status = ADS_ERROR(LDAP_PARAM_ERROR);
621                 goto out;
622         }
623
624         *principal = princ;
625
626         status = ADS_SUCCESS;
627 out:
628         TALLOC_FREE(frame);
629         return status;
630 }
631
632 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
633                                                  struct ads_service_principal *p)
634 {
635         ADS_STATUS status;
636 #ifdef HAVE_KRB5
637         gss_buffer_desc input_name;
638         /* GSS_KRB5_NT_PRINCIPAL_NAME */
639         gss_OID_desc nt_principal =
640         {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
641         uint32_t minor_status;
642         int gss_rc;
643 #endif
644
645         ZERO_STRUCTP(p);
646
647         status = ads_guess_target(ads,
648                                   &p->service,
649                                   &p->hostname,
650                                   &p->string);
651         if (!ADS_ERR_OK(status)) {
652                 return status;
653         }
654
655 #ifdef HAVE_KRB5
656         input_name.value = p->string;
657         input_name.length = strlen(p->string);
658
659         gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
660         if (gss_rc) {
661                 ads_free_service_principal(p);
662                 return ADS_ERROR_GSS(gss_rc, minor_status);
663         }
664 #endif
665
666         return ADS_SUCCESS;
667 }
668
669 #endif /* HAVE_KRB5 */
670
671 /* 
672    this performs a SASL/SPNEGO bind
673 */
674 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
675 {
676         TALLOC_CTX *frame = talloc_stackframe();
677         struct ads_service_principal p = {0};
678         struct berval *scred=NULL;
679         int rc, i;
680         ADS_STATUS status;
681         DATA_BLOB blob = data_blob_null;
682         char *given_principal = NULL;
683         char *OIDs[ASN1_MAX_OIDS];
684 #ifdef HAVE_KRB5
685         bool got_kerberos_mechanism = False;
686 #endif
687         const char *mech = NULL;
688
689         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
690
691         if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
692                 status = ADS_ERROR(rc);
693                 goto done;
694         }
695
696         blob = data_blob(scred->bv_val, scred->bv_len);
697
698         ber_bvfree(scred);
699
700 #if 0
701         file_save("sasl_spnego.dat", blob.data, blob.length);
702 #endif
703
704         /* the server sent us the first part of the SPNEGO exchange in the negprot 
705            reply */
706         if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
707                         OIDs[0] == NULL) {
708                 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
709                 goto done;
710         }
711         TALLOC_FREE(given_principal);
712
713         /* make sure the server understands kerberos */
714         for (i=0;OIDs[i];i++) {
715                 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
716 #ifdef HAVE_KRB5
717                 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
718                     strcmp(OIDs[i], OID_KERBEROS5) == 0) {
719                         got_kerberos_mechanism = True;
720                 }
721 #endif
722                 talloc_free(OIDs[i]);
723         }
724
725         status = ads_generate_service_principal(ads, &p);
726         if (!ADS_ERR_OK(status)) {
727                 goto done;
728         }
729
730 #ifdef HAVE_KRB5
731         if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
732             got_kerberos_mechanism) 
733         {
734                 mech = "KRB5";
735
736                 if (ads->auth.password == NULL ||
737                     ads->auth.password[0] == '\0')
738                 {
739
740                         status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
741                                                              CRED_MUST_USE_KERBEROS,
742                                                              p.service, p.hostname,
743                                                              blob);
744                         if (ADS_ERR_OK(status)) {
745                                 ads_free_service_principal(&p);
746                                 goto done;
747                         }
748
749                         DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
750                                   "calling kinit\n", ads_errstr(status)));
751                 }
752
753                 status = ADS_ERROR_KRB5(ads_kinit_password(ads)); 
754
755                 if (ADS_ERR_OK(status)) {
756                         status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
757                                                         CRED_MUST_USE_KERBEROS,
758                                                         p.service, p.hostname,
759                                                         blob);
760                         if (!ADS_ERR_OK(status)) {
761                                 DEBUG(0,("kinit succeeded but "
762                                         "ads_sasl_spnego_gensec_bind(KRB5) failed "
763                                         "for %s/%s with user[%s] realm[%s]: %s\n",
764                                         p.service, p.hostname,
765                                         ads->auth.user_name,
766                                         ads->auth.realm,
767                                         ads_errstr(status)));
768                         }
769                 }
770
771                 /* only fallback to NTLMSSP if allowed */
772                 if (ADS_ERR_OK(status) || 
773                     !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
774                         goto done;
775                 }
776
777                 DEBUG(1,("ads_sasl_spnego_gensec_bind(KRB5) failed "
778                          "for %s/%s with user[%s] realm[%s]: %s, "
779                          "fallback to NTLMSSP\n",
780                          p.service, p.hostname,
781                          ads->auth.user_name,
782                          ads->auth.realm,
783                          ads_errstr(status)));
784         }
785 #endif
786
787         /* lets do NTLMSSP ... this has the big advantage that we don't need
788            to sync clocks, and we don't rely on special versions of the krb5 
789            library for HMAC_MD4 encryption */
790         mech = "NTLMSSP";
791         status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
792                                              CRED_DONT_USE_KERBEROS,
793                                              p.service, p.hostname,
794                                              data_blob_null);
795 done:
796         if (!ADS_ERR_OK(status)) {
797                 DEBUG(1,("ads_sasl_spnego_gensec_bind(%s) failed "
798                          "for %s/%s with user[%s] realm=[%s]: %s\n", mech,
799                           p.service, p.hostname,
800                           ads->auth.user_name,
801                           ads->auth.realm,
802                           ads_errstr(status)));
803         }
804         ads_free_service_principal(&p);
805         TALLOC_FREE(frame);
806         if (blob.data != NULL) {
807                 data_blob_free(&blob);
808         }
809         return status;
810 }
811
812 #ifdef HAVE_KRB5
813 #define MAX_GSS_PASSES 3
814
815 /* this performs a SASL/gssapi bind
816    we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
817    is very dependent on correctly configured DNS whereas
818    this routine is much less fragile
819    see RFC2078 and RFC2222 for details
820 */
821 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
822 {
823         uint32_t minor_status;
824         gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
825         gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
826         gss_OID mech_type = GSS_C_NULL_OID;
827         gss_buffer_desc output_token, input_token;
828         uint32_t req_flags, ret_flags;
829         int conf_state;
830         struct berval cred;
831         struct berval *scred = NULL;
832         int i=0;
833         int gss_rc, rc;
834         uint8_t *p;
835         uint32_t max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
836         uint8_t wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
837         ADS_STATUS status;
838         struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
839
840         input_token.value = NULL;
841         input_token.length = 0;
842
843         status = ads_init_gssapi_cred(ads, &gss_cred);
844         if (!ADS_ERR_OK(status)) {
845                 goto failed;
846         }
847
848         /*
849          * Note: here we always ask the gssapi for sign and seal
850          *       as this is negotiated later after the mutal
851          *       authentication
852          */
853         req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
854
855         for (i=0; i < MAX_GSS_PASSES; i++) {
856                 gss_rc = gss_init_sec_context(&minor_status,
857                                           gss_cred,
858                                           &context_handle,
859                                           serv_name,
860                                           mech_type,
861                                           req_flags,
862                                           0,
863                                           NULL,
864                                           &input_token,
865                                           NULL,
866                                           &output_token,
867                                           &ret_flags,
868                                           NULL);
869                 if (scred) {
870                         ber_bvfree(scred);
871                         scred = NULL;
872                 }
873                 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
874                         status = ADS_ERROR_GSS(gss_rc, minor_status);
875                         goto failed;
876                 }
877
878                 cred.bv_val = (char *)output_token.value;
879                 cred.bv_len = output_token.length;
880
881                 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL, 
882                                       &scred);
883                 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
884                         status = ADS_ERROR(rc);
885                         goto failed;
886                 }
887
888                 if (output_token.value) {
889                         gss_release_buffer(&minor_status, &output_token);
890                 }
891
892                 if (scred) {
893                         input_token.value = scred->bv_val;
894                         input_token.length = scred->bv_len;
895                 } else {
896                         input_token.value = NULL;
897                         input_token.length = 0;
898                 }
899
900                 if (gss_rc == 0) break;
901         }
902
903         gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
904                             &conf_state,NULL);
905         if (scred) {
906                 ber_bvfree(scred);
907                 scred = NULL;
908         }
909         if (gss_rc) {
910                 status = ADS_ERROR_GSS(gss_rc, minor_status);
911                 goto failed;
912         }
913
914         p = (uint8_t *)output_token.value;
915
916 #if 0
917         file_save("sasl_gssapi.dat", output_token.value, output_token.length);
918 #endif
919
920         if (p) {
921                 wrap_type = CVAL(p,0);
922                 SCVAL(p,0,0);
923                 max_msg_size = RIVAL(p,0);
924         }
925
926         gss_release_buffer(&minor_status, &output_token);
927
928         if (!(wrap_type & wrap->wrap_type)) {
929                 /*
930                  * the server doesn't supports the wrap
931                  * type we want :-(
932                  */
933                 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
934                         wrap->wrap_type, wrap_type));
935                 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
936                 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
937                 goto failed;
938         }
939
940         /* 0x58 is the minimum windows accepts */
941         if (max_msg_size < 0x58) {
942                 max_msg_size = 0x58;
943         }
944
945         output_token.length = 4;
946         output_token.value = SMB_MALLOC(output_token.length);
947         if (!output_token.value) {
948                 output_token.length = 0;
949                 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
950                 goto failed;
951         }
952         p = (uint8_t *)output_token.value;
953
954         RSIVAL(p,0,max_msg_size);
955         SCVAL(p,0,wrap->wrap_type);
956
957         /*
958          * we used to add sprintf("dn:%s", ads->config.bind_path) here.
959          * but using ads->config.bind_path is the wrong! It should be
960          * the DN of the user object!
961          *
962          * w2k3 gives an error when we send an incorrect DN, but sending nothing
963          * is ok and matches the information flow used in GSS-SPNEGO.
964          */
965
966         gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
967                         &output_token, /* used as *input* here. */
968                         &conf_state,
969                         &input_token); /* Used as *output* here. */
970         if (gss_rc) {
971                 status = ADS_ERROR_GSS(gss_rc, minor_status);
972                 output_token.length = 0;
973                 SAFE_FREE(output_token.value);
974                 goto failed;
975         }
976
977         /* We've finished with output_token. */
978         SAFE_FREE(output_token.value);
979         output_token.length = 0;
980
981         cred.bv_val = (char *)input_token.value;
982         cred.bv_len = input_token.length;
983
984         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL, 
985                               &scred);
986         gss_release_buffer(&minor_status, &input_token);
987         status = ADS_ERROR(rc);
988         if (!ADS_ERR_OK(status)) {
989                 goto failed;
990         }
991
992         if (wrap->wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
993                 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
994                                              (wrap->wrap_type == ADS_SASLWRAP_TYPE_SEAL),
995                                              GSS_C_QOP_DEFAULT,
996                                              max_msg_size, &wrap->out.max_unwrapped);
997                 if (gss_rc) {
998                         status = ADS_ERROR_GSS(gss_rc, minor_status);
999                         goto failed;
1000                 }
1001
1002                 wrap->out.sig_size = max_msg_size - wrap->out.max_unwrapped;
1003                 wrap->in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
1004                 wrap->in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
1005                 status = ads_setup_sasl_wrapping(wrap->wrap_private_data, ads->ldap.ld,
1006                                                  &ads_sasl_gssapi_ops,
1007                                                  context_handle);
1008                 if (!ADS_ERR_OK(status)) {
1009                         DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1010                                 ads_errstr(status)));
1011                         goto failed;
1012                 }
1013                 /* make sure we don't free context_handle */
1014                 context_handle = GSS_C_NO_CONTEXT;
1015         }
1016
1017 failed:
1018         if (gss_cred != GSS_C_NO_CREDENTIAL)
1019                 gss_release_cred(&minor_status, &gss_cred);
1020         if (context_handle != GSS_C_NO_CONTEXT)
1021                 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1022
1023         if(scred)
1024                 ber_bvfree(scred);
1025         return status;
1026 }
1027
1028 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1029 {
1030         ADS_STATUS status;
1031         struct ads_service_principal p;
1032
1033         status = ads_generate_service_principal(ads, &p);
1034         if (!ADS_ERR_OK(status)) {
1035                 return status;
1036         }
1037
1038         if (ads->auth.password == NULL ||
1039             ads->auth.password[0] == '\0') {
1040                 status = ads_sasl_gssapi_do_bind(ads, p.name);
1041                 if (ADS_ERR_OK(status)) {
1042                         ads_free_service_principal(&p);
1043                         return status;
1044                 }
1045
1046                 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1047                           "calling kinit\n", ads_errstr(status)));
1048         }
1049
1050         status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1051
1052         if (ADS_ERR_OK(status)) {
1053                 status = ads_sasl_gssapi_do_bind(ads, p.name);
1054         }
1055
1056         ads_free_service_principal(&p);
1057
1058         return status;
1059 }
1060
1061 #endif /* HAVE_KRB5 */
1062
1063 /* mapping between SASL mechanisms and functions */
1064 static struct {
1065         const char *name;
1066         ADS_STATUS (*fn)(ADS_STRUCT *);
1067 } sasl_mechanisms[] = {
1068         {"GSS-SPNEGO", ads_sasl_spnego_bind},
1069 #ifdef HAVE_KRB5
1070         {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1071 #endif
1072         {NULL, NULL}
1073 };
1074
1075 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1076 {
1077         const char *attrs[] = {"supportedSASLMechanisms", NULL};
1078         char **values;
1079         ADS_STATUS status;
1080         int i, j;
1081         LDAPMessage *res;
1082         struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
1083
1084         /* get a list of supported SASL mechanisms */
1085         status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1086         if (!ADS_ERR_OK(status)) return status;
1087
1088         values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1089
1090         if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1091                 wrap->wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1092         } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1093                 wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1094         } else {
1095                 wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1096         }
1097
1098         /* try our supported mechanisms in order */
1099         for (i=0;sasl_mechanisms[i].name;i++) {
1100                 /* see if the server supports it */
1101                 for (j=0;values && values[j];j++) {
1102                         if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1103                                 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1104 retry:
1105                                 status = sasl_mechanisms[i].fn(ads);
1106                                 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
1107                                     status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
1108                                     wrap->wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
1109                                 {
1110                                         DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1111                                                  "retrying with signing enabled\n"));
1112                                         wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1113                                         goto retry;
1114                                 }
1115                                 ldap_value_free(values);
1116                                 ldap_msgfree(res);
1117                                 return status;
1118                         }
1119                 }
1120         }
1121
1122         ldap_value_free(values);
1123         ldap_msgfree(res);
1124         return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1125 }
1126
1127 #endif /* HAVE_LDAP */
1128