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