~ubuntu-branches/ubuntu/maverick/openldap/maverick-proposed

« back to all changes in this revision

Viewing changes to libraries/libldap/tls_m.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathias Gug, Steve Langasek, Mathias Gug
  • Date: 2009-02-18 18:44:00 UTC
  • mfrom: (1.1.2 upstream) (0.1.2 lenny)
  • Revision ID: james.westby@ubuntu.com-20090218184400-zw4mjse9eywt5566
Tags: 2.4.14-0ubuntu1
[ Steve Langasek ]
* New upstream version
  - Fixes a bug with the pcache overlay not returning cached entries
    (closes: #497697)
  - Update evolution-ntlm patch to apply to current Makefiles.
  - (tentatively) drop gnutls-ciphers, since this bug was reported to be
    fixed upstream in 2.4.8.  The fix applied in 2.4.8 didn't match the
    patch from the bug report, so this should be watched for regressions.
* Build against db4.7 instead of db4.2 at last!  Closes: #421946.
* Build with --disable-ndb, to avoid a misbuild when libmysqlclient is
  installed in the build environment.
* New patch, no-crlcheck-for-gnutls, to fix a build failure when using
  --with-tls=gnutls.

[ Mathias Gug ]
* Merge from debian unstable, remaining changes:
  - debian/apparmor-profile: add AppArmor profile
  - debian/slapd.postinst: Reload AA profile on configuration
  - updated debian/slapd.README.Debian for note on AppArmor
  - debian/control: Recommends apparmor >= 2.1+1075-0ubuntu6
  - debian/control: Conflicts with apparmor-profiles << 2.1+1075-0ubuntu4
    to make sure that if earlier version of apparmour-profiles gets
    installed it won't overwrite our profile.
  - Modify Maintainer value to match the DebianMaintainerField
    speficication.
  - follow ApparmorProfileMigration and force apparmor compalin mode on 
    some upgrades (LP: #203529)
  - debian/slapd.dirs: add etc/apparmor.d/force-complain
  - debian/slapd.preinst: create symlink for force-complain on pre-feisty
    upgrades, upgrades where apparmor-profiles profile is unchanged (ie
    non-enforcing) and upgrades where apparmor profile does not exist.
  - debian/slapd.postrm: remove symlink in force-complain/ on purge
  - debian/patches/fix-ucred-libc due to changes how newer glibc handle
    the ucred struct now.
  - debian/control:
    - Build-depend on libltdl7-dev rather then libltdl3-dev.
  - debian/patches/autogen.sh:
    - Call libtoolize with the --install option to install config.{guess,sub}
      files.
  - Don't use local statement in config script as it fails if /bin/sh
    points to bash (LP: #286063).
  - Disable the testsuite on hppa. Allows building of packages on this
    architecture again, once this package is in the archive.
    LP: #288908.
  - debian/slapd.postinst, debian/slapd.script-common: set correct ownership
    and permissions on /var/lib/ldap, /etc/ldap/slapd.d (group readable) and
    /var/run/slapd (world readable). (LP: #257667).
  - debian/patches/nssov-build, debian/rules: 
    Build and package the nss overlay.
    debian/schema/misc.ldif: add ldif file for the misc schema, which defines
    rfc822MailMember (required by the nss overlay).
  - debian/{control,rules}: enable PIE hardening
  - Use cn=config as the default configuration backend instead of 
    slapd.conf. Migrate slapd.conf  file to /etc/ldap/slapd.d/ on upgrade
    asking the end user to enter a new password to control the access to the
    cn=config tree.
* debian/patches/corrupt-contextCSN: The contextCSN can get corrupted at
  times. (ITS: #5947)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* tls_m.c - Handle tls/ssl using Mozilla NSS. */
 
2
/* $OpenLDAP: pkg/ldap/libraries/libldap/tls_m.c,v 1.3.2.2 2009/02/10 16:41:01 quanah Exp $ */
 
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 
4
 *
 
5
 * Copyright 2008-2009 The OpenLDAP Foundation.
 
6
 * All rights reserved.
 
7
 *
 
8
 * Redistribution and use in source and binary forms, with or without
 
9
 * modification, are permitted only as authorized by the OpenLDAP
 
10
 * Public License.
 
11
 *
 
12
 * A copy of this license is available in the file LICENSE in the
 
13
 * top-level directory of the distribution or, alternatively, at
 
14
 * <http://www.OpenLDAP.org/license.html>.
 
15
 */
 
16
/* ACKNOWLEDGEMENTS: written by Howard Chu.
 
17
 */
 
18
 
 
19
#include "portable.h"
 
20
 
 
21
#ifdef HAVE_MOZNSS
 
22
 
 
23
#include "ldap_config.h"
 
24
 
 
25
#include <stdio.h>
 
26
 
 
27
#include <ac/stdlib.h>
 
28
#include <ac/errno.h>
 
29
#include <ac/socket.h>
 
30
#include <ac/string.h>
 
31
#include <ac/ctype.h>
 
32
#include <ac/time.h>
 
33
#include <ac/unistd.h>
 
34
#include <ac/param.h>
 
35
#include <ac/dirent.h>
 
36
 
 
37
#include "ldap-int.h"
 
38
#include "ldap-tls.h"
 
39
 
 
40
#ifdef LDAP_R_COMPILE
 
41
#include <ldap_pvt_thread.h>
 
42
#endif
 
43
 
 
44
#include <nspr.h>
 
45
#include <nss.h>
 
46
#include <ssl.h>
 
47
 
 
48
typedef struct tlsm_ctx {
 
49
        PRFileDesc *tc_model;
 
50
        int tc_refcnt;
 
51
#ifdef LDAP_R_COMPILE
 
52
        ldap_pvt_thread_mutex_t tc_refmutex;
 
53
#endif
 
54
} tlsm_ctx;
 
55
 
 
56
typedef PRFileDesc tlsm_session;
 
57
 
 
58
static PRDescIdentity   tlsm_layer_id;
 
59
 
 
60
static const PRIOMethods tlsm_PR_methods;
 
61
 
 
62
extern tls_impl ldap_int_tls_impl;
 
63
 
 
64
#ifdef LDAP_R_COMPILE
 
65
 
 
66
static void
 
67
tlsm_thr_init( void )
 
68
{
 
69
}
 
70
 
 
71
#endif /* LDAP_R_COMPILE */
 
72
 
 
73
/*
 
74
 * Initialize TLS subsystem. Should be called only once.
 
75
 */
 
76
static int
 
77
tlsm_init( void )
 
78
{
 
79
        PR_Init(0, 0, 0);
 
80
 
 
81
        tlsm_layer_id = PR_GetUniqueIdentity("OpenLDAP");
 
82
 
 
83
        if ( !NSS_IsInitialized() ) {
 
84
                NSS_NoDB_Init("");
 
85
 
 
86
                NSS_SetDomesticPolicy();
 
87
        }
 
88
 
 
89
        /* No cipher suite handling for now */
 
90
 
 
91
        return 0;
 
92
}
 
93
 
 
94
/*
 
95
 * Tear down the TLS subsystem. Should only be called once.
 
96
 */
 
97
static void
 
98
tlsm_destroy( void )
 
99
{
 
100
        NSS_Shutdown();
 
101
 
 
102
        PR_Cleanup();
 
103
}
 
104
 
 
105
static tls_ctx *
 
106
tlsm_ctx_new ( struct ldapoptions *lo )
 
107
{
 
108
        tlsm_ctx *ctx;
 
109
 
 
110
        ctx = LDAP_MALLOC( sizeof (*ctx) );
 
111
        if ( ctx ) {
 
112
                PRFileDesc *fd = PR_CreateIOLayerStub(tlsm_layer_id, &tlsm_PR_methods);
 
113
                if ( fd ) {
 
114
                        ctx->tc_model = SSL_ImportFD( NULL, fd );
 
115
                        if ( ctx->tc_model ) {
 
116
                                ctx->tc_refcnt = 1;
 
117
#ifdef LDAP_R_COMPILE
 
118
                                ldap_pvt_thread_mutex_init( &ctx->tc_refmutex );
 
119
#endif
 
120
                        } else {
 
121
                                PR_DELETE( fd );
 
122
                                LDAP_FREE( ctx );
 
123
                                ctx = NULL;
 
124
                        }
 
125
                } else {
 
126
                        LDAP_FREE( ctx );
 
127
                        ctx = NULL;
 
128
                }
 
129
        }
 
130
        return (tls_ctx *)ctx;
 
131
}
 
132
 
 
133
static void
 
134
tlsm_ctx_ref( tls_ctx *ctx )
 
135
{
 
136
        tlsm_ctx *c = (tlsm_ctx *)ctx;
 
137
#ifdef LDAP_R_COMPILE
 
138
        ldap_pvt_thread_mutex_lock( &c->tc_refmutex );
 
139
#endif
 
140
        c->tc_refcnt++;
 
141
#ifdef LDAP_R_COMPILE
 
142
        ldap_pvt_thread_mutex_unlock( &c->tc_refmutex );
 
143
#endif
 
144
}
 
145
 
 
146
static void
 
147
tlsm_ctx_free ( tls_ctx *ctx )
 
148
{
 
149
        tlsm_ctx *c = (tlsm_ctx *)ctx;
 
150
        int refcount;
 
151
 
 
152
        if ( !c ) return;
 
153
 
 
154
#ifdef LDAP_R_COMPILE
 
155
        ldap_pvt_thread_mutex_lock( &c->tc_refmutex );
 
156
#endif
 
157
        refcount = --c->tc_refcnt;
 
158
#ifdef LDAP_R_COMPILE
 
159
        ldap_pvt_thread_mutex_unlock( &c->tc_refmutex );
 
160
#endif
 
161
        if ( refcount )
 
162
                return;
 
163
        PR_Close( c->tc_model );
 
164
#ifdef LDAP_R_COMPILE
 
165
        ldap_pvt_thread_mutex_destroy( &c->tc_refmutex );
 
166
#endif
 
167
        LDAP_FREE( c );
 
168
}
 
169
 
 
170
/*
 
171
 * initialize a new TLS context
 
172
 */
 
173
static int
 
174
tlsm_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server )
 
175
{
 
176
        tlsm_ctx *ctx = lo->ldo_tls_ctx;
 
177
        int rc;
 
178
 
 
179
        SSL_OptionSet( ctx->tc_model, SSL_SECURITY, PR_TRUE );
 
180
        SSL_OptionSet( ctx->tc_model, SSL_HANDSHAKE_AS_CLIENT, !is_server );
 
181
        SSL_OptionSet( ctx->tc_model, SSL_HANDSHAKE_AS_SERVER, is_server );
 
182
 
 
183
        /* See SECMOD_OpenUserDB() */
 
184
#if 0
 
185
        if ( lo->ldo_tls_ciphersuite &&
 
186
                tlsm_parse_ciphers( ctx, lt->lt_ciphersuite )) {
 
187
                Debug( LDAP_DEBUG_ANY,
 
188
                           "TLS: could not set cipher list %s.\n",
 
189
                           lo->ldo_tls_ciphersuite, 0, 0 );
 
190
                return -1;
 
191
        }
 
192
 
 
193
        if (lo->ldo_tls_cacertdir != NULL) {
 
194
                Debug( LDAP_DEBUG_ANY, 
 
195
                       "TLS: warning: cacertdir not implemented for gnutls\n",
 
196
                       NULL, NULL, NULL );
 
197
        }
 
198
 
 
199
        if (lo->ldo_tls_cacertfile != NULL) {
 
200
                rc = gnutls_certificate_set_x509_trust_file( 
 
201
                        ctx->cred,
 
202
                        lt->lt_cacertfile,
 
203
                        GNUTLS_X509_FMT_PEM );
 
204
                if ( rc < 0 ) return -1;
 
205
        }
 
206
 
 
207
        if ( lo->ldo_tls_certfile && lo->ldo_tls_keyfile ) {
 
208
                rc = gnutls_certificate_set_x509_key_file( 
 
209
                        ctx->cred,
 
210
                        lt->lt_certfile,
 
211
                        lt->lt_keyfile,
 
212
                        GNUTLS_X509_FMT_PEM );
 
213
                if ( rc ) return -1;
 
214
        } else if ( lo->ldo_tls_certfile || lo->ldo_tls_keyfile ) {
 
215
                Debug( LDAP_DEBUG_ANY, 
 
216
                       "TLS: only one of certfile and keyfile specified\n",
 
217
                       NULL, NULL, NULL );
 
218
                return -1;
 
219
        }
 
220
 
 
221
        if ( lo->ldo_tls_dhfile ) {
 
222
                Debug( LDAP_DEBUG_ANY, 
 
223
                       "TLS: warning: ignoring dhfile\n", 
 
224
                       NULL, NULL, NULL );
 
225
        }
 
226
 
 
227
        if ( lo->ldo_tls_crlfile ) {
 
228
                rc = gnutls_certificate_set_x509_crl_file( 
 
229
                        ctx->cred,
 
230
                        lt->lt_crlfile,
 
231
                        GNUTLS_X509_FMT_PEM );
 
232
                if ( rc < 0 ) return -1;
 
233
                rc = 0;
 
234
        }
 
235
        if ( is_server ) {
 
236
                gnutls_dh_params_init(&ctx->dh_params);
 
237
                gnutls_dh_params_generate2(ctx->dh_params, DH_BITS);
 
238
        }
 
239
#endif
 
240
        return 0;
 
241
}
 
242
 
 
243
static tls_session *
 
244
tlsm_session_new ( tls_ctx * ctx, int is_server )
 
245
{
 
246
        tlsm_ctx *c = (tlsm_ctx *)ctx;
 
247
        tlsm_session *session;
 
248
        PRFileDesc *fd;
 
249
 
 
250
        fd = PR_CreateIOLayerStub(tlsm_layer_id, &tlsm_PR_methods);
 
251
        if ( !fd ) {
 
252
                return NULL;
 
253
        }
 
254
 
 
255
        session = SSL_ImportFD( c->tc_model, fd );
 
256
        if ( !session ) {
 
257
                PR_DELETE( fd );
 
258
                return NULL;
 
259
        }
 
260
 
 
261
        SSL_ResetHandshake( session, is_server );
 
262
 
 
263
        return (tls_session *)session;
 
264
 
265
 
 
266
static int
 
267
tlsm_session_accept( tls_session *session )
 
268
{
 
269
        tlsm_session *s = (tlsm_session *)session;
 
270
 
 
271
        return SSL_ForceHandshake( s );
 
272
}
 
273
 
 
274
static int
 
275
tlsm_session_connect( LDAP *ld, tls_session *session )
 
276
{
 
277
        tlsm_session *s = (tlsm_session *)session;
 
278
        int rc;
 
279
 
 
280
        /* By default, NSS checks the cert hostname for us */
 
281
        rc = SSL_SetURL( s, ld->ld_options.ldo_defludp->lud_host );
 
282
        return SSL_ForceHandshake( s );
 
283
}
 
284
 
 
285
static int
 
286
tlsm_session_upflags( Sockbuf *sb, tls_session *session, int rc )
 
287
{
 
288
        /* Should never happen */
 
289
        rc = PR_GetError();
 
290
 
 
291
        if ( rc != PR_PENDING_INTERRUPT_ERROR && rc != PR_WOULD_BLOCK_ERROR )
 
292
                return 0;
 
293
        return 0;
 
294
}
 
295
 
 
296
static char *
 
297
tlsm_session_errmsg( int rc, char *buf, size_t len )
 
298
{
 
299
        int i;
 
300
 
 
301
        rc = PR_GetError();
 
302
        i = PR_GetErrorTextLength();
 
303
        if ( i > len ) {
 
304
                char *msg = LDAP_MALLOC( i+1 );
 
305
                PR_GetErrorText( msg );
 
306
                memcpy( buf, msg, len );
 
307
                LDAP_FREE( msg );
 
308
        } else if ( i ) {
 
309
                PR_GetErrorText( buf );
 
310
        }
 
311
 
 
312
        return i ? buf : NULL;
 
313
}
 
314
 
 
315
static int
 
316
tlsm_session_my_dn( tls_session *session, struct berval *der_dn )
 
317
{
 
318
        tlsm_session *s = (tlsm_session *)session;
 
319
        CERTCertificate *cert;
 
320
 
 
321
        cert = SSL_LocalCertificate( s );
 
322
        if (!cert) return LDAP_INVALID_CREDENTIALS;
 
323
 
 
324
        der_dn->bv_val = cert->derSubject.data;
 
325
        der_dn->bv_len = cert->derSubject.len;
 
326
        CERT_DestroyCertificate( cert );
 
327
        return 0;
 
328
}
 
329
 
 
330
static int
 
331
tlsm_session_peer_dn( tls_session *session, struct berval *der_dn )
 
332
{
 
333
        tlsm_session *s = (tlsm_session *)session;
 
334
        CERTCertificate *cert;
 
335
 
 
336
        cert = SSL_PeerCertificate( s );
 
337
        if (!cert) return LDAP_INVALID_CREDENTIALS;
 
338
        
 
339
        der_dn->bv_val = cert->derSubject.data;
 
340
        der_dn->bv_len = cert->derSubject.len;
 
341
        CERT_DestroyCertificate( cert );
 
342
        return 0;
 
343
}
 
344
 
 
345
/* what kind of hostname were we given? */
 
346
#define IS_DNS  0
 
347
#define IS_IP4  1
 
348
#define IS_IP6  2
 
349
 
 
350
static int
 
351
tlsm_session_chkhost( LDAP *ld, tls_session *session, const char *name_in )
 
352
{
 
353
/* NSS already does a hostname check */
 
354
#if 0
 
355
        int i, ret;
 
356
        const gnutls_datum_t *peer_cert_list;
 
357
        int list_size;
 
358
        struct berval bv;
 
359
        char altname[NI_MAXHOST];
 
360
        size_t altnamesize;
 
361
 
 
362
        gnutls_x509_crt_t cert;
 
363
        gnutls_datum_t *x;
 
364
        const char *name;
 
365
        char *ptr;
 
366
        char *domain = NULL;
 
367
#ifdef LDAP_PF_INET6
 
368
        struct in6_addr addr;
 
369
#else
 
370
        struct in_addr addr;
 
371
#endif
 
372
        int n, len1 = 0, len2 = 0;
 
373
        int ntype = IS_DNS;
 
374
        time_t now = time(0);
 
375
 
 
376
        if( ldap_int_hostname &&
 
377
                ( !name_in || !strcasecmp( name_in, "localhost" ) ) )
 
378
        {
 
379
                name = ldap_int_hostname;
 
380
        } else {
 
381
                name = name_in;
 
382
        }
 
383
 
 
384
        peer_cert_list = gnutls_certificate_get_peers( session->session, 
 
385
                                                &list_size );
 
386
        if ( !peer_cert_list ) {
 
387
                Debug( LDAP_DEBUG_ANY,
 
388
                        "TLS: unable to get peer certificate.\n",
 
389
                        0, 0, 0 );
 
390
                /* If this was a fatal condition, things would have
 
391
                 * aborted long before now.
 
392
                 */
 
393
                return LDAP_SUCCESS;
 
394
        }
 
395
        ret = gnutls_x509_crt_init( &cert );
 
396
        if ( ret < 0 )
 
397
                return LDAP_LOCAL_ERROR;
 
398
        ret = gnutls_x509_crt_import( cert, peer_cert_list, GNUTLS_X509_FMT_DER );
 
399
        if ( ret ) {
 
400
                gnutls_x509_crt_deinit( cert );
 
401
                return LDAP_LOCAL_ERROR;
 
402
        }
 
403
 
 
404
#ifdef LDAP_PF_INET6
 
405
        if (name[0] == '[' && strchr(name, ']')) {
 
406
                char *n2 = ldap_strdup(name+1);
 
407
                *strchr(n2, ']') = 0;
 
408
                if (inet_pton(AF_INET6, n2, &addr))
 
409
                        ntype = IS_IP6;
 
410
                LDAP_FREE(n2);
 
411
        } else 
 
412
#endif
 
413
        if ((ptr = strrchr(name, '.')) && isdigit((unsigned char)ptr[1])) {
 
414
                if (inet_aton(name, (struct in_addr *)&addr)) ntype = IS_IP4;
 
415
        }
 
416
        
 
417
        if (ntype == IS_DNS) {
 
418
                len1 = strlen(name);
 
419
                domain = strchr(name, '.');
 
420
                if (domain) {
 
421
                        len2 = len1 - (domain-name);
 
422
                }
 
423
        }
 
424
 
 
425
        for ( i=0, ret=0; ret >= 0; i++ ) {
 
426
                altnamesize = sizeof(altname);
 
427
                ret = gnutls_x509_crt_get_subject_alt_name( cert, i, 
 
428
                        altname, &altnamesize, NULL );
 
429
                if ( ret < 0 ) break;
 
430
 
 
431
                /* ignore empty */
 
432
                if ( altnamesize == 0 ) continue;
 
433
 
 
434
                if ( ret == GNUTLS_SAN_DNSNAME ) {
 
435
                        if (ntype != IS_DNS) continue;
 
436
        
 
437
                        /* Is this an exact match? */
 
438
                        if ((len1 == altnamesize) && !strncasecmp(name, altname, len1)) {
 
439
                                break;
 
440
                        }
 
441
 
 
442
                        /* Is this a wildcard match? */
 
443
                        if (domain && (altname[0] == '*') && (altname[1] == '.') &&
 
444
                                (len2 == altnamesize-1) && !strncasecmp(domain, &altname[1], len2))
 
445
                        {
 
446
                                break;
 
447
                        }
 
448
                } else if ( ret == GNUTLS_SAN_IPADDRESS ) {
 
449
                        if (ntype == IS_DNS) continue;
 
450
 
 
451
#ifdef LDAP_PF_INET6
 
452
                        if (ntype == IS_IP6 && altnamesize != sizeof(struct in6_addr)) {
 
453
                                continue;
 
454
                        } else
 
455
#endif
 
456
                        if (ntype == IS_IP4 && altnamesize != sizeof(struct in_addr)) {
 
457
                                continue;
 
458
                        }
 
459
                        if (!memcmp(altname, &addr, altnamesize)) {
 
460
                                break;
 
461
                        }
 
462
                }
 
463
        }
 
464
        if ( ret >= 0 ) {
 
465
                ret = LDAP_SUCCESS;
 
466
        } else {
 
467
                altnamesize = sizeof(altname);
 
468
                ret = gnutls_x509_crt_get_dn_by_oid( cert, CN_OID,
 
469
                        0, 0, altname, &altnamesize );
 
470
                if ( ret < 0 ) {
 
471
                        Debug( LDAP_DEBUG_ANY,
 
472
                                "TLS: unable to get common name from peer certificate.\n",
 
473
                                0, 0, 0 );
 
474
                        ret = LDAP_CONNECT_ERROR;
 
475
                        if ( ld->ld_error ) {
 
476
                                LDAP_FREE( ld->ld_error );
 
477
                        }
 
478
                        ld->ld_error = LDAP_STRDUP(
 
479
                                _("TLS: unable to get CN from peer certificate"));
 
480
 
 
481
                } else {
 
482
                        ret = LDAP_LOCAL_ERROR;
 
483
                        if ( len1 == altnamesize && strncasecmp(name, altname, altnamesize) == 0 ) {
 
484
                                ret = LDAP_SUCCESS;
 
485
 
 
486
                        } else if (( altname[0] == '*' ) && ( altname[1] == '.' )) {
 
487
                                        /* Is this a wildcard match? */
 
488
                                if( domain &&
 
489
                                        (len2 == altnamesize-1) && !strncasecmp(domain, &altname[1], len2)) {
 
490
                                        ret = LDAP_SUCCESS;
 
491
                                }
 
492
                        }
 
493
                }
 
494
 
 
495
                if( ret == LDAP_LOCAL_ERROR ) {
 
496
                        altname[altnamesize] = '\0';
 
497
                        Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match "
 
498
                                "common name in certificate (%s).\n", 
 
499
                                name, altname, 0 );
 
500
                        ret = LDAP_CONNECT_ERROR;
 
501
                        if ( ld->ld_error ) {
 
502
                                LDAP_FREE( ld->ld_error );
 
503
                        }
 
504
                        ld->ld_error = LDAP_STRDUP(
 
505
                                _("TLS: hostname does not match CN in peer certificate"));
 
506
                }
 
507
        }
 
508
        gnutls_x509_crt_deinit( cert );
 
509
        return ret;
 
510
#endif
 
511
}
 
512
 
 
513
static int
 
514
tlsm_session_strength( tls_session *session )
 
515
{
 
516
        tlsm_session *s = (tlsm_session *)session;
 
517
        int rc, keySize;
 
518
 
 
519
        rc = SSL_SecurityStatus( s, NULL, NULL, NULL, &keySize,
 
520
                NULL, NULL );
 
521
        return rc ? 0 : keySize;
 
522
}
 
523
 
 
524
/*
 
525
 * TLS support for LBER Sockbufs
 
526
 */
 
527
 
 
528
struct tls_data {
 
529
        tlsm_session            *session;
 
530
        Sockbuf_IO_Desc         *sbiod;
 
531
};
 
532
 
 
533
 
 
534
static PRStatus PR_CALLBACK
 
535
tlsm_PR_Close(PRFileDesc *fd)
 
536
{
 
537
        return PR_SUCCESS;
 
538
}
 
539
 
 
540
static int PR_CALLBACK
 
541
tlsm_PR_Recv(PRFileDesc *fd, void *buf, PRInt32 len, PRIntn flags,
 
542
         PRIntervalTime timeout)
 
543
{
 
544
        struct tls_data         *p;
 
545
 
 
546
        if ( buf == NULL || len <= 0 ) return 0;
 
547
 
 
548
        p = (struct tls_data *)fd->secret;
 
549
 
 
550
        if ( p == NULL || p->sbiod == NULL ) {
 
551
                return 0;
 
552
        }
 
553
 
 
554
        return LBER_SBIOD_READ_NEXT( p->sbiod, buf, len );
 
555
}
 
556
 
 
557
static int PR_CALLBACK
 
558
tlsm_PR_Send(PRFileDesc *fd, const void *buf, PRInt32 len, PRIntn flags,
 
559
         PRIntervalTime timeout)
 
560
{
 
561
        struct tls_data         *p;
 
562
 
 
563
        if ( buf == NULL || len <= 0 ) return 0;
 
564
 
 
565
        p = (struct tls_data *)fd->secret;
 
566
 
 
567
        if ( p == NULL || p->sbiod == NULL ) {
 
568
                return 0;
 
569
        }
 
570
 
 
571
        return LBER_SBIOD_WRITE_NEXT( p->sbiod, (char *)buf, len );
 
572
}
 
573
 
 
574
static int PR_CALLBACK
 
575
tlsm_PR_Read(PRFileDesc *fd, void *buf, PRInt32 len)
 
576
{
 
577
        return tlsm_PR_Recv( fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
 
578
}
 
579
 
 
580
static int PR_CALLBACK
 
581
tlsm_PR_Write(PRFileDesc *fd, const void *buf, PRInt32 len)
 
582
{
 
583
        return tlsm_PR_Send( fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
 
584
}
 
585
 
 
586
static PRStatus PR_CALLBACK
 
587
tlsm_PR_GetPeerName(PRFileDesc *fd, PRNetAddr *addr)
 
588
{
 
589
        struct tls_data         *p;
 
590
        int rc;
 
591
        ber_socklen_t len;
 
592
 
 
593
        p = (struct tls_data *)fd->secret;
 
594
 
 
595
        if ( p == NULL || p->sbiod == NULL ) {
 
596
                return PR_FAILURE;
 
597
        }
 
598
        len = sizeof(PRNetAddr);
 
599
        return getpeername( p->sbiod->sbiod_sb->sb_fd, (struct sockaddr *)addr, &len );
 
600
}
 
601
 
 
602
static PRStatus PR_CALLBACK
 
603
tlsm_PR_prs_unimp()
 
604
{
 
605
    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
 
606
    return PR_FAILURE;
 
607
}
 
608
 
 
609
static PRFileDesc * PR_CALLBACK
 
610
tlsm_PR_pfd_unimp()
 
611
{
 
612
    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
 
613
    return NULL;
 
614
}
 
615
 
 
616
static PRInt16 PR_CALLBACK
 
617
tlsm_PR_i16_unimp()
 
618
{
 
619
    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
 
620
    return SECFailure;
 
621
}
 
622
 
 
623
static PRInt32 PR_CALLBACK
 
624
tlsm_PR_i32_unimp()
 
625
{
 
626
    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
 
627
    return SECFailure;
 
628
}
 
629
 
 
630
static PRInt64 PR_CALLBACK
 
631
tlsm_PR_i64_unimp()
 
632
{
 
633
    PRInt64 res;
 
634
 
 
635
    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
 
636
    LL_I2L(res, -1L);
 
637
    return res;
 
638
}
 
639
 
 
640
static const PRIOMethods tlsm_PR_methods = {
 
641
    PR_DESC_LAYERED,
 
642
    tlsm_PR_Close,                      /* close        */
 
643
    tlsm_PR_Read,                       /* read         */
 
644
    tlsm_PR_Write,                      /* write        */
 
645
    tlsm_PR_i32_unimp,          /* available    */
 
646
    tlsm_PR_i64_unimp,          /* available64  */
 
647
    tlsm_PR_prs_unimp,          /* fsync        */
 
648
    tlsm_PR_i32_unimp,          /* seek         */
 
649
    tlsm_PR_i64_unimp,          /* seek64       */
 
650
    tlsm_PR_prs_unimp,          /* fileInfo     */
 
651
    tlsm_PR_prs_unimp,          /* fileInfo64   */
 
652
    tlsm_PR_i32_unimp,          /* writev       */
 
653
    tlsm_PR_prs_unimp,          /* connect      */
 
654
    tlsm_PR_pfd_unimp,          /* accept       */
 
655
    tlsm_PR_prs_unimp,          /* bind         */
 
656
    tlsm_PR_prs_unimp,          /* listen       */
 
657
    (PRShutdownFN)tlsm_PR_Close,                        /* shutdown     */
 
658
    tlsm_PR_Recv,                       /* recv         */
 
659
    tlsm_PR_Send,                       /* send         */
 
660
    tlsm_PR_i32_unimp,          /* recvfrom     */
 
661
    tlsm_PR_i32_unimp,          /* sendto       */
 
662
    (PRPollFN)tlsm_PR_i16_unimp,        /* poll         */
 
663
    tlsm_PR_i32_unimp,          /* acceptread   */
 
664
    tlsm_PR_i32_unimp,          /* transmitfile */
 
665
    tlsm_PR_prs_unimp,          /* getsockname  */
 
666
    tlsm_PR_GetPeerName,        /* getpeername  */
 
667
    tlsm_PR_i32_unimp,          /* getsockopt   OBSOLETE */
 
668
    tlsm_PR_i32_unimp,          /* setsockopt   OBSOLETE */
 
669
    tlsm_PR_i32_unimp,          /* getsocketoption   */
 
670
    tlsm_PR_i32_unimp,          /* setsocketoption   */
 
671
    tlsm_PR_i32_unimp,          /* Send a (partial) file with header/trailer*/
 
672
    (PRConnectcontinueFN)tlsm_PR_prs_unimp,             /* connectcontinue */
 
673
    tlsm_PR_i32_unimp,          /* reserved for future use */
 
674
    tlsm_PR_i32_unimp,          /* reserved for future use */
 
675
    tlsm_PR_i32_unimp,          /* reserved for future use */
 
676
    tlsm_PR_i32_unimp           /* reserved for future use */
 
677
};
 
678
 
 
679
static int
 
680
tlsm_sb_setup( Sockbuf_IO_Desc *sbiod, void *arg )
 
681
{
 
682
        struct tls_data         *p;
 
683
        tlsm_session    *session = arg;
 
684
        PRFileDesc *fd;
 
685
 
 
686
        assert( sbiod != NULL );
 
687
 
 
688
        p = LBER_MALLOC( sizeof( *p ) );
 
689
        if ( p == NULL ) {
 
690
                return -1;
 
691
        }
 
692
 
 
693
        fd = PR_GetIdentitiesLayer( session, tlsm_layer_id );
 
694
        if ( !fd ) {
 
695
                LBER_FREE( p );
 
696
                return -1;
 
697
        }
 
698
 
 
699
        fd->secret = (PRFilePrivate *)p;
 
700
        p->session = session;
 
701
        p->sbiod = sbiod;
 
702
        sbiod->sbiod_pvt = p;
 
703
        return 0;
 
704
}
 
705
 
 
706
static int
 
707
tlsm_sb_remove( Sockbuf_IO_Desc *sbiod )
 
708
{
 
709
        struct tls_data         *p;
 
710
        
 
711
        assert( sbiod != NULL );
 
712
        assert( sbiod->sbiod_pvt != NULL );
 
713
 
 
714
        p = (struct tls_data *)sbiod->sbiod_pvt;
 
715
        PR_Close( p->session );
 
716
        LBER_FREE( sbiod->sbiod_pvt );
 
717
        sbiod->sbiod_pvt = NULL;
 
718
        return 0;
 
719
}
 
720
 
 
721
static int
 
722
tlsm_sb_close( Sockbuf_IO_Desc *sbiod )
 
723
{
 
724
        struct tls_data         *p;
 
725
        
 
726
        assert( sbiod != NULL );
 
727
        assert( sbiod->sbiod_pvt != NULL );
 
728
 
 
729
        p = (struct tls_data *)sbiod->sbiod_pvt;
 
730
        PR_Shutdown( p->session, PR_SHUTDOWN_BOTH );
 
731
        return 0;
 
732
}
 
733
 
 
734
static int
 
735
tlsm_sb_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
 
736
{
 
737
        struct tls_data         *p;
 
738
        
 
739
        assert( sbiod != NULL );
 
740
        assert( sbiod->sbiod_pvt != NULL );
 
741
 
 
742
        p = (struct tls_data *)sbiod->sbiod_pvt;
 
743
        
 
744
        if ( opt == LBER_SB_OPT_GET_SSL ) {
 
745
                *((tlsm_session **)arg) = p->session;
 
746
                return 1;
 
747
                
 
748
        } else if ( opt == LBER_SB_OPT_DATA_READY ) {
 
749
        PRPollDesc pd = { p->session, PR_POLL_READ, 0 };
 
750
        if( PR_Poll( &pd, 1, 1 ) > 0 ) {
 
751
            return 1;
 
752
                }
 
753
        }
 
754
        
 
755
        return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
 
756
}
 
757
 
 
758
static ber_slen_t
 
759
tlsm_sb_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
 
760
{
 
761
        struct tls_data         *p;
 
762
        ber_slen_t              ret;
 
763
        int                     err;
 
764
 
 
765
        assert( sbiod != NULL );
 
766
        assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
 
767
 
 
768
        p = (struct tls_data *)sbiod->sbiod_pvt;
 
769
 
 
770
        ret = PR_Recv( p->session, buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
 
771
        if ( ret < 0 ) {
 
772
                err = PR_GetError();
 
773
                if ( err == PR_PENDING_INTERRUPT_ERROR || err == PR_WOULD_BLOCK_ERROR ) {
 
774
                        sbiod->sbiod_sb->sb_trans_needs_read = 1;
 
775
                        sock_errset(EWOULDBLOCK);
 
776
                }
 
777
        } else {
 
778
                sbiod->sbiod_sb->sb_trans_needs_read = 0;
 
779
        }
 
780
        return ret;
 
781
}
 
782
 
 
783
static ber_slen_t
 
784
tlsm_sb_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
 
785
{
 
786
        struct tls_data         *p;
 
787
        ber_slen_t              ret;
 
788
        int                     err;
 
789
 
 
790
        assert( sbiod != NULL );
 
791
        assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
 
792
 
 
793
        p = (struct tls_data *)sbiod->sbiod_pvt;
 
794
 
 
795
        ret = PR_Send( p->session, (char *)buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
 
796
        if ( ret < 0 ) {
 
797
                err = PR_GetError();
 
798
                if ( err == PR_PENDING_INTERRUPT_ERROR || err == PR_WOULD_BLOCK_ERROR ) {
 
799
                        sbiod->sbiod_sb->sb_trans_needs_write = 1;
 
800
                        sock_errset(EWOULDBLOCK);
 
801
                        ret = 0;
 
802
                }
 
803
        } else {
 
804
                sbiod->sbiod_sb->sb_trans_needs_write = 0;
 
805
        }
 
806
        return ret;
 
807
}
 
808
 
 
809
static Sockbuf_IO tlsm_sbio =
 
810
{
 
811
        tlsm_sb_setup,          /* sbi_setup */
 
812
        tlsm_sb_remove,         /* sbi_remove */
 
813
        tlsm_sb_ctrl,           /* sbi_ctrl */
 
814
        tlsm_sb_read,           /* sbi_read */
 
815
        tlsm_sb_write,          /* sbi_write */
 
816
        tlsm_sb_close           /* sbi_close */
 
817
};
 
818
 
 
819
tls_impl ldap_int_moznss_impl = {
 
820
        "MozNSS",
 
821
 
 
822
        tlsm_init,
 
823
        tlsm_destroy,
 
824
 
 
825
        tlsm_ctx_new,
 
826
        tlsm_ctx_ref,
 
827
        tlsm_ctx_free,
 
828
        tlsm_ctx_init,
 
829
 
 
830
        tlsm_session_new,
 
831
        tlsm_session_connect,
 
832
        tlsm_session_accept,
 
833
        tlsm_session_upflags,
 
834
        tlsm_session_errmsg,
 
835
        tlsm_session_my_dn,
 
836
        tlsm_session_peer_dn,
 
837
        tlsm_session_chkhost,
 
838
        tlsm_session_strength,
 
839
 
 
840
        &tlsm_sbio,
 
841
 
 
842
#ifdef LDAP_R_COMPILE
 
843
        tlsm_thr_init,
 
844
#else
 
845
        NULL,
 
846
#endif
 
847
 
 
848
        0
 
849
};
 
850
 
 
851
#endif /* HAVE_MOZNSS */