~ttx/openldap/lucid-gssapi-495418

« back to all changes in this revision

Viewing changes to libraries/libldap/gssapi.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve Langasek, Updated debconf translations
  • Date: 2009-07-28 10:17:15 UTC
  • mfrom: (1.1.4 upstream) (0.2.2 sid)
  • mto: (0.2.4 sid)
  • mto: This revision was merged to the branch mainline in revision 16.
  • Revision ID: james.westby@ubuntu.com-20090728101715-epwmqmsk0d3h22k3
* New upstream version.
  - Fixes FTBFS on ia64 with -fPIE. Closes: #524770.
  - Fixes some TLS issues with GnuTLS.  Closes: #505191.
* Update priority of libldap-2.4-2 to match the archive override.
* Add the missing ldapexop and ldapurl tools to ldap-utils, as well as the
  ldapurl(1) manpage.  Thanks to Peter Marschall for the patch.
  Closes: #496749.
* Bump build-dependency on debhelper to 6 instead of 5, since that's
  what we're using.  Closes: #498116.
* Set the default SLAPD_SERVICES to ldap:/// ldapi:///, instead of using
  the built-in default of ldap:/// only.
* Build-depend on libltdl-dev | libltdl3-dev (>= 1.4.3), for the package
  name change.  Closes: #522965.

[ Updated debconf translations ]
* Spanish, thanks to Francisco Javier Cuadrado <fcocuadrado@gmail.com>.
  Closes: #521804.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $OpenLDAP: pkg/ldap/libraries/libldap/gssapi.c,v 1.1.2.4 2009/04/29 01:53:02 quanah Exp $ */
 
2
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 
3
 *
 
4
 * Copyright 1998-2009 The OpenLDAP Foundation.
 
5
 * All rights reserved.
 
6
 *
 
7
 * Author: Stefan Metzmacher <metze@sernet.de>
 
8
 *
 
9
 * Redistribution and use in source and binary forms, with or without
 
10
 * modification, are permitted only as authorized by the OpenLDAP
 
11
 * Public License.
 
12
 *
 
13
 * A copy of this license is available in the file LICENSE in the
 
14
 * top-level directory of the distribution or, alternatively, at
 
15
 * <http://www.OpenLDAP.org/license.html>.
 
16
 */
 
17
 
 
18
#include "portable.h"
 
19
 
 
20
#include <stdio.h>
 
21
 
 
22
#include <ac/socket.h>
 
23
#include <ac/stdlib.h>
 
24
#include <ac/string.h>
 
25
#include <ac/time.h>
 
26
#include <ac/errno.h>
 
27
#include <ac/ctype.h>
 
28
#include <ac/unistd.h>
 
29
 
 
30
#ifdef HAVE_LIMITS_H
 
31
#include <limits.h>
 
32
#endif
 
33
 
 
34
#include "ldap-int.h"
 
35
 
 
36
#ifdef HAVE_GSSAPI
 
37
 
 
38
#ifdef HAVE_GSSAPI_GSSAPI_H
 
39
#include <gssapi/gssapi.h>
 
40
#else
 
41
#include <gssapi.h>
 
42
#endif
 
43
 
 
44
static char *
 
45
gsserrstr(
 
46
        char *buf,
 
47
        ber_len_t buf_len,
 
48
        gss_OID mech,
 
49
        int gss_rc,
 
50
        OM_uint32 minor_status )
 
51
{
 
52
        OM_uint32 min2;
 
53
        gss_buffer_desc mech_msg = GSS_C_EMPTY_BUFFER;
 
54
        gss_buffer_desc gss_msg = GSS_C_EMPTY_BUFFER;
 
55
        gss_buffer_desc minor_msg = GSS_C_EMPTY_BUFFER;
 
56
        OM_uint32 msg_ctx = 0;
 
57
 
 
58
        if (buf == NULL) {
 
59
                return NULL;
 
60
        }
 
61
 
 
62
        if (buf_len == 0) {
 
63
                return NULL;
 
64
        }
 
65
 
 
66
#ifdef HAVE_GSS_OID_TO_STR
 
67
        gss_oid_to_str(&min2, mech, &mech_msg);
 
68
#endif
 
69
        gss_display_status(&min2, gss_rc, GSS_C_GSS_CODE,
 
70
                           mech, &msg_ctx, &gss_msg);
 
71
        gss_display_status(&min2, minor_status, GSS_C_MECH_CODE,
 
72
                           mech, &msg_ctx, &minor_msg);
 
73
 
 
74
        snprintf(buf, buf_len, "gss_rc[%d:%*s] mech[%*s] minor[%u:%*s]",
 
75
                 gss_rc, (int)gss_msg.length,
 
76
                 (const char *)(gss_msg.value?gss_msg.value:""),
 
77
                 (int)mech_msg.length,
 
78
                 (const char *)(mech_msg.value?mech_msg.value:""),
 
79
                 minor_status, (int)minor_msg.length,
 
80
                 (const char *)(minor_msg.value?minor_msg.value:""));
 
81
 
 
82
        gss_release_buffer(&min2, &mech_msg);
 
83
        gss_release_buffer(&min2, &gss_msg);
 
84
        gss_release_buffer(&min2, &minor_msg);
 
85
 
 
86
        buf[buf_len-1] = '\0';
 
87
 
 
88
        return buf;
 
89
}
 
90
 
 
91
static void
 
92
sb_sasl_gssapi_init(
 
93
        struct sb_sasl_generic_data *p,
 
94
        ber_len_t *min_send,
 
95
        ber_len_t *max_send,
 
96
        ber_len_t *max_recv )
 
