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