~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/libads/sasl.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

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