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