s3:libads: don't use MEMORY:ads_sasl_gssapi_do_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                 const char *ccache_name = "MEMORY:ads_sasl_spnego_bind";
753                 if (ads->auth.ccache_name != NULL) {
754                         ccache_name = ads->auth.ccache_name;
755                 }
756
757                 if (ads->auth.password == NULL ||
758                     ads->auth.password[0] == '\0')
759                 {
760
761                         status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
762                                                              CRED_MUST_USE_KERBEROS,
763                                                              p.service, p.hostname,
764                                                              blob);
765                         if (ADS_ERR_OK(status)) {
766                                 ads_free_service_principal(&p);
767                                 goto done;
768                         }
769
770                         DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
771                                   "calling kinit\n", ads_errstr(status)));
772                 }
773
774                 setenv(KRB5_ENV_CCNAME, ccache_name, 1);
775                 status = ADS_ERROR_KRB5(ads_kinit_password(ads)); 
776
777                 if (ADS_ERR_OK(status)) {
778                         status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
779                                                         CRED_MUST_USE_KERBEROS,
780                                                         p.service, p.hostname,
781                                                         blob);
782                         if (!ADS_ERR_OK(status)) {
783                                 DEBUG(0,("kinit succeeded but "
784                                         "ads_sasl_spnego_gensec_bind(KRB5) failed: %s\n",
785                                         ads_errstr(status)));
786                         }
787                 }
788
789                 /* only fallback to NTLMSSP if allowed */
790                 if (ADS_ERR_OK(status) || 
791                     !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
792                         goto done;
793                 }
794         }
795 #endif
796
797         /* lets do NTLMSSP ... this has the big advantage that we don't need
798            to sync clocks, and we don't rely on special versions of the krb5 
799            library for HMAC_MD4 encryption */
800         status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
801                                              CRED_DONT_USE_KERBEROS,
802                                              p.service, p.hostname,
803                                              data_blob_null);
804 done:
805         ads_free_service_principal(&p);
806         TALLOC_FREE(frame);
807         if (blob.data != NULL) {
808                 data_blob_free(&blob);
809         }
810         return status;
811 }
812
813 #ifdef HAVE_KRB5
814 #define MAX_GSS_PASSES 3
815
816 /* this performs a SASL/gssapi bind
817    we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
818    is very dependent on correctly configured DNS whereas
819    this routine is much less fragile
820    see RFC2078 and RFC2222 for details
821 */
822 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
823 {
824         uint32_t minor_status;
825         gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
826         gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
827         gss_OID mech_type = GSS_C_NULL_OID;
828         gss_buffer_desc output_token, input_token;
829         uint32_t req_flags, ret_flags;
830         int conf_state;
831         struct berval cred;
832         struct berval *scred = NULL;
833         int i=0;
834         int gss_rc, rc;
835         uint8_t *p;
836         uint32_t max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
837         uint8_t wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
838         ADS_STATUS status;
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 & ads->ldap.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                         ads->ldap.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,ads->ldap.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 (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
993                 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
994                                              (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
995                                              GSS_C_QOP_DEFAULT,
996                                              max_msg_size, &ads->ldap.out.max_unwrapped);
997                 if (gss_rc) {
998                         status = ADS_ERROR_GSS(gss_rc, minor_status);
999                         goto failed;
1000                 }
1001
1002                 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
1003                 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
1004                 ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
1005                 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
1006                 if (!ADS_ERR_OK(status)) {
1007                         DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1008                                 ads_errstr(status)));
1009                         goto failed;
1010                 }
1011                 /* make sure we don't free context_handle */
1012                 context_handle = GSS_C_NO_CONTEXT;
1013         }
1014
1015 failed:
1016         if (gss_cred != GSS_C_NO_CREDENTIAL)
1017                 gss_release_cred(&minor_status, &gss_cred);
1018         if (context_handle != GSS_C_NO_CONTEXT)
1019                 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1020
1021         if(scred)
1022                 ber_bvfree(scred);
1023         return status;
1024 }
1025
1026 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1027 {
1028         ADS_STATUS status;
1029         struct ads_service_principal p;
1030
1031         status = ads_generate_service_principal(ads, &p);
1032         if (!ADS_ERR_OK(status)) {
1033                 return status;
1034         }
1035
1036         if (ads->auth.password == NULL ||
1037             ads->auth.password[0] == '\0') {
1038                 status = ads_sasl_gssapi_do_bind(ads, p.name);
1039                 if (ADS_ERR_OK(status)) {
1040                         ads_free_service_principal(&p);
1041                         return status;
1042                 }
1043
1044                 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1045                           "calling kinit\n", ads_errstr(status)));
1046         }
1047
1048         status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1049
1050         if (ADS_ERR_OK(status)) {
1051                 status = ads_sasl_gssapi_do_bind(ads, p.name);
1052         }
1053
1054         ads_free_service_principal(&p);
1055
1056         return status;
1057 }
1058
1059 #endif /* HAVE_KRB5 */
1060
1061 /* mapping between SASL mechanisms and functions */
1062 static struct {
1063         const char *name;
1064         ADS_STATUS (*fn)(ADS_STRUCT *);
1065 } sasl_mechanisms[] = {
1066         {"GSS-SPNEGO", ads_sasl_spnego_bind},
1067 #ifdef HAVE_KRB5
1068         {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1069 #endif
1070         {NULL, NULL}
1071 };
1072
1073 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1074 {
1075         const char *attrs[] = {"supportedSASLMechanisms", NULL};
1076         char **values;
1077         ADS_STATUS status;
1078         int i, j;
1079         LDAPMessage *res;
1080
1081         /* get a list of supported SASL mechanisms */
1082         status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1083         if (!ADS_ERR_OK(status)) return status;
1084
1085         values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1086
1087         if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1088                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1089         } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1090                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1091         } else {
1092                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1093         }
1094
1095         /* try our supported mechanisms in order */
1096         for (i=0;sasl_mechanisms[i].name;i++) {
1097                 /* see if the server supports it */
1098                 for (j=0;values && values[j];j++) {
1099                         if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1100                                 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1101 retry:
1102                                 status = sasl_mechanisms[i].fn(ads);
1103                                 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
1104                                     status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
1105                                     ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
1106                                 {
1107                                         DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1108                                                  "retrying with signing enabled\n"));
1109                                         ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1110                                         goto retry;
1111                                 }
1112                                 ldap_value_free(values);
1113                                 ldap_msgfree(res);
1114                                 return status;
1115                         }
1116                 }
1117         }
1118
1119         ldap_value_free(values);
1120         ldap_msgfree(res);
1121         return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1122 }
1123
1124 #endif /* HAVE_LDAP */
1125