123ad491fb34d28833cfde8ae13c18557a009bb5
[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
22 #ifdef HAVE_LDAP
23
24 static ADS_STATUS ads_sasl_ntlmssp_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
25 {
26         struct ntlmssp_state *ntlmssp_state =
27                 (struct ntlmssp_state *)ads->ldap.wrap_private_data;
28         ADS_STATUS status;
29         NTSTATUS nt_status;
30         DATA_BLOB sig;
31         uint8 *dptr = ads->ldap.out.buf + (4 + NTLMSSP_SIG_SIZE);
32
33         /* copy the data to the right location */
34         memcpy(dptr, buf, len);
35
36         /* create the signature and may encrypt the data */
37         if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
38                 nt_status = ntlmssp_seal_packet(ntlmssp_state,
39                                                 dptr, len,
40                                                 dptr, len,
41                                                 &sig);
42         } else {
43                 nt_status = ntlmssp_sign_packet(ntlmssp_state,
44                                                 dptr, len,
45                                                 dptr, len,
46                                                 &sig);
47         }
48         status = ADS_ERROR_NT(nt_status);
49         if (!ADS_ERR_OK(status)) return status;
50
51         /* copy the signature to the right location */
52         memcpy(ads->ldap.out.buf + 4,
53                sig.data, NTLMSSP_SIG_SIZE);
54
55         data_blob_free(&sig);
56
57         /* set how many bytes must be written to the underlying socket */
58         ads->ldap.out.left = 4 + NTLMSSP_SIG_SIZE + len;
59
60         return ADS_SUCCESS;
61 }
62
63 static ADS_STATUS ads_sasl_ntlmssp_unwrap(ADS_STRUCT *ads)
64 {
65         struct ntlmssp_state *ntlmssp_state =
66                 (struct ntlmssp_state *)ads->ldap.wrap_private_data;
67         ADS_STATUS status;
68         NTSTATUS nt_status;
69         DATA_BLOB sig;
70         uint8 *dptr = ads->ldap.in.buf + (4 + NTLMSSP_SIG_SIZE);
71         uint32 dlen = ads->ldap.in.ofs - (4 + NTLMSSP_SIG_SIZE);
72
73         /* wrap the signature into a DATA_BLOB */
74         sig = data_blob_const(ads->ldap.in.buf + 4, NTLMSSP_SIG_SIZE);
75
76         /* verify the signature and maybe decrypt the data */
77         if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
78                 nt_status = ntlmssp_unseal_packet(ntlmssp_state,
79                                                   dptr, dlen,
80                                                   dptr, dlen,
81                                                   &sig);
82         } else {
83                 nt_status = ntlmssp_check_packet(ntlmssp_state,
84                                                  dptr, dlen,
85                                                  dptr, dlen,
86                                                  &sig);
87         }
88         status = ADS_ERROR_NT(nt_status);
89         if (!ADS_ERR_OK(status)) return status;
90
91         /* set the amount of bytes for the upper layer and set the ofs to the data */
92         ads->ldap.in.left       = dlen;
93         ads->ldap.in.ofs        = 4 + NTLMSSP_SIG_SIZE;
94
95         return ADS_SUCCESS;
96 }
97
98 static void ads_sasl_ntlmssp_disconnect(ADS_STRUCT *ads)
99 {
100         struct ntlmssp_state *ntlmssp_state =
101                 (struct ntlmssp_state *)ads->ldap.wrap_private_data;
102
103         ntlmssp_end(&ntlmssp_state);
104
105         ads->ldap.wrap_ops = NULL;
106         ads->ldap.wrap_private_data = NULL;
107 }
108
109 static const struct ads_saslwrap_ops ads_sasl_ntlmssp_ops = {
110         .name           = "ntlmssp",
111         .wrap           = ads_sasl_ntlmssp_wrap,
112         .unwrap         = ads_sasl_ntlmssp_unwrap,
113         .disconnect     = ads_sasl_ntlmssp_disconnect
114 };
115
116 /* 
117    perform a LDAP/SASL/SPNEGO/NTLMSSP bind (just how many layers can
118    we fit on one socket??)
119 */
120 static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
121 {
122         DATA_BLOB msg1 = data_blob_null;
123         DATA_BLOB blob = data_blob_null;
124         DATA_BLOB blob_in = data_blob_null;
125         DATA_BLOB blob_out = data_blob_null;
126         struct berval cred, *scred = NULL;
127         int rc;
128         NTSTATUS nt_status;
129         ADS_STATUS status;
130         int turn = 1;
131         uint32 features = 0;
132
133         struct ntlmssp_state *ntlmssp_state;
134
135         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) {
136                 return ADS_ERROR_NT(nt_status);
137         }
138         ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SIGN;
139
140         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, ads->auth.user_name))) {
141                 return ADS_ERROR_NT(nt_status);
142         }
143         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, ads->auth.realm))) {
144                 return ADS_ERROR_NT(nt_status);
145         }
146         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, ads->auth.password))) {
147                 return ADS_ERROR_NT(nt_status);
148         }
149
150         switch (ads->ldap.wrap_type) {
151         case ADS_SASLWRAP_TYPE_SEAL:
152                 features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
153                 break;
154         case ADS_SASLWRAP_TYPE_SIGN:
155                 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
156                         features = NTLMSSP_FEATURE_SIGN;
157                 } else {
158                         /*
159                          * windows servers are broken with sign only,
160                          * so we need to use seal here too
161                          */
162                         features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
163                         ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
164                 }
165                 break;
166         case ADS_SASLWRAP_TYPE_PLAIN:
167                 break;
168         }
169
170         ntlmssp_want_feature(ntlmssp_state, features);
171
172         blob_in = data_blob_null;
173
174         do {
175                 nt_status = ntlmssp_update(ntlmssp_state, 
176                                            blob_in, &blob_out);
177                 data_blob_free(&blob_in);
178                 if ((NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) 
179                      || NT_STATUS_IS_OK(nt_status))
180                     && blob_out.length) {
181                         if (turn == 1) {
182                                 /* and wrap it in a SPNEGO wrapper */
183                                 msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
184                         } else {
185                                 /* wrap it in SPNEGO */
186                                 msg1 = spnego_gen_auth(blob_out);
187                         }
188
189                         data_blob_free(&blob_out);
190
191                         cred.bv_val = (char *)msg1.data;
192                         cred.bv_len = msg1.length;
193                         scred = NULL;
194                         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
195                         data_blob_free(&msg1);
196                         if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
197                                 if (scred) {
198                                         ber_bvfree(scred);
199                                 }
200
201                                 ntlmssp_end(&ntlmssp_state);
202                                 return ADS_ERROR(rc);
203                         }
204                         if (scred) {
205                                 blob = data_blob(scred->bv_val, scred->bv_len);
206                                 ber_bvfree(scred);
207                         } else {
208                                 blob = data_blob_null;
209                         }
210
211                 } else {
212
213                         ntlmssp_end(&ntlmssp_state);
214                         data_blob_free(&blob_out);
215                         return ADS_ERROR_NT(nt_status);
216                 }
217                 
218                 if ((turn == 1) && 
219                     (rc == LDAP_SASL_BIND_IN_PROGRESS)) {
220                         DATA_BLOB tmp_blob = data_blob_null;
221                         /* the server might give us back two challenges */
222                         if (!spnego_parse_challenge(blob, &blob_in, 
223                                                     &tmp_blob)) {
224
225                                 ntlmssp_end(&ntlmssp_state);
226                                 data_blob_free(&blob);
227                                 DEBUG(3,("Failed to parse challenges\n"));
228                                 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
229                         }
230                         data_blob_free(&tmp_blob);
231                 } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) {
232                         if (!spnego_parse_auth_response(blob, nt_status, OID_NTLMSSP, 
233                                                         &blob_in)) {
234
235                                 ntlmssp_end(&ntlmssp_state);
236                                 data_blob_free(&blob);
237                                 DEBUG(3,("Failed to parse auth response\n"));
238                                 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
239                         }
240                 }
241                 data_blob_free(&blob);
242                 data_blob_free(&blob_out);
243                 turn++;
244         } while (rc == LDAP_SASL_BIND_IN_PROGRESS && !NT_STATUS_IS_OK(nt_status));
245         
246         /* we have a reference conter on ntlmssp_state, if we are signing
247            then the state will be kept by the signing engine */
248
249         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
250                 ads->ldap.out.max_unwrapped = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED - NTLMSSP_SIG_SIZE;
251                 ads->ldap.out.sig_size = NTLMSSP_SIG_SIZE;
252                 ads->ldap.in.min_wrapped = ads->ldap.out.sig_size;
253                 ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
254                 status = ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, ntlmssp_state);
255                 if (!ADS_ERR_OK(status)) {
256                         DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
257                                 ads_errstr(status)));
258                         ntlmssp_end(&ntlmssp_state);
259                         return status;
260                 }
261         } else {
262                 ntlmssp_end(&ntlmssp_state);
263         }
264
265         return ADS_ERROR(rc);
266 }
267
268 #ifdef HAVE_GSSAPI
269 static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
270 {
271         gss_ctx_id_t context_handle = ads->ldap.wrap_private_data;
272         ADS_STATUS status;
273         int gss_rc;
274         uint32 minor_status;
275         gss_buffer_desc unwrapped, wrapped;
276         int conf_req_flag, conf_state;
277
278         unwrapped.value         = buf;
279         unwrapped.length        = len;
280
281         /* for now request sign and seal */
282         conf_req_flag   = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
283
284         gss_rc = gss_wrap(&minor_status, context_handle,
285                           conf_req_flag, GSS_C_QOP_DEFAULT,
286                           &unwrapped, &conf_state,
287                           &wrapped);
288         status = ADS_ERROR_GSS(gss_rc, minor_status);
289         if (!ADS_ERR_OK(status)) return status;
290
291         if (conf_req_flag && conf_state == 0) {
292                 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
293         }
294
295         if ((ads->ldap.out.size - 4) < wrapped.length) {
296                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
297         }
298
299         /* copy the wrapped blob to the right location */
300         memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
301
302         /* set how many bytes must be written to the underlying socket */
303         ads->ldap.out.left = 4 + wrapped.length;
304
305         gss_release_buffer(&minor_status, &wrapped);
306
307         return ADS_SUCCESS;
308 }
309
310 static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
311 {
312         gss_ctx_id_t context_handle = ads->ldap.wrap_private_data;
313         ADS_STATUS status;
314         int gss_rc;
315         uint32 minor_status;
316         gss_buffer_desc unwrapped, wrapped;
317         int conf_state;
318
319         wrapped.value   = ads->ldap.in.buf + 4;
320         wrapped.length  = ads->ldap.in.ofs - 4;
321
322         gss_rc = gss_unwrap(&minor_status, context_handle,
323                             &wrapped, &unwrapped,
324                             &conf_state, GSS_C_QOP_DEFAULT);
325         status = ADS_ERROR_GSS(gss_rc, minor_status);
326         if (!ADS_ERR_OK(status)) return status;
327
328         if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
329                 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
330         }
331
332         if (wrapped.length < wrapped.length) {
333                 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
334         }
335
336         /* copy the wrapped blob to the right location */
337         memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
338
339         /* set how many bytes must be written to the underlying socket */
340         ads->ldap.in.left       = unwrapped.length;
341         ads->ldap.in.ofs        = 4;
342
343         gss_release_buffer(&minor_status, &unwrapped);
344
345         return ADS_SUCCESS;
346 }
347
348 static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
349 {
350         gss_ctx_id_t context_handle = ads->ldap.wrap_private_data;
351         uint32 minor_status;
352
353         gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
354
355         ads->ldap.wrap_ops = NULL;
356         ads->ldap.wrap_private_data = NULL;
357 }
358
359 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
360         .name           = "gssapi",
361         .wrap           = ads_sasl_gssapi_wrap,
362         .unwrap         = ads_sasl_gssapi_unwrap,
363         .disconnect     = ads_sasl_gssapi_disconnect
364 };
365
366 /* 
367    perform a LDAP/SASL/SPNEGO/GSSKRB5 bind
368 */
369 static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
370 {
371         ADS_STATUS status;
372         BOOL ok;
373         uint32 minor_status;
374         int gss_rc, rc;
375         gss_OID_desc krb5_mech_type =
376         {9, CONST_DISCARD(char *, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
377         gss_OID mech_type = &krb5_mech_type;
378         gss_OID actual_mech_type = GSS_C_NULL_OID;
379         const char *spnego_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL};
380         gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
381         gss_buffer_desc input_token, output_token;
382         uint32 req_flags, ret_flags;
383         uint32 req_tmp, ret_tmp;
384         DATA_BLOB unwrapped;
385         DATA_BLOB wrapped;
386         struct berval cred, *scred = NULL;
387
388         input_token.value = NULL;
389         input_token.length = 0;
390
391         req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
392         switch (ads->ldap.wrap_type) {
393         case ADS_SASLWRAP_TYPE_SEAL:
394                 req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
395                 break;
396         case ADS_SASLWRAP_TYPE_SIGN:
397                 req_flags |= GSS_C_INTEG_FLAG;
398                 break;
399         case ADS_SASLWRAP_TYPE_PLAIN:
400                 break;
401         }
402
403         /* Note: here we explicit ask for the krb5 mech_type */
404         gss_rc = gss_init_sec_context(&minor_status,
405                                       GSS_C_NO_CREDENTIAL,
406                                       &context_handle,
407                                       serv_name,
408                                       mech_type,
409                                       req_flags,
410                                       0,
411                                       NULL,
412                                       &input_token,
413                                       &actual_mech_type,
414                                       &output_token,
415                                       &ret_flags,
416                                       NULL);
417         if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
418                 status = ADS_ERROR_GSS(gss_rc, minor_status);
419                 goto failed;
420         }
421
422         /*
423          * As some gssapi krb5 mech implementations
424          * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG
425          * to req_flags internaly, it's not possible to
426          * use plain or signing only connection via
427          * the gssapi interface.
428          *
429          * Because of this we need to check it the ret_flags
430          * has more flags as req_flags and correct the value
431          * of ads->ldap.wrap_type.
432          *
433          * I ads->auth.flags has ADS_AUTH_SASL_FORCE
434          * we need to give an error.
435          */
436         req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
437         ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
438
439         if (req_tmp == ret_tmp) {
440                 /* everythings fine... */
441
442         } else if (req_flags & GSS_C_CONF_FLAG) {
443                 /*
444                  * here we wanted sealing but didn't got it
445                  * from the gssapi library
446                  */
447                 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
448                 goto failed;
449
450         } else if ((req_flags & GSS_C_INTEG_FLAG) &&
451                    !(ret_flags & GSS_C_INTEG_FLAG)) {
452                 /*
453                  * here we wanted siging but didn't got it
454                  * from the gssapi library
455                  */
456                 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
457                 goto failed;
458
459         } else if (ret_flags & GSS_C_CONF_FLAG) {
460                 /*
461                  * here we didn't want sealing
462                  * but the gssapi library forces it
463                  * so correct the needed wrap_type if
464                  * the caller didn't forced siging only
465                  */
466                 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
467                         status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
468                         goto failed;
469                 }
470
471                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
472                 req_flags = ret_flags;
473
474         } else if (ret_flags & GSS_C_INTEG_FLAG) {
475                 /*
476                  * here we didn't want signing
477                  * but the gssapi library forces it
478                  * so correct the needed wrap_type if
479                  * the caller didn't forced plain
480                  */
481                 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
482                         status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
483                         goto failed;
484                 }
485
486                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
487                 req_flags = ret_flags;
488         } else {
489                 /*
490                  * This could (should?) not happen
491                  */
492                 status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
493                 goto failed;
494         
495         }
496
497         /* and wrap that in a shiny SPNEGO wrapper */
498         unwrapped = data_blob_const(output_token.value, output_token.length);
499         wrapped = gen_negTokenTarg(spnego_mechs, unwrapped);
500         gss_release_buffer(&minor_status, &output_token);
501         if (unwrapped.length > wrapped.length) {
502                 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
503                 goto failed;
504         }
505
506         cred.bv_val = (char *)wrapped.data;
507         cred.bv_len = wrapped.length;
508
509         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, 
510                               &scred);
511         data_blob_free(&wrapped);
512         if (rc != LDAP_SUCCESS) {
513                 status = ADS_ERROR(rc);
514                 goto failed;
515         }
516
517         if (scred) {
518                 wrapped = data_blob_const(scred->bv_val, scred->bv_len);
519         } else {
520                 wrapped = data_blob_null;
521         }
522
523         ok = spnego_parse_auth_response(wrapped, NT_STATUS_OK,
524                                         OID_KERBEROS5_OLD,
525                                         &unwrapped);
526         if (scred) ber_bvfree(scred);
527         if (!ok) {
528                 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
529                 goto failed;
530         }
531
532         input_token.value       = unwrapped.data;
533         input_token.length      = unwrapped.length;
534
535         /* 
536          * As we asked for mutal authentication
537          * we need to pass the servers response
538          * to gssapi
539          */
540         gss_rc = gss_init_sec_context(&minor_status,
541                                       GSS_C_NO_CREDENTIAL,
542                                       &context_handle,
543                                       serv_name,
544                                       mech_type,
545                                       req_flags,
546                                       0,
547                                       NULL,
548                                       &input_token,
549                                       &actual_mech_type,
550                                       &output_token,
551                                       &ret_flags,
552                                       NULL);
553         data_blob_free(&unwrapped);
554         if (gss_rc) {
555                 status = ADS_ERROR_GSS(gss_rc, minor_status);
556                 goto failed;
557         }
558
559         gss_release_buffer(&minor_status, &output_token);
560
561         /*
562          * If we the sign and seal options
563          * doesn't match after getting the response
564          * from the server, we don't want to use the connection
565          */
566         req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
567         ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
568
569         if (req_tmp != ret_tmp) {
570                 /* everythings fine... */
571                 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
572                 goto failed;
573         }
574
575         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
576                 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
577
578                 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
579                                              (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
580                                              GSS_C_QOP_DEFAULT,
581                                              max_msg_size, &ads->ldap.out.max_unwrapped);
582                 if (gss_rc) {
583                         status = ADS_ERROR_GSS(gss_rc, minor_status);
584                         goto failed;
585                 }
586
587                 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
588                 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
589                 ads->ldap.in.max_wrapped = max_msg_size;
590                 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
591                 if (!ADS_ERR_OK(status)) {
592                         DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
593                                 ads_errstr(status)));
594                         goto failed;
595                 }
596                 /* make sure we don't free context_handle */
597                 context_handle = GSS_C_NO_CONTEXT;
598         }
599
600 failed:
601         if (context_handle != GSS_C_NO_CONTEXT)
602                 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
603         return status;
604 }
605
606 #endif /* HAVE_GSSAPI */
607
608 #ifdef HAVE_KRB5
609 struct ads_service_principal {
610          krb5_context ctx;
611          char *string;
612          krb5_principal principal;
613 #ifdef HAVE_GSSAPI
614          gss_name_t name;
615 #endif
616 };
617
618 static void ads_free_service_principal(struct ads_service_principal *p)
619 {
620         SAFE_FREE(p->string);
621
622 #ifdef HAVE_GSSAPI
623         if (p->name) {
624                 uint32 minor_status;
625                 gss_release_name(&minor_status, &p->name);
626         }
627 #endif
628         if (p->principal) {
629                 krb5_free_principal(p->ctx, p->principal);
630         }
631
632         if (p->ctx) {
633                 krb5_free_context(p->ctx);
634         }
635
636         ZERO_STRUCTP(p);
637 }
638
639 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
640                                                  const char *given_principal,
641                                                  struct ads_service_principal *p)
642 {
643         ADS_STATUS status;
644         krb5_enctype enc_types[] = {
645 #ifdef ENCTYPE_ARCFOUR_HMAC
646                         ENCTYPE_ARCFOUR_HMAC,
647 #endif
648                         ENCTYPE_DES_CBC_MD5,
649                         ENCTYPE_NULL};
650 #ifdef HAVE_GSSAPI
651         gss_buffer_desc input_name;
652         gss_OID_desc nt_principal = 
653         {10, CONST_DISCARD(char *, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
654         uint32 minor_status;
655         int gss_rc;
656 #endif
657
658         ZERO_STRUCTP(p);
659
660         /* I've seen a child Windows 2000 domain not send
661            the principal name back in the first round of
662            the SASL bind reply.  So we guess based on server
663            name and realm.  --jerry  */
664         /* Also try best guess when we get the w2k8 ignore
665            principal back - gd */
666
667         if (!given_principal ||
668             strequal(given_principal, ADS_IGNORE_PRINCIPAL)) {
669
670                 status = ads_guess_service_principal(ads, given_principal,
671                                                      &p->string);
672                 if (!ADS_ERR_OK(status)) {
673                         return status;
674                 }
675         } else {
676                 p->string = SMB_STRDUP(given_principal);
677                 if (!p->string) {
678                         return ADS_ERROR(LDAP_NO_MEMORY);
679                 }
680         }
681
682         initialize_krb5_error_table();
683         status = ADS_ERROR_KRB5(krb5_init_context(&p->ctx));
684         if (!ADS_ERR_OK(status)) {
685                 ads_free_service_principal(p);
686                 return status;
687         }
688         status = ADS_ERROR_KRB5(krb5_set_default_tgs_ktypes(p->ctx, enc_types));
689         if (!ADS_ERR_OK(status)) {
690                 ads_free_service_principal(p);
691                 return status;
692         }
693         status = ADS_ERROR_KRB5(smb_krb5_parse_name(p->ctx, p->string, &p->principal));
694         if (!ADS_ERR_OK(status)) {
695                 ads_free_service_principal(p);
696                 return status;
697         }
698
699 #ifdef HAVE_GSSAPI
700         /*
701          * The MIT libraries have a *HORRIBLE* bug - input_value.value needs
702          * to point to the *address* of the krb5_principal, and the gss libraries
703          * to a shallow copy of the krb5_principal pointer - so we need to keep
704          * the krb5_principal around until we do the gss_release_name. MIT *SUCKS* !
705          * Just one more way in which MIT engineers screwed me over.... JRA.
706          *
707          * That's the reason for principal not beeing a local var in this function
708          */
709         input_name.value = &p->principal;
710         input_name.length = sizeof(p->principal);
711
712         gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
713         if (gss_rc) {
714                 ads_free_service_principal(p);
715                 return ADS_ERROR_GSS(gss_rc, minor_status);
716         }
717 #endif
718
719         return status;
720 }
721
722 /* 
723    perform a LDAP/SASL/SPNEGO/KRB5 bind
724 */
725 static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
726 {
727         DATA_BLOB blob = data_blob_null;
728         struct berval cred, *scred = NULL;
729         DATA_BLOB session_key = data_blob_null;
730         int rc;
731
732         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
733                 return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
734         }
735
736         rc = spnego_gen_negTokenTarg(principal, ads->auth.time_offset, &blob, &session_key, 0,
737                                      &ads->auth.tgs_expire);
738
739         if (rc) {
740                 return ADS_ERROR_KRB5(rc);
741         }
742
743         /* now send the auth packet and we should be done */
744         cred.bv_val = (char *)blob.data;
745         cred.bv_len = blob.length;
746
747         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
748
749         data_blob_free(&blob);
750         data_blob_free(&session_key);
751         if(scred)
752                 ber_bvfree(scred);
753
754         return ADS_ERROR(rc);
755 }
756
757 static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
758                                             struct ads_service_principal *p)
759 {
760 #ifdef HAVE_GSSAPI
761         /*
762          * we only use the gsskrb5 based implementation
763          * when sasl sign or seal is requested.
764          *
765          * This has the following reasons:
766          * - it's likely that the gssapi krb5 mech implementation
767          *   doesn't support to negotiate plain connections
768          * - the ads_sasl_spnego_rawkrb5_bind is more robust
769          *   against clock skew errors
770          */
771         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
772                 return ads_sasl_spnego_gsskrb5_bind(ads, p->name);
773         }
774 #endif
775         return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
776 }
777 #endif /* HAVE_KRB5 */
778
779 /* 
780    this performs a SASL/SPNEGO bind
781 */
782 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
783 {
784         struct berval *scred=NULL;
785         int rc, i;
786         ADS_STATUS status;
787         DATA_BLOB blob;
788         char *given_principal = NULL;
789         char *OIDs[ASN1_MAX_OIDS];
790 #ifdef HAVE_KRB5
791         BOOL got_kerberos_mechanism = False;
792 #endif
793
794         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
795
796         if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
797                 status = ADS_ERROR(rc);
798                 goto failed;
799         }
800
801         blob = data_blob(scred->bv_val, scred->bv_len);
802
803         ber_bvfree(scred);
804
805 #if 0
806         file_save("sasl_spnego.dat", blob.data, blob.length);
807 #endif
808
809         /* the server sent us the first part of the SPNEGO exchange in the negprot 
810            reply */
811         if (!spnego_parse_negTokenInit(blob, OIDs, &given_principal)) {
812                 data_blob_free(&blob);
813                 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
814                 goto failed;
815         }
816         data_blob_free(&blob);
817
818         /* make sure the server understands kerberos */
819         for (i=0;OIDs[i];i++) {
820                 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
821 #ifdef HAVE_KRB5
822                 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
823                     strcmp(OIDs[i], OID_KERBEROS5) == 0) {
824                         got_kerberos_mechanism = True;
825                 }
826 #endif
827                 free(OIDs[i]);
828         }
829         DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));
830
831 #ifdef HAVE_KRB5
832         if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
833             got_kerberos_mechanism) 
834         {
835                 struct ads_service_principal p;
836
837                 status = ads_generate_service_principal(ads, given_principal, &p);
838                 SAFE_FREE(given_principal);
839                 if (!ADS_ERR_OK(status)) {
840                         return status;
841                 }
842
843                 status = ads_sasl_spnego_krb5_bind(ads, &p);
844                 if (ADS_ERR_OK(status)) {
845                         ads_free_service_principal(&p);
846                         return status;
847                 }
848
849                 DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
850                           "calling kinit\n", ads_errstr(status)));
851
852                 status = ADS_ERROR_KRB5(ads_kinit_password(ads)); 
853
854                 if (ADS_ERR_OK(status)) {
855                         status = ads_sasl_spnego_krb5_bind(ads, &p);
856                 }
857
858                 ads_free_service_principal(&p);
859
860                 /* only fallback to NTLMSSP if allowed */
861                 if (ADS_ERR_OK(status) || 
862                     !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
863                         return status;
864                 }
865         } else
866 #endif
867         {
868                 SAFE_FREE(given_principal);
869         }
870
871         /* lets do NTLMSSP ... this has the big advantage that we don't need
872            to sync clocks, and we don't rely on special versions of the krb5 
873            library for HMAC_MD4 encryption */
874         return ads_sasl_spnego_ntlmssp_bind(ads);
875
876 failed:
877         return status;
878 }
879
880 #ifdef HAVE_GSSAPI
881 #define MAX_GSS_PASSES 3
882
883 /* this performs a SASL/gssapi bind
884    we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
885    is very dependent on correctly configured DNS whereas
886    this routine is much less fragile
887    see RFC2078 and RFC2222 for details
888 */
889 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
890 {
891         uint32 minor_status;
892         gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
893         gss_OID mech_type = GSS_C_NULL_OID;
894         gss_buffer_desc output_token, input_token;
895         uint32 req_flags, ret_flags;
896         int conf_state;
897         struct berval cred;
898         struct berval *scred = NULL;
899         int i=0;
900         int gss_rc, rc;
901         uint8 *p;
902         uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
903         uint8 wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
904         ADS_STATUS status;
905
906         input_token.value = NULL;
907         input_token.length = 0;
908
909         /*
910          * Note: here we always ask the gssapi for sign and seal
911          *       as this is negotiated later after the mutal
912          *       authentication
913          */
914         req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
915
916         for (i=0; i < MAX_GSS_PASSES; i++) {
917                 gss_rc = gss_init_sec_context(&minor_status,
918                                           GSS_C_NO_CREDENTIAL,
919                                           &context_handle,
920                                           serv_name,
921                                           mech_type,
922                                           req_flags,
923                                           0,
924                                           NULL,
925                                           &input_token,
926                                           NULL,
927                                           &output_token,
928                                           &ret_flags,
929                                           NULL);
930                 if (scred) {
931                         ber_bvfree(scred);
932                         scred = NULL;
933                 }
934                 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
935                         status = ADS_ERROR_GSS(gss_rc, minor_status);
936                         goto failed;
937                 }
938
939                 cred.bv_val = (char *)output_token.value;
940                 cred.bv_len = output_token.length;
941
942                 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL, 
943                                       &scred);
944                 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
945                         status = ADS_ERROR(rc);
946                         goto failed;
947                 }
948
949                 if (output_token.value) {
950                         gss_release_buffer(&minor_status, &output_token);
951                 }
952
953                 if (scred) {
954                         input_token.value = scred->bv_val;
955                         input_token.length = scred->bv_len;
956                 } else {
957                         input_token.value = NULL;
958                         input_token.length = 0;
959                 }
960
961                 if (gss_rc == 0) break;
962         }
963
964         gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
965                             &conf_state,NULL);
966         if (scred) {
967                 ber_bvfree(scred);
968                 scred = NULL;
969         }
970         if (gss_rc) {
971                 status = ADS_ERROR_GSS(gss_rc, minor_status);
972                 goto failed;
973         }
974
975         p = (uint8 *)output_token.value;
976
977 #if 0
978         file_save("sasl_gssapi.dat", output_token.value, output_token.length);
979 #endif
980
981         if (p) {
982                 wrap_type = CVAL(p,0);
983                 SCVAL(p,0,0);
984                 max_msg_size = RIVAL(p,0);
985         }
986
987         gss_release_buffer(&minor_status, &output_token);
988
989         if (!(wrap_type & ads->ldap.wrap_type)) {
990                 /*
991                  * the server doesn't supports the wrap
992                  * type we want :-(
993                  */
994                 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
995                         ads->ldap.wrap_type, wrap_type));
996                 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
997                 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
998                 goto failed;
999         }
1000
1001         /* 0x58 is the minimum windows accepts */
1002         if (max_msg_size < 0x58) {
1003                 max_msg_size = 0x58;
1004         }
1005
1006         output_token.length = 4;
1007         output_token.value = SMB_MALLOC(output_token.length);
1008         p = (uint8 *)output_token.value;
1009
1010         RSIVAL(p,0,max_msg_size);
1011         SCVAL(p,0,ads->ldap.wrap_type);
1012
1013         /*
1014          * we used to add sprintf("dn:%s", ads->config.bind_path) here.
1015          * but using ads->config.bind_path is the wrong! It should be
1016          * the DN of the user object!
1017          *
1018          * w2k3 gives an error when we send an incorrect DN, but sending nothing
1019          * is ok and matches the information flow used in GSS-SPNEGO.
1020          */
1021
1022         gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
1023                           &output_token, &conf_state,
1024                           &input_token);
1025         if (gss_rc) {
1026                 status = ADS_ERROR_GSS(gss_rc, minor_status);
1027                 goto failed;
1028         }
1029
1030         free(output_token.value);
1031
1032         cred.bv_val = (char *)input_token.value;
1033         cred.bv_len = input_token.length;
1034
1035         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL, 
1036                               &scred);
1037         gss_release_buffer(&minor_status, &input_token);
1038         status = ADS_ERROR(rc);
1039         if (!ADS_ERR_OK(status)) {
1040                 goto failed;
1041         }
1042
1043         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
1044                 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
1045                                              (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
1046                                              GSS_C_QOP_DEFAULT,
1047                                              max_msg_size, &ads->ldap.out.max_unwrapped);
1048                 if (gss_rc) {
1049                         status = ADS_ERROR_GSS(gss_rc, minor_status);
1050                         goto failed;
1051                 }
1052
1053                 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
1054                 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
1055                 ads->ldap.in.max_wrapped = max_msg_size;
1056                 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
1057                 if (!ADS_ERR_OK(status)) {
1058                         DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1059                                 ads_errstr(status)));
1060                         goto failed;
1061                 }
1062                 /* make sure we don't free context_handle */
1063                 context_handle = GSS_C_NO_CONTEXT;
1064         }
1065
1066 failed:
1067
1068         if (context_handle != GSS_C_NO_CONTEXT)
1069                 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1070
1071         if(scred)
1072                 ber_bvfree(scred);
1073         return status;
1074 }
1075
1076 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1077 {
1078         ADS_STATUS status;
1079         struct ads_service_principal p;
1080
1081         status = ads_generate_service_principal(ads, NULL, &p);
1082         if (!ADS_ERR_OK(status)) {
1083                 return status;
1084         }
1085
1086         status = ads_sasl_gssapi_do_bind(ads, p.name);
1087         if (ADS_ERR_OK(status)) {
1088                 ads_free_service_principal(&p);
1089                 return status;
1090         }
1091
1092         DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1093                   "calling kinit\n", ads_errstr(status)));
1094
1095         status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1096
1097         if (ADS_ERR_OK(status)) {
1098                 status = ads_sasl_gssapi_do_bind(ads, p.name);
1099         }
1100
1101         ads_free_service_principal(&p);
1102
1103         return status;
1104 }
1105
1106 #endif /* HAVE_GGSAPI */
1107
1108 /* mapping between SASL mechanisms and functions */
1109 static struct {
1110         const char *name;
1111         ADS_STATUS (*fn)(ADS_STRUCT *);
1112 } sasl_mechanisms[] = {
1113         {"GSS-SPNEGO", ads_sasl_spnego_bind},
1114 #ifdef HAVE_GSSAPI
1115         {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1116 #endif
1117         {NULL, NULL}
1118 };
1119
1120 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1121 {
1122         const char *attrs[] = {"supportedSASLMechanisms", NULL};
1123         char **values;
1124         ADS_STATUS status;
1125         int i, j;
1126         LDAPMessage *res;
1127
1128         /* get a list of supported SASL mechanisms */
1129         status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1130         if (!ADS_ERR_OK(status)) return status;
1131
1132         values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1133
1134         if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1135                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1136         } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1137                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1138         } else {
1139                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1140         }
1141
1142         /* try our supported mechanisms in order */
1143         for (i=0;sasl_mechanisms[i].name;i++) {
1144                 /* see if the server supports it */
1145                 for (j=0;values && values[j];j++) {
1146                         if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1147                                 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1148                                 status = sasl_mechanisms[i].fn(ads);
1149                                 ldap_value_free(values);
1150                                 ldap_msgfree(res);
1151                                 return status;
1152                         }
1153                 }
1154         }
1155
1156         ldap_value_free(values);
1157         ldap_msgfree(res);
1158         return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1159 }
1160
1161 #endif /* HAVE_LDAP */
1162