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