97
{
 
98
        gss_ctx_id_t gss_ctx = (gss_ctx_id_t)p->ops_private;
 
99
        int gss_rc;
 
100
        OM_uint32 minor_status;
 
101
        gss_OID ctx_mech = GSS_C_NO_OID;
 
102
        OM_uint32 ctx_flags = 0;
 
103
        int conf_req_flag = 0;
 
104
        OM_uint32 max_input_size;
 
105
 
 
106
        gss_inquire_context(&minor_status,
 
107
                            gss_ctx,
 
108
                            NULL,
 
109
                            NULL,
 
110
                            NULL,
 
111
                            &ctx_mech,
 
112
                            &ctx_flags,
 
113
                            NULL,
 
114
                            NULL);
 
115
 
 
116
        if (ctx_flags & (GSS_C_CONF_FLAG)) {
 
117
                conf_req_flag = 1;
 
118
        }
 
119
 
 
120
#if defined(HAVE_CYRUS_SASL)
 
121
#define SEND_PREALLOC_SIZE      SASL_MIN_BUFF_SIZE
 
122
#else
 
123
#define SEND_PREALLOC_SIZE      4096
 
124
#endif
 
125
#define SEND_MAX_WIRE_SIZE      0x00A00000
 
126
#define RECV_MAX_WIRE_SIZE      0x0FFFFFFF
 
127
#define FALLBACK_SEND_MAX_SIZE  0x009FFFB8 /* from MIT 1.5.x */
 
128
 
 
129
        gss_rc = gss_wrap_size_limit(&minor_status, gss_ctx,
 
130
                                     conf_req_flag, GSS_C_QOP_DEFAULT,
 
131
                                     SEND_MAX_WIRE_SIZE, &max_input_size);
 
132
        if ( gss_rc != GSS_S_COMPLETE ) {
 
133
                char msg[256];
 
134
                ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug,
 
135
                                "sb_sasl_gssapi_init: failed to wrap size limit: %s\n",
 
136
                                gsserrstr( msg, sizeof(msg), ctx_mech, gss_rc, minor_status ) );
 
137
                ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug,
 
138
                                "sb_sasl_gssapi_init: fallback to default wrap size limit\n");
 
139
                /*
 
140
                 * some libgssglue/libgssapi versions
 
141
                 * have a broken gss_wrap_size_limit()
 
142
                 * implementation
 
143
                 */
 
144
                max_input_size = FALLBACK_SEND_MAX_SIZE;
 
145
        }
 
146
 
 
147
        *min_send = SEND_PREALLOC_SIZE;
 
148
        *max_send = max_input_size;
 
149
        *max_recv = RECV_MAX_WIRE_SIZE;
 
150
}
 
151
 
 
152
static ber_int_t
 
153
sb_sasl_gssapi_encode(
 
154
        struct sb_sasl_generic_data *p,
 
155
        unsigned char *buf,
 
156
        ber_len_t len,
 
157
        Sockbuf_Buf *dst )
 
158
{
 
159
        gss_ctx_id_t gss_ctx = (gss_ctx_id_t)p->ops_private;
 
160
        int gss_rc;
 
161
        OM_uint32 minor_status;
 
162
        gss_buffer_desc unwrapped, wrapped;
 
163
        gss_OID ctx_mech = GSS_C_NO_OID;
 
164
        OM_uint32 ctx_flags = 0;
 
165
        int conf_req_flag = 0;
 
166
        int conf_state;
 
167
        unsigned char *b;
 
168
        ber_len_t pkt_len;
 
169
 
 
170
        unwrapped.value         = buf;
 
171
        unwrapped.length        = len;
 
172
 
 
173
        gss_inquire_context(&minor_status,
 
174
                            gss_ctx,
 
175
                            NULL,
 
176
                            NULL,
 
177
                            NULL,
 
178
                            &ctx_mech,
 
179
                            &ctx_flags,
 
180
                            NULL,
 
181
                            NULL);
 
182
 
 
183
        if (ctx_flags & (GSS_C_CONF_FLAG)) {
 
184
                conf_req_flag = 1;
 
185
        }
 
186
 
 
187
        gss_rc = gss_wrap(&minor_status, gss_ctx,
 
188
                          conf_req_flag, GSS_C_QOP_DEFAULT,
 
189
                          &unwrapped, &conf_state,
 
190
                          &wrapped);
 
191
        if ( gss_rc != GSS_S_COMPLETE ) {
 
192
                char msg[256];
 
193
                ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug,
 
194
                                "sb_sasl_gssapi_encode: failed to encode packet: %s\n",
 
195
                                gsserrstr( msg, sizeof(msg), ctx_mech, gss_rc, minor_status ) );
 
196
                return -1;
 
197
        }
 
198
 
 
199
        if ( conf_req_flag && conf_state == 0 ) {
 
200
                ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug,
 
201
                                "sb_sasl_gssapi_encode: GSS_C_CONF_FLAG was ignored by our gss_wrap()\n" );
 
202
                return -1;
 
203
        }
 
204
 
 
205
        pkt_len = 4 + wrapped.length;
 
206
 
 
207
        /* Grow the packet buffer if neccessary */
 
208
        if ( dst->buf_size < pkt_len &&
 
209
                ber_pvt_sb_grow_buffer( dst, pkt_len ) < 0 )
 
210
        {
 
211
                ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug,
 
212
                                "sb_sasl_gssapi_encode: failed to grow the buffer to %lu bytes\n",
 
213
                                pkt_len );
 
214
                return -1;
 
215
        }
 
216
 
 
217
        dst->buf_end = pkt_len;
 
218
 
 
219
        b = (unsigned char *)dst->buf_base;
 
220
 
 
221
        b[0] = (unsigned char)(wrapped.length >> 24);
 
222
        b[1] = (unsigned char)(wrapped.length >> 16);
 
