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