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