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