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