RIP BOOL. Convert BOOL -> bool. I found a few interesting
[sfrench/samba-autobuild/.git] / source / 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 = (gss_ctx_id_t)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 = (gss_ctx_id_t)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 = (gss_ctx_id_t)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          char *string;
611 #ifdef HAVE_GSSAPI
612          gss_name_t name;
613 #endif
614 };
615
616 static void ads_free_service_principal(struct ads_service_principal *p)
617 {
618         SAFE_FREE(p->string);
619
620 #ifdef HAVE_GSSAPI
621         if (p->name) {
622                 uint32 minor_status;
623                 gss_release_name(&minor_status, &p->name);
624         }
625 #endif
626         ZERO_STRUCTP(p);
627 }
628
629 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
630                                                  const char *given_principal,
631                                                  struct ads_service_principal *p)
632 {
633         ADS_STATUS status;
634 #ifdef HAVE_GSSAPI
635         gss_buffer_desc input_name;
636         /* GSS_KRB5_NT_PRINCIPAL_NAME */
637         gss_OID_desc nt_principal =
638         {10, CONST_DISCARD(char *, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
639         uint32 minor_status;
640         int gss_rc;
641 #endif
642
643         ZERO_STRUCTP(p);
644
645         /* I've seen a child Windows 2000 domain not send
646            the principal name back in the first round of
647            the SASL bind reply.  So we guess based on server
648            name and realm.  --jerry  */
649         /* Also try best guess when we get the w2k8 ignore
650            principal back - gd */
651
652         if (!given_principal ||
653             strequal(given_principal, ADS_IGNORE_PRINCIPAL)) {
654
655                 status = ads_guess_service_principal(ads, &p->string);
656                 if (!ADS_ERR_OK(status)) {
657                         return status;
658                 }
659         } else {
660                 p->string = SMB_STRDUP(given_principal);
661                 if (!p->string) {
662                         return ADS_ERROR(LDAP_NO_MEMORY);
663                 }
664         }
665
666 #ifdef HAVE_GSSAPI
667         input_name.value = p->string;
668         input_name.length = strlen(p->string);
669
670         gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
671         if (gss_rc) {
672                 ads_free_service_principal(p);
673                 return ADS_ERROR_GSS(gss_rc, minor_status);
674         }
675 #endif
676
677         return ADS_SUCCESS;
678 }
679
680 /* 
681    perform a LDAP/SASL/SPNEGO/KRB5 bind
682 */
683 static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
684 {
685         DATA_BLOB blob = data_blob_null;
686         struct berval cred, *scred = NULL;
687         DATA_BLOB session_key = data_blob_null;
688         int rc;
689
690         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
691                 return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
692         }
693
694         rc = spnego_gen_negTokenTarg(principal, ads->auth.time_offset, &blob, &session_key, 0,
695                                      &ads->auth.tgs_expire);
696
697         if (rc) {
698                 return ADS_ERROR_KRB5(rc);
699         }
700
701         /* now send the auth packet and we should be done */
702         cred.bv_val = (char *)blob.data;
703         cred.bv_len = blob.length;
704
705         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
706
707         data_blob_free(&blob);
708         data_blob_free(&session_key);
709         if(scred)
710                 ber_bvfree(scred);
711
712         return ADS_ERROR(rc);
713 }
714
715 static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
716                                             struct ads_service_principal *p)
717 {
718 #ifdef HAVE_GSSAPI
719         /*
720          * we only use the gsskrb5 based implementation
721          * when sasl sign or seal is requested.
722          *
723          * This has the following reasons:
724          * - it's likely that the gssapi krb5 mech implementation
725          *   doesn't support to negotiate plain connections
726          * - the ads_sasl_spnego_rawkrb5_bind is more robust
727          *   against clock skew errors
728          */
729         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
730                 return ads_sasl_spnego_gsskrb5_bind(ads, p->name);
731         }
732 #endif
733         return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
734 }
735 #endif /* HAVE_KRB5 */
736
737 /* 
738    this performs a SASL/SPNEGO bind
739 */
740 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
741 {
742         struct berval *scred=NULL;
743         int rc, i;
744         ADS_STATUS status;
745         DATA_BLOB blob;
746         char *given_principal = NULL;
747         char *OIDs[ASN1_MAX_OIDS];
748 #ifdef HAVE_KRB5
749         bool got_kerberos_mechanism = False;
750 #endif
751
752         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
753
754         if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
755                 status = ADS_ERROR(rc);
756                 goto failed;
757         }
758
759         blob = data_blob(scred->bv_val, scred->bv_len);
760
761         ber_bvfree(scred);
762
763 #if 0
764         file_save("sasl_spnego.dat", blob.data, blob.length);
765 #endif
766
767         /* the server sent us the first part of the SPNEGO exchange in the negprot 
768            reply */
769         if (!spnego_parse_negTokenInit(blob, OIDs, &given_principal)) {
770                 data_blob_free(&blob);
771                 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
772                 goto failed;
773         }
774         data_blob_free(&blob);
775
776         /* make sure the server understands kerberos */
777         for (i=0;OIDs[i];i++) {
778                 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
779 #ifdef HAVE_KRB5
780                 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
781                     strcmp(OIDs[i], OID_KERBEROS5) == 0) {
782                         got_kerberos_mechanism = True;
783                 }
784 #endif
785                 free(OIDs[i]);
786         }
787         DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));
788
789 #ifdef HAVE_KRB5
790         if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
791             got_kerberos_mechanism) 
792         {
793                 struct ads_service_principal p;
794
795                 status = ads_generate_service_principal(ads, given_principal, &p);
796                 SAFE_FREE(given_principal);
797                 if (!ADS_ERR_OK(status)) {
798                         return status;
799                 }
800
801                 status = ads_sasl_spnego_krb5_bind(ads, &p);
802                 if (ADS_ERR_OK(status)) {
803                         ads_free_service_principal(&p);
804                         return status;
805                 }
806
807                 DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
808                           "calling kinit\n", ads_errstr(status)));
809
810                 status = ADS_ERROR_KRB5(ads_kinit_password(ads)); 
811
812                 if (ADS_ERR_OK(status)) {
813                         status = ads_sasl_spnego_krb5_bind(ads, &p);
814                         if (!ADS_ERR_OK(status)) {
815                                 DEBUG(0,("kinit succeeded but "
816                                         "ads_sasl_spnego_krb5_bind failed: %s\n",
817                                         ads_errstr(status)));
818                         }
819                 }
820
821                 ads_free_service_principal(&p);
822
823                 /* only fallback to NTLMSSP if allowed */
824                 if (ADS_ERR_OK(status) || 
825                     !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
826                         return status;
827                 }
828         } else
829 #endif
830         {
831                 SAFE_FREE(given_principal);
832         }
833
834         /* lets do NTLMSSP ... this has the big advantage that we don't need
835            to sync clocks, and we don't rely on special versions of the krb5 
836            library for HMAC_MD4 encryption */
837         return ads_sasl_spnego_ntlmssp_bind(ads);
838
839 failed:
840         return status;
841 }
842
843 #ifdef HAVE_GSSAPI
844 #define MAX_GSS_PASSES 3
845
846 /* this performs a SASL/gssapi bind
847    we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
848    is very dependent on correctly configured DNS whereas
849    this routine is much less fragile
850    see RFC2078 and RFC2222 for details
851 */
852 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
853 {
854         uint32 minor_status;
855         gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
856         gss_OID mech_type = GSS_C_NULL_OID;
857         gss_buffer_desc output_token, input_token;
858         uint32 req_flags, ret_flags;
859         int conf_state;
860         struct berval cred;
861         struct berval *scred = NULL;
862         int i=0;
863         int gss_rc, rc;
864         uint8 *p;
865         uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
866         uint8 wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
867         ADS_STATUS status;
868
869         input_token.value = NULL;
870         input_token.length = 0;
871
872         /*
873          * Note: here we always ask the gssapi for sign and seal
874          *       as this is negotiated later after the mutal
875          *       authentication
876          */
877         req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
878
879         for (i=0; i < MAX_GSS_PASSES; i++) {
880                 gss_rc = gss_init_sec_context(&minor_status,
881                                           GSS_C_NO_CREDENTIAL,
882                                           &context_handle,
883                                           serv_name,
884                                           mech_type,
885                                           req_flags,
886                                           0,
887                                           NULL,
888                                           &input_token,
889                                           NULL,
890                                           &output_token,
891                                           &ret_flags,
892                                           NULL);
893                 if (scred) {
894                         ber_bvfree(scred);
895                         scred = NULL;
896                 }
897                 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
898                         status = ADS_ERROR_GSS(gss_rc, minor_status);
899                         goto failed;
900                 }
901
902                 cred.bv_val = (char *)output_token.value;
903                 cred.bv_len = output_token.length;
904
905                 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL, 
906                                       &scred);
907                 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
908                         status = ADS_ERROR(rc);
909                         goto failed;
910                 }
911
912                 if (output_token.value) {
913                         gss_release_buffer(&minor_status, &output_token);
914                 }
915
916                 if (scred) {
917                         input_token.value = scred->bv_val;
918                         input_token.length = scred->bv_len;
919                 } else {
920                         input_token.value = NULL;
921                         input_token.length = 0;
922                 }
923
924                 if (gss_rc == 0) break;
925         }
926
927         gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
928                             &conf_state,NULL);
929         if (scred) {
930                 ber_bvfree(scred);
931                 scred = NULL;
932         }
933         if (gss_rc) {
934                 status = ADS_ERROR_GSS(gss_rc, minor_status);
935                 goto failed;
936         }
937
938         p = (uint8 *)output_token.value;
939
940 #if 0
941         file_save("sasl_gssapi.dat", output_token.value, output_token.length);
942 #endif
943
944         if (p) {
945                 wrap_type = CVAL(p,0);
946                 SCVAL(p,0,0);
947                 max_msg_size = RIVAL(p,0);
948         }
949
950         gss_release_buffer(&minor_status, &output_token);
951
952         if (!(wrap_type & ads->ldap.wrap_type)) {
953                 /*
954                  * the server doesn't supports the wrap
955                  * type we want :-(
956                  */
957                 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
958                         ads->ldap.wrap_type, wrap_type));
959                 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
960                 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
961                 goto failed;
962         }
963
964         /* 0x58 is the minimum windows accepts */
965         if (max_msg_size < 0x58) {
966                 max_msg_size = 0x58;
967         }
968
969         output_token.length = 4;
970         output_token.value = SMB_MALLOC(output_token.length);
971         p = (uint8 *)output_token.value;
972
973         RSIVAL(p,0,max_msg_size);
974         SCVAL(p,0,ads->ldap.wrap_type);
975
976         /*
977          * we used to add sprintf("dn:%s", ads->config.bind_path) here.
978          * but using ads->config.bind_path is the wrong! It should be
979          * the DN of the user object!
980          *
981          * w2k3 gives an error when we send an incorrect DN, but sending nothing
982          * is ok and matches the information flow used in GSS-SPNEGO.
983          */
984
985         gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
986                           &output_token, &conf_state,
987                           &input_token);
988         if (gss_rc) {
989                 status = ADS_ERROR_GSS(gss_rc, minor_status);
990                 goto failed;
991         }
992
993         free(output_token.value);
994
995         cred.bv_val = (char *)input_token.value;
996         cred.bv_len = input_token.length;
997
998         rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL, 
999                               &scred);
1000         gss_release_buffer(&minor_status, &input_token);
1001         status = ADS_ERROR(rc);
1002         if (!ADS_ERR_OK(status)) {
1003                 goto failed;
1004         }
1005
1006         if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
1007                 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
1008                                              (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
1009                                              GSS_C_QOP_DEFAULT,
1010                                              max_msg_size, &ads->ldap.out.max_unwrapped);
1011                 if (gss_rc) {
1012                         status = ADS_ERROR_GSS(gss_rc, minor_status);
1013                         goto failed;
1014                 }
1015
1016                 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
1017                 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
1018                 ads->ldap.in.max_wrapped = max_msg_size;
1019                 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
1020                 if (!ADS_ERR_OK(status)) {
1021                         DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1022                                 ads_errstr(status)));
1023                         goto failed;
1024                 }
1025                 /* make sure we don't free context_handle */
1026                 context_handle = GSS_C_NO_CONTEXT;
1027         }
1028
1029 failed:
1030
1031         if (context_handle != GSS_C_NO_CONTEXT)
1032                 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1033
1034         if(scred)
1035                 ber_bvfree(scred);
1036         return status;
1037 }
1038
1039 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1040 {
1041         ADS_STATUS status;
1042         struct ads_service_principal p;
1043
1044         status = ads_generate_service_principal(ads, NULL, &p);
1045         if (!ADS_ERR_OK(status)) {
1046                 return status;
1047         }
1048
1049         status = ads_sasl_gssapi_do_bind(ads, p.name);
1050         if (ADS_ERR_OK(status)) {
1051                 ads_free_service_principal(&p);
1052                 return status;
1053         }
1054
1055         DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1056                   "calling kinit\n", ads_errstr(status)));
1057
1058         status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1059
1060         if (ADS_ERR_OK(status)) {
1061                 status = ads_sasl_gssapi_do_bind(ads, p.name);
1062         }
1063
1064         ads_free_service_principal(&p);
1065
1066         return status;
1067 }
1068
1069 #endif /* HAVE_GSSAPI */
1070
1071 /* mapping between SASL mechanisms and functions */
1072 static struct {
1073         const char *name;
1074         ADS_STATUS (*fn)(ADS_STRUCT *);
1075 } sasl_mechanisms[] = {
1076         {"GSS-SPNEGO", ads_sasl_spnego_bind},
1077 #ifdef HAVE_GSSAPI
1078         {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1079 #endif
1080         {NULL, NULL}
1081 };
1082
1083 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1084 {
1085         const char *attrs[] = {"supportedSASLMechanisms", NULL};
1086         char **values;
1087         ADS_STATUS status;
1088         int i, j;
1089         LDAPMessage *res;
1090
1091         /* get a list of supported SASL mechanisms */
1092         status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1093         if (!ADS_ERR_OK(status)) return status;
1094
1095         values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1096
1097         if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1098                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1099         } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1100                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1101         } else {
1102                 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1103         }
1104
1105         /* try our supported mechanisms in order */
1106         for (i=0;sasl_mechanisms[i].name;i++) {
1107                 /* see if the server supports it */
1108                 for (j=0;values && values[j];j++) {
1109                         if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1110                                 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1111                                 status = sasl_mechanisms[i].fn(ads);
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