223
        b[2] = (unsigned char)(wrapped.length >>  8);
 
224
        b[3] = (unsigned char)(wrapped.length >>  0);
 
225
 
 
226
        /* copy the wrapped blob to the right location */
 
227
        memcpy(b + 4, wrapped.value, wrapped.length);
 
228
 
 
229
        gss_release_buffer(&minor_status, &wrapped);
 
230
 
 
231
        return 0;
 
232
}
 
233
 
 
234
static ber_int_t
 
235
sb_sasl_gssapi_decode(
 
236
        struct sb_sasl_generic_data *p,
 
237
        const Sockbuf_Buf *src,
 
238
        Sockbuf_Buf *dst )
 
239
{
 
240
        gss_ctx_id_t gss_ctx = (gss_ctx_id_t)p->ops_private;
 
241
        int gss_rc;
 
242
        OM_uint32 minor_status;
 
243
        gss_buffer_desc unwrapped, wrapped;
 
244
        gss_OID ctx_mech = GSS_C_NO_OID;
 
245
        OM_uint32 ctx_flags = 0;
 
246
        int conf_req_flag = 0;
 
247
        int conf_state;
 
248
        unsigned char *b;
 
249
 
 
250
        wrapped.value   = src->buf_base + 4;
 
251
        wrapped.length  = src->buf_end - 4;
 
252
 
 
253
        gss_inquire_context(&minor_status,
 
254
                            gss_ctx,
 
255
                            NULL,
 
256
                            NULL,
 
257
                            NULL,
 
258
                            &ctx_mech,
 
259
                            &ctx_flags,
 
260
                            NULL,
 
261
                            NULL);
 
262
 
 
263
        if (ctx_flags & (GSS_C_CONF_FLAG)) {
 
264
                conf_req_flag = 1;
 
265
        }
 
266
 
 
267
        gss_rc = gss_unwrap(&minor_status, gss_ctx,
 
268
                            &wrapped, &unwrapped,
 
269
                            &conf_state, GSS_C_QOP_DEFAULT);
 
270
        if ( gss_rc != GSS_S_COMPLETE ) {
 
271
                char msg[256];
 
272
                ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug,
 
273
                                "sb_sasl_gssapi_decode: failed to decode packet: %s\n",
 
274
                                gsserrstr( msg, sizeof(msg), ctx_mech, gss_rc, minor_status ) );
 
275
                return -1;
 
276
        }
 
277
 
 
278
        if ( conf_req_flag && conf_state == 0 ) {
 
279
                ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug,
 
280
                                "sb_sasl_gssapi_encode: GSS_C_CONF_FLAG was ignored by our peer\n" );
 
281
                return -1;
 
282
        }
 
283
 
 
284
        /* Grow the packet buffer if neccessary */
 
285
        if ( dst->buf_size < unwrapped.length &&
 
286
                ber_pvt_sb_grow_buffer( dst, unwrapped.length ) < 0 )
 
287
        {
 
288
                ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug,
 
289
                                "sb_sasl_gssapi_decode: failed to grow the buffer to %lu bytes\n",
 
290
                                unwrapped.length );
 
291
                return -1;
 
292
        }
 
293
 
 
294
        dst->buf_end = unwrapped.length;
 
295
 
 
296
        b = (unsigned char *)dst->buf_base;
 
297
 
 
298
        /* copy the wrapped blob to the right location */
 
299
        memcpy(b, unwrapped.value, unwrapped.length);
 
300
 
 
301
        gss_release_buffer(&minor_status, &unwrapped);
 
302
 
 
303
        return 0;
 
304
}
 
305
 
 
306
static void
 
307
sb_sasl_gssapi_reset_buf(
 
308
        struct sb_sasl_generic_data *p,
 
309
        Sockbuf_Buf *buf )
 
310
{
 
311
        ber_pvt_sb_buf_destroy( buf );
 
312
}
 
313
 
 
314
static void
 
315
sb_sasl_gssapi_fini( struct sb_sasl_generic_data *p )
 
316
{
 
317
}
 
318
 
 
319
static const struct sb_sasl_generic_ops sb_sasl_gssapi_ops = {
 
320
        sb_sasl_gssapi_init,
 
321
        sb_sasl_gssapi_encode,
 
322
        sb_sasl_gssapi_decode,
 
323
        sb_sasl_gssapi_reset_buf,
 
324
        sb_sasl_gssapi_fini
 
325
};
 
326
 
 
327
static int
 
328
sb_sasl_gssapi_install(
 
329
        Sockbuf *sb,
 
330
        gss_ctx_id_t gss_ctx )
 
331
{
 
332
        struct sb_sasl_generic_install install_arg;
 
333
 
 
334
        install_arg.ops         = &sb_sasl_gssapi_ops;
 
335
        install_arg.ops_private = gss_ctx;
 
336
 
 
337
        return ldap_pvt_sasl_generic_install( sb, &install_arg );
 
338
}
 
339
 
 
340
static void
 
341
sb_sasl_gssapi_remove( Sockbuf *sb )
 
342
{
 
343
        ldap_pvt_sasl_generic_remove( sb );
 
344
}
 
345
 
 
346
static int
 
347
map_gsserr2ldap(
 
348
        LDAP *ld,
 
349
        gss_OID mech,
 
350
        int gss_rc,
 
351
        OM_uint32 minor_status )
 
