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