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