352
{
 
353
        char msg[256];
 
354
 
 
355
        Debug( LDAP_DEBUG_ANY, "%s\n",
 
356
               gsserrstr( msg, sizeof(msg), mech, gss_rc, minor_status ),
 
357
               NULL, NULL );
 
358
 
 
359
        if (gss_rc == GSS_S_COMPLETE) {
 
360
                ld->ld_errno = LDAP_SUCCESS;
 
361
        } else if (GSS_CALLING_ERROR(gss_rc)) {
 
362
                ld->ld_errno = LDAP_LOCAL_ERROR;
 
363
        } else if (GSS_ROUTINE_ERROR(gss_rc)) {
 
364
                ld->ld_errno = LDAP_INAPPROPRIATE_AUTH;
 
365
        } else if (gss_rc == GSS_S_CONTINUE_NEEDED) {
 
366
                ld->ld_errno = LDAP_SASL_BIND_IN_PROGRESS;
 
367
        } else if (GSS_SUPPLEMENTARY_INFO(gss_rc)) {
 
368
                ld->ld_errno = LDAP_AUTH_UNKNOWN;
 
369
        } else if (GSS_ERROR(gss_rc)) {
 
370
                ld->ld_errno = LDAP_AUTH_UNKNOWN;
 
371
        } else {
 
372
                ld->ld_errno = LDAP_OTHER;
 
373
        }
 
374
 
 
375
        return ld->ld_errno;
 
376
}
 
377
 
 
378
 
 
379
static int
 
380
ldap_gssapi_get_rootdse_infos (
 
381
        LDAP *ld,
 
382
        char **pmechlist,
 
383
        char **pldapServiceName,
 
384
        char **pdnsHostName )
 
385
{
 
386
        /* we need to query the server for supported mechs anyway */
 
387
        LDAPMessage *res, *e;
 
388
        char *attrs[] = {
 
389
                "supportedSASLMechanisms",
 
390
                "ldapServiceName",
 
391
                "dnsHostName",
 
392
                NULL
 
393
        };
 
394
        char **values, *mechlist;
 
395
        char *ldapServiceName = NULL;
 
396
        char *dnsHostName = NULL;
 
397
        int rc;
 
398
 
 
399
        Debug( LDAP_DEBUG_TRACE, "ldap_gssapi_get_rootdse_infos\n", 0, 0, 0 );
 
400
 
 
401
        rc = ldap_search_s( ld, "", LDAP_SCOPE_BASE,
 
402
                NULL, attrs, 0, &res );
 
403
 
 
404
        if ( rc != LDAP_SUCCESS ) {
 
405
                return ld->ld_errno;
 
406
        }
 
407
 
 
408
        e = ldap_first_entry( ld, res );
 
409
        if ( e == NULL ) {
 
410
                ldap_msgfree( res );
 
411
                if ( ld->ld_errno == LDAP_SUCCESS ) {
 
412
                        ld->ld_errno = LDAP_NO_SUCH_OBJECT;
 
413
                }
 
414
                return ld->ld_errno;
 
415
        }
 
416
 
 
417
        values = ldap_get_values( ld, e, "supportedSASLMechanisms" );
 
418
        if ( values == NULL ) {
 
419
                ldap_msgfree( res );
 
420
                ld->ld_errno = LDAP_NO_SUCH_ATTRIBUTE;
 
421
                return ld->ld_errno;
 
422
        }
 
423
 
 
424
        mechlist = ldap_charray2str( values, " " );
 
425
        if ( mechlist == NULL ) {
 
426
                LDAP_VFREE( values );
 
427
                ldap_msgfree( res );
 
428
                ld->ld_errno = LDAP_NO_MEMORY;
 
429
                return ld->ld_errno;
 
430
        }
 
431
 
 
432
        LDAP_VFREE( values );
 
433
 
 
434
        values = ldap_get_values( ld, e, "ldapServiceName" );
 
435
        if ( values == NULL ) {
 
436
                goto get_dns_host_name;
 
437
        }
 
438
 
 
439
        ldapServiceName = ldap_charray2str( values, " " );
 
440
        if ( ldapServiceName == NULL ) {
 
441
                LDAP_FREE( mechlist );
 
442
                LDAP_VFREE( values );
 
443
                ldap_msgfree( res );
 
444
                ld->ld_errno = LDAP_NO_MEMORY;
 
445
                return ld->ld_errno;
 
446
        }
 
447
        LDAP_VFREE( values );
 
448
 
 
449
get_dns_host_name:
 
450
 
 
451
        values = ldap_get_values( ld, e, "dnsHostName" );
 
452
        if ( values == NULL ) {
 
453
                goto done;
 
454
        }
 
455
 
 
456
        dnsHostName = ldap_charray2str( values, " " );
 
457
        if ( dnsHostName == NULL ) {
 
458
                LDAP_FREE( mechlist );
 
459
                LDAP_FREE( ldapServiceName );
 
460
                LDAP_VFREE( values );
 
461
                ldap_msgfree( res );
 
462
                ld->ld_errno = LDAP_NO_MEMORY;
 
463
                return ld->ld_errno;
 
464
        }
 
465
        LDAP_VFREE( values );
 
466
 
 
467
done:
 
468
        ldap_msgfree( res );
 
469
 
 
470
        *pmechlist = mechlist;
 
471
        *pldapServiceName = ldapServiceName;
 
472
        *pdnsHostName = dnsHostName;
 
473
 
 
474
        return LDAP_SUCCESS;
 
475
}
 
476
 
 
477
 
 
478
static int check_for_gss_spnego_support( LDAP *ld, const char *mechs_str )
 
479
{
 
480
        int rc;
 
481
        char **mechs_list = NULL;
 
482
 
 
483
        mechs_list = ldap_str2charray( mechs_str, " " );
 
484
        if ( mechs_list == NULL ) {
 
485
                ld->ld_errno = LDAP_NO_MEMORY;
 
486
                return ld->ld_errno;
 
487
        }
 
488
 
 
489
        rc = ldap_charray_inlist( mechs_list, "GSS-SPNEGO" );
 
490
        ldap_charray_free( mechs_list );
 
491
        if ( rc != 1) {
 
492
                ld->ld_errno = LDAP_STRONG_AUTH_NOT_SUPPORTED;
 
493
                return ld->ld_errno;
 
494
        }
 
495
 
 
496
        return LDAP_SUCCESS;
 
497
}
 
