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