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