498
 
 
499
static int
 
500
guess_service_principal(
 
501
        LDAP *ld,
 
502
        const char *ldapServiceName,
 
503
        const char *dnsHostName,
 
504
        gss_name_t *principal )
 
505
{
 
506
        gss_buffer_desc input_name;
 
507
        /* GSS_KRB5_NT_PRINCIPAL_NAME */
 
508
        gss_OID_desc nt_principal =
 
509
        {10, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01"};
 
510
        const char *host = ld->ld_defconn->lconn_server->lud_host;
 
511
        OM_uint32 minor_status;
 
512
        int gss_rc;
 
513
        int ret;
 
514
        size_t svc_principal_size;
 
515
        char *svc_principal = NULL;
 
516
        const char *principal_fmt = NULL;
 
517
        const char *str = NULL;
 
518
        const char *givenstr = NULL;
 
519
        const char *ignore = "not_defined_in_RFC4178@please_ignore";
 
520
        int allow_remote = 0;
 
521
 
 
522
        if (ldapServiceName) {
 
523
                givenstr = strchr(ldapServiceName, ':');
 
524
                if (givenstr && givenstr[1]) {
 
525
                        givenstr++;
 
526
                        if (strcmp(givenstr, ignore) == 0) {
 
527
                                givenstr = NULL;
 
528
                        }
 
529
                } else {
 
530
                        givenstr = NULL;
 
531
                }
 
532
        }
 
533
 
 
534
        if ( ld->ld_options.ldo_gssapi_options & LDAP_GSSAPI_OPT_ALLOW_REMOTE_PRINCIPAL ) {
 
535
                allow_remote = 1;
 
536
        }
 
537
 
 
538
        if (allow_remote && givenstr) {
 
539
                principal_fmt = "%s";
 
540
                svc_principal_size = strlen(givenstr) + 1;
 
541
                str = givenstr;
 
542
 
 
543
        } else if (allow_remote && dnsHostName) {
 
544
                principal_fmt = "ldap/%s";
 
545
                svc_principal_size = strlen(dnsHostName) + strlen(principal_fmt);
 
546
                str = dnsHostName;
 
547
 
 
548
        } else {
 
549
                principal_fmt = "ldap/%s";
 
550
                svc_principal_size = strlen(host) + strlen(principal_fmt);
 
551
                str = host;
 
552
        }
 
553
 
 
554
        svc_principal = (char*) ldap_memalloc(svc_principal_size * sizeof(char));
 
555
        if ( svc_principal == NULL ) {
 
556
                ld->ld_errno = LDAP_NO_MEMORY;
 
557
                return ld->ld_errno;
 
558
        }
 
559
 
 
560
        ret = snprintf( svc_principal, svc_principal_size - 1, principal_fmt, str);
 
561
        if (ret < 0 || (size_t)ret + 1 >= svc_principal_size) {
 
562
                ld->ld_errno = LDAP_LOCAL_ERROR;
 
563
                return ld->ld_errno;
 
564
        }
 
565
 
 
566
        Debug( LDAP_DEBUG_TRACE, "principal for host[%s]: '%s'\n",
 
567
               host, svc_principal, 0 );
 
568
 
 
569
        input_name.value  = svc_principal;
 
570
        input_name.length = strlen( svc_principal );
 
571
 
 
572
        gss_rc = gss_import_name( &minor_status, &input_name, &nt_principal, principal );
 
573
        ldap_memfree( svc_principal );
 
574
        if ( gss_rc != GSS_S_COMPLETE ) {
 
575
                return map_gsserr2ldap( ld, GSS_C_NO_OID, gss_rc, minor_status );
 
576
        }
 
577
 
 
578
        return LDAP_SUCCESS;
 
579
}
 
580
 
 
581
void ldap_int_gssapi_close( LDAP *ld, LDAPConn *lc )
 
582
{
 
583
        if ( lc && lc->lconn_gss_ctx ) {
 
584
                OM_uint32 minor_status;
 
585
                OM_uint32 ctx_flags = 0;
 
586
                gss_ctx_id_t old_gss_ctx = GSS_C_NO_CONTEXT;
 
587
                old_gss_ctx = (gss_ctx_id_t)lc->lconn_gss_ctx;
 
588
 
 
589
                gss_inquire_context(&minor_status,
 
590
                                    old_gss_ctx,
 
591
                                    NULL,
 
592
                                    NULL,
 
593
                                    NULL,
 
594
                                    NULL,
 
595
                                    &ctx_flags,
 
596
                                    NULL,
 
597
                                    NULL);
 
598
 
 
599
                if (!( ld->ld_options.ldo_gssapi_options & LDAP_GSSAPI_OPT_DO_NOT_FREE_GSS_CONTEXT )) {
 
600
                        gss_delete_sec_context( &minor_status, &old_gss_ctx, GSS_C_NO_BUFFER );
 
601
                }
 
602
                lc->lconn_gss_ctx = GSS_C_NO_CONTEXT;
 
603
 
 
604
                if (ctx_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG)) {
 
605
                        /* remove wrapping layer */
 
606
                        sb_sasl_gssapi_remove( lc->lconn_sb );
 
607
                }
 
608
        }
 
609
}
 
610
 
 
611
static void
 
612
ldap_int_gssapi_setup(
 
613
        LDAP *ld,
 
614
        LDAPConn *lc,
 
615
        gss_ctx_id_t gss_ctx)
 
616
{
 
617
        OM_uint32 minor_status;
 
618
        OM_uint32 ctx_flags = 0;
 
619
 
 
620
        ldap_int_gssapi_close( ld, lc );
 
621
 
 
622
        gss_inquire_context(&minor_status,
 
623
                            gss_ctx,
 
624
                            NULL,
 
625
                            NULL,
 
626
                            NULL,
 
627
                            NULL,
 
628
                            &ctx_flags,
 
629
                            NULL,
 
630
                            NULL);
 
631
 
 
632
        lc->lconn_gss_ctx = gss_ctx;
 
633
 
 
634
        if (ctx_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG)) {
 
635
                /* setup wrapping layer */
 
636
                sb_sasl_gssapi_install( lc->lconn_sb, gss_ctx );
 
637
        }
 
638
}
 
639
 
 
640
#ifdef LDAP_R_COMPILE
 
641
ldap_pvt_thread_mutex_t ldap_int_gssapi_mutex;
 
642
#endif
 
643
 
 
644
static int
 
645
ldap_int_gss_spnego_bind_s( LDAP *ld )
 
646
{
 
647
        int rc;
 
648
        int gss_rc;
 
649
        OM_uint32 minor_status;
 
650
        char *mechlist = NULL;
 
651
        char *ldapServiceName = NULL;
 
652
        char *dnsHostName = NULL;
 
653
        gss_OID_set supported_mechs = GSS_C_NO_OID_SET;
 
654
        int spnego_support = 0;
 
655
#define __SPNEGO_OID_LENGTH 6
 
656
#define __SPNEGO_OID "\053\006\001\005\005\002"
 
657
        gss_OID_desc spnego_oid = {__SPNEGO_OID_LENGTH, __SPNEGO_OID};
 
658
        gss_OID req_mech = GSS_C_NO_OID;
 
659
        gss_OID ret_mech = GSS_C_NO_OID;
 
660
        gss_ctx_id_t gss_ctx = GSS_C_NO_CONTEXT;
 
661
        gss_name_t principal = GSS_C_NO_NAME;
 
662
        OM_uint32 req_flags;
 
663
        OM_uint32 ret_flags;
 
664
        gss_buffer_desc input_token, output_token = GSS_C_EMPTY_BUFFER;
 
665
        struct berval cred, *scred = NULL;
 
666
 
 
667
#ifdef LDAP_R_COMPILE
 
668
        ldap_pvt_thread_mutex_lock( &ldap_int_gssapi_mutex );
 
669
#endif
 
670
 
 
671
        /* get information from RootDSE entry */
 
672
        rc = ldap_gssapi_get_rootdse_infos ( ld, &mechlist,
 
673
                                             &ldapServiceName, &dnsHostName);
 
674
        if ( rc != LDAP_SUCCESS ) {
 
675
                return rc;
 
676
        }
 
677
 
 
678
        /* check that the server supports GSS-SPNEGO */
 
679
        rc = check_for_gss_spnego_support( ld, mechlist );
 
680
        if ( rc != LDAP_SUCCESS ) {
 
681
                goto rc_error;
 
682
        }
 
683
 
 
684
        /* prepare new gss_ctx_id_t */
 
685
        rc = guess_service_principal( ld, ldapServiceName, dnsHostName, &principal );
 
686
        if ( rc != LDAP_SUCCESS ) {
 
687
                goto rc_error;
 
688
        }
 
689
 
 
690
        /* see if our gssapi library supports spnego */
 
691
        gss_rc = gss_indicate_mechs( &minor_status, &supported_mechs );
 
692
        if ( gss_rc != GSS_S_COMPLETE ) {
 
693
                goto gss_error;
 
694
        }
 
695
        gss_rc = gss_test_oid_set_member( &minor_status,
 
696
                &spnego_oid, supported_mechs, &spnego_support);
 
697
        gss_release_oid_set( &minor_status, &supported_mechs);
 
698
        if ( gss_rc != GSS_S_COMPLETE ) {
 
699
                goto gss_error;
 
700
        }
 
701
        if ( spnego_support != 0 ) {
 
702
                req_mech = &spnego_oid;
 
703
        }
 
704
 
 
705
        req_flags = ld->ld_options.gssapi_flags;
 
706
        req_flags |= GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
 
707
 
 
708
        /*
 
709
         * loop around gss_init_sec_context() and ldap_sasl_bind_s()
 
710
         */
 
711
        input_token.value = NULL;
 
712
        input_token.length = 0;
 
713
        gss_rc = gss_init_sec_context(&minor_status,
 
714
                                      GSS_C_NO_CREDENTIAL,
 
715
                                      &gss_ctx,
 
716
                                      principal,
 
717
                                      req_mech,
 
718
                                      req_flags,
 
719
                                      0,
 
720
                                      NULL,
 
721
                                      &input_token,
 
722
                                      &ret_mech,
 
723
                                      &output_token,
 
724
                                      &ret_flags,
 
725
                                      NULL);
 
726
        if ( gss_rc == GSS_S_COMPLETE ) {
 
727
                rc = LDAP_INAPPROPRIATE_AUTH;
 
728
                goto rc_error;
 
729
        }
 
730
        if ( gss_rc != GSS_S_CONTINUE_NEEDED ) {
 
731
                goto gss_error;
 
732
        }
 
733
        while (1) {
 
734
                cred.bv_val = (char *)output_token.value;
 
735
                cred.bv_len = output_token.length;
 
736
                rc = ldap_sasl_bind_s( ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred );
 
737
                gss_release_buffer( &minor_status, &output_token );
 
738
                if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) {
 
739
                        goto rc_error;
 
740
                }
 
741
 
 
742
                if ( scred ) {
 
743
                        input_token.value = scred->bv_val;
 
744
                        input_token.length = scred->bv_len;
 
745
                } else {
 
746
                        input_token.value = NULL;
 
747
                        input_token.length = 0;
 
748
                }
 
749
 
 
750
                gss_rc = gss_init_sec_context(&minor_status,
 
751
                                              GSS_C_NO_CREDENTIAL,
 
752
                                              &gss_ctx,
 
753
                                              principal,
 
754
                                              req_mech,
 
755
                                              req_flags,
 
756
                                              0,
 
757
                                              NULL,
 
758
                                              &input_token,
 
759
                                              &ret_mech,
 
760
                                              &output_token,
 
761
                                              &ret_flags,
 
762
                                              NULL);
 
763
                if ( scred ) {
 
764
                        ber_bvfree( scred );
 
765
                }
 
766
                if ( gss_rc == GSS_S_COMPLETE ) {
 
767
                        gss_release_buffer( &minor_status, &output_token );
 
768
                        break;
 
769
                }
 
770
 
 
771
                if ( gss_rc != GSS_S_CONTINUE_NEEDED ) {
 
772
                        goto gss_error;
 
773
                }
 
774
        }
 
775
 
 
776
        ldap_int_gssapi_setup( ld, ld->ld_defconn, gss_ctx);
 
777
        gss_ctx = GSS_C_NO_CONTEXT;
 
778
 
 
779
        rc = LDAP_SUCCESS;
 
780
        goto rc_error;
 
781
 
 
782
gss_error:
 
783
        rc = map_gsserr2ldap( ld, 
 
784
                              (ret_mech != GSS_C_NO_OID ? ret_mech : req_mech ),
 
785
                              gss_rc, minor_status );
 
786
rc_error:
 
787
#ifdef LDAP_R_COMPILE
 
788
        ldap_pvt_thread_mutex_unlock( &ldap_int_gssapi_mutex );
 
789
#endif
 
790
        LDAP_FREE( mechlist );
 
791
        LDAP_FREE( ldapServiceName );
 
792
        LDAP_FREE( dnsHostName );
 
793
        gss_release_buffer( &minor_status, &output_token );
 
794
        if ( gss_ctx != GSS_C_NO_CONTEXT ) {
 
795
                gss_delete_sec_context( &minor_status, &gss_ctx, GSS_C_NO_BUFFER );
 
796
        }
 
797
        if ( principal != GSS_C_NO_NAME ) {
 
798
                gss_release_name( &minor_status, &principal );
 
799
        }
 
800
        return rc;
 
801
}
 
802
 
 
803
int
 
804
ldap_int_gssapi_config( struct ldapoptions *lo, int option, const char *arg )
 
805
{
 
806
        int ok = 0;
 
807
 
 
808
        switch( option ) {
 
809
        case LDAP_OPT_SIGN:
 
810
 
 
811
                if (!arg) {
 
812
                } else if (strcasecmp(arg, "on") == 0) {
 
813
                        ok = 1;
 
814
                } else if (strcasecmp(arg, "yes") == 0) {
 
815
                        ok = 1;
 
816
                } else if (strcasecmp(arg, "true") == 0) {
 
817
                        ok = 1;
 
818
 
 
819
                }
 
820
                if (ok) {
 
821
                        lo->ldo_gssapi_flags |= GSS_C_INTEG_FLAG;
 
822
                }
 
823
 
 
824
                return 0;
 
825
 
 
826
        case LDAP_OPT_ENCRYPT:
 
827
 
 
828
                if (!arg) {
 
829
                } else if (strcasecmp(arg, "on") == 0) {
 
830
                        ok = 1;
 
831
                } else if (strcasecmp(arg, "yes") == 0) {
 
832
                        ok = 1;
 
833
                } else if (strcasecmp(arg, "true") == 0) {
 
834
                        ok = 1;
 
835
                }
 
836
 
 
837
                if (ok) {
 
838
                        lo->ldo_gssapi_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
 
839
                }
 
840
 
 
841
                return 0;
 
842
 
 
843
        case LDAP_OPT_X_GSSAPI_ALLOW_REMOTE_PRINCIPAL:
 
844
 
 
845
                if (!arg) {
 
846
                } else if (strcasecmp(arg, "on") == 0) {
 
847
                        ok = 1;
 
848
                } else if (strcasecmp(arg, "yes") == 0) {
 
849
                        ok = 1;
 
850
                } else if (strcasecmp(arg, "true") == 0) {
 
851
                        ok = 1;
 
852
                }
 
853
 
 
854
                if (ok) {
 
855
                        lo->ldo_gssapi_options |= LDAP_GSSAPI_OPT_ALLOW_REMOTE_PRINCIPAL;
 
856
                }
 
857
 
 
858
                return 0;
 
859
        }
 
860
 
 
861
        return -1;
 
862
}
 
863
 
 
864
int
 
865
ldap_int_gssapi_get_option( LDAP *ld, int option, void *arg )
 
866
{
 
867
        if ( ld == NULL )
 
868
                return -1;
 
869
 
 
870
        switch ( option ) {
 
871
        case LDAP_OPT_SSPI_FLAGS:
 
872
                * (unsigned *) arg = (unsigned) ld->ld_options.gssapi_flags;
 
873
                break;
 
874
 
 
875
        case LDAP_OPT_SIGN:
 
876
                if ( ld->ld_options.gssapi_flags & GSS_C_INTEG_FLAG ) {
 
877
                        * (int *) arg = (int)-1;
 
878
                } else {
 
879
                        * (int *) arg = (int)0;
 
880
                }
 
881
                break;
 
882
 
 
883
        case LDAP_OPT_ENCRYPT:
 
884
                if ( ld->ld_options.gssapi_flags & GSS_C_CONF_FLAG ) {
 
885
                        * (int *) arg = (int)-1;
 
886
                } else {
 
887
                        * (int *) arg = (int)0;
 
888
                }
 
889
                break;
 
890
 
 
891
        case LDAP_OPT_SASL_METHOD:
 
892
                * (char **) arg = LDAP_STRDUP("GSS-SPNEGO");
 
893
                break;
 
894
 
 
895
        case LDAP_OPT_SECURITY_CONTEXT:
 
896
                if ( ld->ld_defconn && ld->ld_defconn->lconn_gss_ctx ) {
 
897
                        * (gss_ctx_id_t *) arg = (gss_ctx_id_t)ld->ld_defconn->lconn_gss_ctx;
 
898
                } else {
 
899
                        * (gss_ctx_id_t *) arg = GSS_C_NO_CONTEXT;
 
900
                }
 
901
                break;
 
902
 
 
903
        case LDAP_OPT_X_GSSAPI_DO_NOT_FREE_CONTEXT:
 
904
                if ( ld->ld_options.ldo_gssapi_options & LDAP_GSSAPI_OPT_DO_NOT_FREE_GSS_CONTEXT ) {
 
905
                        * (int *) arg = (int)-1;
 
906
                } else {
 
907
                        * (int *) arg = (int)0;
 
908
                }
 
909
                break;
 
910
 
 
911
        case LDAP_OPT_X_GSSAPI_ALLOW_REMOTE_PRINCIPAL:
 
912
                if ( ld->ld_options.ldo_gssapi_options & LDAP_GSSAPI_OPT_ALLOW_REMOTE_PRINCIPAL ) {
 
913
                        * (int *) arg = (int)-1;
 
914
                } else {
 
915
                        * (int *) arg = (int)0;
 
916
                }
 
917
                break;
 
918
 
 
919
        default:
 
920
                return -1;
 
921
        }
 
922
 
 
923
        return 0;
 
924
}
 
925
 
 
926
int
 
927
ldap_int_gssapi_set_option( LDAP *ld, int option, void *arg )
 
928
{
 
929
        if ( ld == NULL )
 
930
                return -1;
 
931
 
 
932
        switch ( option ) {
 
933
        case LDAP_OPT_SSPI_FLAGS:
 
934
                if ( arg != LDAP_OPT_OFF ) {
 
935
                        ld->ld_options.gssapi_flags = * (unsigned *)arg;
 
936
                }
 
937
                break;
 
938
 
 
939
        case LDAP_OPT_SIGN:
 
940
                if ( arg != LDAP_OPT_OFF ) {
 
941
                        ld->ld_options.gssapi_flags |= GSS_C_INTEG_FLAG;
 
942
                }
 
943
                break;
 
944
 
 
945
        case LDAP_OPT_ENCRYPT:
 
946
                if ( arg != LDAP_OPT_OFF ) {
 
947
                        ld->ld_options.gssapi_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
 
948
                }
 
949
                break;
 
950
 
 
951
        case LDAP_OPT_SASL_METHOD:
 
952
                if ( arg != LDAP_OPT_OFF ) {
 
953
                        const char *m = (const char *)arg;
 
954
                        if ( strcmp( "GSS-SPNEGO", m ) != 0 ) {
 
955
                                /* we currently only support GSS-SPNEGO */
 
956
                                return -1;
 
957
                        }
 
958
                }
 
959
                break;
 
960
 
 
961
        case LDAP_OPT_SECURITY_CONTEXT:
 
962
                if ( arg != LDAP_OPT_OFF && ld->ld_defconn) {
 
963
                        ldap_int_gssapi_setup( ld, ld->ld_defconn,
 
964
                                               (gss_ctx_id_t) arg);
 
965
                }
 
966
                break;
 
967
 
 
968
        case LDAP_OPT_X_GSSAPI_DO_NOT_FREE_CONTEXT:
 
969
                if ( arg != LDAP_OPT_OFF ) {
 
970
                        ld->ld_options.ldo_gssapi_options |= LDAP_GSSAPI_OPT_DO_NOT_FREE_GSS_CONTEXT;
 
971
                }
 
972
                break;
 
973
 
 
974
        case LDAP_OPT_X_GSSAPI_ALLOW_REMOTE_PRINCIPAL:
 
975
                if ( arg != LDAP_OPT_OFF ) {
 
976
                        ld->ld_options.ldo_gssapi_options |= LDAP_GSSAPI_OPT_ALLOW_REMOTE_PRINCIPAL;
 
977
                }
 
978
                break;
 
979
 
 
980
        default:
 
981
                return -1;
 
982
        }
 
983
 
 
984
        return 0;
 
985
}
 
986
 
 
987
#else /* HAVE_GSSAPI */
 
988
#define ldap_int_gss_spnego_bind_s(ld) LDAP_NOT_SUPPORTED
 
989
#endif /* HAVE_GSSAPI */
 
990
 
 
991
int
 
992
ldap_gssapi_bind(
 
993
        LDAP *ld,
 
994
        LDAP_CONST char *dn,
 
995
        LDAP_CONST char *creds )
 
996
{
 
997
        return LDAP_NOT_SUPPORTED;
 
998
}
 
999
 
 
1000
int
 
1001
ldap_gssapi_bind_s(
 
1002
        LDAP *ld,
 
1003
        LDAP_CONST char *dn,
 
1004
        LDAP_CONST char *creds )
 
1005
{
 
1006
        if ( dn != NULL ) {
 
1007
                return LDAP_NOT_SUPPORTED;
 
1008
        }
 
1009
 
 
1010
        if ( creds != NULL ) {
 
1011
                return LDAP_NOT_SUPPORTED;
 
1012
        }
 
1013
 
 
1014
        return ldap_int_gss_spnego_bind_s(ld);
 
1015
}