]> git.sur5r.net Git - openldap/blob - libraries/libldap/tls_m.c
30c8a766d12c51d114501aec79e01f32d2487552
[openldap] / libraries / libldap / tls_m.c
1 /* tls_m.c - Handle tls/ssl using Mozilla NSS. */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2008-2011 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: Initial version written by Howard Chu. 
17  * Additional support by Rich Megginson.
18  */
19
20 #include "portable.h"
21
22 #ifdef HAVE_MOZNSS
23
24 #include "ldap_config.h"
25
26 #include <stdio.h>
27
28 #if defined( HAVE_FCNTL_H )
29 #include <fcntl.h>
30 #endif
31
32 #include <ac/stdlib.h>
33 #include <ac/errno.h>
34 #include <ac/socket.h>
35 #include <ac/string.h>
36 #include <ac/ctype.h>
37 #include <ac/time.h>
38 #include <ac/unistd.h>
39 #include <ac/param.h>
40 #include <ac/dirent.h>
41
42 #include "ldap-int.h"
43 #include "ldap-tls.h"
44
45 #define READ_PASSWORD_FROM_STDIN
46 #define READ_PASSWORD_FROM_FILE
47
48 #ifdef READ_PASSWORD_FROM_STDIN
49 #include <termios.h> /* for echo on/off */
50 #endif
51
52 #include <nspr/nspr.h>
53 #include <nspr/private/pprio.h>
54 #include <nss/nss.h>
55 #include <nss/ssl.h>
56 #include <nss/sslerr.h>
57 #include <nss/sslproto.h>
58 #include <nss/pk11pub.h>
59 #include <nss/secerr.h>
60 #include <nss/keyhi.h>
61 #include <nss/secmod.h>
62 #include <nss/cert.h>
63
64 #undef NSS_VERSION_INT
65 #define NSS_VERSION_INT ((NSS_VMAJOR << 24) | (NSS_VMINOR << 16) | \
66         (NSS_VPATCH << 8) | NSS_VBUILD)
67
68 /* NSS 3.12.5 and later have NSS_InitContext */
69 #if NSS_VERSION_INT >= 0x030c0500
70 #define HAVE_NSS_INITCONTEXT 1
71 #endif
72
73 /* NSS 3.12.9 and later have SECMOD_RestartModules */
74 #if NSS_VERSION_INT >= 0x030c0900
75 #define HAVE_SECMOD_RESTARTMODULES 1
76 #endif
77
78 /* InitContext does not currently work in server mode */
79 /* #define INITCONTEXT_HACK 1 */
80
81 typedef struct tlsm_ctx {
82         PRFileDesc *tc_model;
83         int tc_refcnt;
84         PRBool tc_verify_cert;
85         CERTCertDBHandle *tc_certdb;
86         char *tc_certname;
87         char *tc_pin_file;
88         struct ldaptls *tc_config;
89         int tc_is_server;
90         int tc_require_cert;
91         PRCallOnceType tc_callonce;
92         PRBool tc_using_pem;
93         char *tc_slotname; /* if using pem */
94 #ifdef HAVE_NSS_INITCONTEXT
95         NSSInitContext *tc_initctx; /* the NSS context */
96 #endif
97         PK11GenericObject **tc_pem_objs; /* array of objects to free */
98         int tc_n_pem_objs; /* number of objects */
99         PRBool tc_warn_only; /* only warn of errors in validation */
100 #ifdef LDAP_R_COMPILE
101         ldap_pvt_thread_mutex_t tc_refmutex;
102 #endif
103 } tlsm_ctx;
104
105 typedef PRFileDesc tlsm_session;
106
107 static PRDescIdentity   tlsm_layer_id;
108
109 static const PRIOMethods tlsm_PR_methods;
110
111 #define PEM_LIBRARY     "nsspem"
112 #define PEM_MODULE      "PEM"
113 /* hash files for use with cacertdir have this file name suffix */
114 #define PEM_CA_HASH_FILE_SUFFIX ".0"
115 #define PEM_CA_HASH_FILE_SUFFIX_LEN 2
116
117 static SECMODModule *pem_module;
118
119 #define DEFAULT_TOKEN_NAME "default"
120 /* sprintf format used to create token name */
121 #define TLSM_PEM_TOKEN_FMT "PEM Token #%ld"
122
123 static int tlsm_slot_count;
124
125 #define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \
126                 (x)->pValue=(v); (x)->ulValueLen = (l);
127
128 /* forward declaration */
129 static int tlsm_init( void );
130
131 #ifdef LDAP_R_COMPILE
132
133 /* it doesn't seem guaranteed that a client will call
134    tlsm_thr_init in a non-threaded context - so we have
135    to wrap the mutex creation in a prcallonce
136 */
137 static ldap_pvt_thread_mutex_t tlsm_init_mutex;
138 static PRCallOnceType tlsm_init_mutex_callonce = {0,0};
139
140 static PRStatus PR_CALLBACK
141 tlsm_thr_init_callonce( void )
142 {
143         if ( ldap_pvt_thread_mutex_init( &tlsm_init_mutex ) ) {
144                 Debug( LDAP_DEBUG_ANY,
145                            "TLS: could not create mutex for moznss initialization: %d\n", errno, 0, 0 );
146                 return PR_FAILURE;
147         }
148
149         return PR_SUCCESS;
150 }
151
152 static void
153 tlsm_thr_init( void )
154 {
155     ( void )PR_CallOnce( &tlsm_init_mutex_callonce, tlsm_thr_init_callonce );
156 }
157
158 #endif /* LDAP_R_COMPILE */
159
160 static const char *
161 tlsm_dump_cipher_info(PRFileDesc *fd)
162 {
163         PRUint16 ii;
164
165         for (ii = 0; ii < SSL_NumImplementedCiphers; ++ii) {
166                 PRInt32 cipher = (PRInt32)SSL_ImplementedCiphers[ii];
167                 PRBool enabled = PR_FALSE;
168                 PRInt32 policy = 0;
169                 SSLCipherSuiteInfo info;
170
171                 if (fd) {
172                         SSL_CipherPrefGet(fd, cipher, &enabled);
173                 } else {
174                         SSL_CipherPrefGetDefault(cipher, &enabled);
175                 }
176                 SSL_CipherPolicyGet(cipher, &policy);
177                 SSL_GetCipherSuiteInfo(cipher, &info, (PRUintn)sizeof(info));
178                 Debug( LDAP_DEBUG_TRACE,
179                            "TLS: cipher: %d - %s, enabled: %d, ",
180                            info.cipherSuite, info.cipherSuiteName, enabled );
181                 Debug( LDAP_DEBUG_TRACE,
182                            "policy: %d\n", policy, 0, 0 );
183         }
184
185         return "";
186 }
187
188 /* Cipher definitions */
189 typedef struct {
190         char *ossl_name;    /* The OpenSSL cipher name */
191         int num;            /* The cipher id */
192         int attr;           /* cipher attributes: algorithms, etc */
193         int version;        /* protocol version valid for this cipher */
194         int bits;           /* bits of strength */
195         int alg_bits;       /* bits of the algorithm */
196         int strength;       /* LOW, MEDIUM, HIGH */
197         int enabled;        /* Enabled by default? */
198 } cipher_properties;
199
200 /* cipher attributes  */
201 #define SSL_kRSA  0x00000001L
202 #define SSL_aRSA  0x00000002L
203 #define SSL_aDSS  0x00000004L
204 #define SSL_DSS   SSL_aDSS
205 #define SSL_eNULL 0x00000008L
206 #define SSL_DES   0x00000010L
207 #define SSL_3DES  0x00000020L
208 #define SSL_RC4   0x00000040L
209 #define SSL_RC2   0x00000080L
210 #define SSL_AES   0x00000100L
211 #define SSL_MD5   0x00000200L
212 #define SSL_SHA1  0x00000400L
213 #define SSL_SHA   SSL_SHA1
214 #define SSL_RSA   (SSL_kRSA|SSL_aRSA)
215
216 /* cipher strength */
217 #define SSL_NULL      0x00000001L
218 #define SSL_EXPORT40  0x00000002L
219 #define SSL_EXPORT56  0x00000004L
220 #define SSL_LOW       0x00000008L
221 #define SSL_MEDIUM    0x00000010L
222 #define SSL_HIGH      0x00000020L
223
224 #define SSL2  0x00000001L
225 #define SSL3  0x00000002L
226 /* OpenSSL treats SSL3 and TLSv1 the same */
227 #define TLS1  SSL3
228
229 /* Cipher translation */
230 static cipher_properties ciphers_def[] = {
231         /* SSL 2 ciphers */
232         {"DES-CBC3-MD5", SSL_EN_DES_192_EDE3_CBC_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_3DES|SSL_MD5, SSL2, 168, 168, SSL_HIGH, SSL_ALLOWED},
233         {"RC2-CBC-MD5", SSL_EN_RC2_128_CBC_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_RC2|SSL_MD5, SSL2, 128, 128, SSL_MEDIUM, SSL_ALLOWED},
234         {"RC4-MD5", SSL_EN_RC4_128_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_MD5, SSL2, 128, 128, SSL_MEDIUM, SSL_ALLOWED},
235         {"DES-CBC-MD5", SSL_EN_DES_64_CBC_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_DES|SSL_MD5, SSL2, 56, 56, SSL_LOW, SSL_ALLOWED},
236         {"EXP-RC2-CBC-MD5", SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_RC2|SSL_MD5, SSL2, 40, 128, SSL_EXPORT40, SSL_ALLOWED},
237         {"EXP-RC4-MD5", SSL_EN_RC4_128_EXPORT40_WITH_MD5, SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_MD5, SSL2, 40, 128, SSL_EXPORT40, SSL_ALLOWED},
238
239         /* SSL3 ciphers */
240         {"RC4-MD5", SSL_RSA_WITH_RC4_128_MD5, SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_MD5, SSL3, 128, 128, SSL_MEDIUM, SSL_ALLOWED},
241         {"RC4-SHA", SSL_RSA_WITH_RC4_128_SHA, SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_SHA1, SSL3, 128, 128, SSL_MEDIUM, SSL_ALLOWED},
242         {"DES-CBC3-SHA", SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_kRSA|SSL_aRSA|SSL_3DES|SSL_SHA1, SSL3, 168, 168, SSL_HIGH, SSL_ALLOWED},
243         {"DES-CBC-SHA", SSL_RSA_WITH_DES_CBC_SHA, SSL_kRSA|SSL_aRSA|SSL_DES|SSL_SHA1, SSL3, 56, 56, SSL_LOW, SSL_ALLOWED},
244         {"EXP-RC4-MD5", SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_MD5, SSL3, 40, 128, SSL_EXPORT40, SSL_ALLOWED},
245         {"EXP-RC2-CBC-MD5", SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, SSL_kRSA|SSL_aRSA|SSL_RC2|SSL_MD5, SSL3, 0, 0, SSL_EXPORT40, SSL_ALLOWED},
246         {"NULL-MD5", SSL_RSA_WITH_NULL_MD5, SSL_kRSA|SSL_aRSA|SSL_eNULL|SSL_MD5, SSL3, 0, 0, SSL_NULL, SSL_NOT_ALLOWED},
247         {"NULL-SHA", SSL_RSA_WITH_NULL_SHA, SSL_kRSA|SSL_aRSA|SSL_eNULL|SSL_SHA1, SSL3, 0, 0, SSL_NULL, SSL_NOT_ALLOWED},
248
249         /* TLSv1 ciphers */
250         {"EXP1024-DES-CBC-SHA", TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, SSL_kRSA|SSL_aRSA|SSL_DES|SSL_SHA, TLS1, 56, 56, SSL_EXPORT56, SSL_ALLOWED},
251         {"EXP1024-RC4-SHA", TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_SHA, TLS1, 56, 56, SSL_EXPORT56, SSL_ALLOWED},
252         {"AES128-SHA", TLS_RSA_WITH_AES_128_CBC_SHA, SSL_kRSA|SSL_aRSA|SSL_AES|SSL_SHA, TLS1, 128, 128, SSL_HIGH, SSL_ALLOWED},
253         {"AES256-SHA", TLS_RSA_WITH_AES_256_CBC_SHA, SSL_kRSA|SSL_aRSA|SSL_AES|SSL_SHA, TLS1, 256, 256, SSL_HIGH, SSL_ALLOWED},
254 };
255
256 #define ciphernum (sizeof(ciphers_def)/sizeof(cipher_properties))
257
258 /* given err which is the current errno, calls PR_SetError with
259    the corresponding NSPR error code */
260 static void 
261 tlsm_map_error(int err)
262 {
263         PRErrorCode prError;
264
265         switch ( err ) {
266         case EACCES:
267                 prError = PR_NO_ACCESS_RIGHTS_ERROR;
268                 break;
269         case EADDRINUSE:
270                 prError = PR_ADDRESS_IN_USE_ERROR;
271                 break;
272         case EADDRNOTAVAIL:
273                 prError = PR_ADDRESS_NOT_AVAILABLE_ERROR;
274                 break;
275         case EAFNOSUPPORT:
276                 prError = PR_ADDRESS_NOT_SUPPORTED_ERROR;
277                 break;
278         case EAGAIN:
279                 prError = PR_WOULD_BLOCK_ERROR;
280                 break;
281         /*
282          * On QNX and Neutrino, EALREADY is defined as EBUSY.
283          */
284 #if EALREADY != EBUSY
285         case EALREADY:
286                 prError = PR_ALREADY_INITIATED_ERROR;
287                 break;
288 #endif
289         case EBADF:
290                 prError = PR_BAD_DESCRIPTOR_ERROR;
291                 break;
292 #ifdef EBADMSG
293         case EBADMSG:
294                 prError = PR_IO_ERROR;
295                 break;
296 #endif
297         case EBUSY:
298                 prError = PR_FILESYSTEM_MOUNTED_ERROR;
299                 break;
300         case ECONNABORTED:
301                 prError = PR_CONNECT_ABORTED_ERROR;
302                 break;
303         case ECONNREFUSED:
304                 prError = PR_CONNECT_REFUSED_ERROR;
305                 break;
306         case ECONNRESET:
307                 prError = PR_CONNECT_RESET_ERROR;
308                 break;
309         case EDEADLK:
310                 prError = PR_DEADLOCK_ERROR;
311                 break;
312 #ifdef EDIRCORRUPTED
313         case EDIRCORRUPTED:
314                 prError = PR_DIRECTORY_CORRUPTED_ERROR;
315                 break;
316 #endif
317 #ifdef EDQUOT
318         case EDQUOT:
319                 prError = PR_NO_DEVICE_SPACE_ERROR;
320                 break;
321 #endif
322         case EEXIST:
323                 prError = PR_FILE_EXISTS_ERROR;
324                 break;
325         case EFAULT:
326                 prError = PR_ACCESS_FAULT_ERROR;
327                 break;
328         case EFBIG:
329                 prError = PR_FILE_TOO_BIG_ERROR;
330                 break;
331         case EHOSTUNREACH:
332                 prError = PR_HOST_UNREACHABLE_ERROR;
333                 break;
334         case EINPROGRESS:
335                 prError = PR_IN_PROGRESS_ERROR;
336                 break;
337         case EINTR:
338                 prError = PR_PENDING_INTERRUPT_ERROR;
339                 break;
340         case EINVAL:
341                 prError = PR_INVALID_ARGUMENT_ERROR;
342                 break;
343         case EIO:
344                 prError = PR_IO_ERROR;
345                 break;
346         case EISCONN:
347                 prError = PR_IS_CONNECTED_ERROR;
348                 break;
349         case EISDIR:
350                 prError = PR_IS_DIRECTORY_ERROR;
351                 break;
352         case ELOOP:
353                 prError = PR_LOOP_ERROR;
354                 break;
355         case EMFILE:
356                 prError = PR_PROC_DESC_TABLE_FULL_ERROR;
357                 break;
358         case EMLINK:
359                 prError = PR_MAX_DIRECTORY_ENTRIES_ERROR;
360                 break;
361         case EMSGSIZE:
362                 prError = PR_INVALID_ARGUMENT_ERROR;
363                 break;
364 #ifdef EMULTIHOP
365         case EMULTIHOP:
366                 prError = PR_REMOTE_FILE_ERROR;
367                 break;
368 #endif
369         case ENAMETOOLONG:
370                 prError = PR_NAME_TOO_LONG_ERROR;
371                 break;
372         case ENETUNREACH:
373                 prError = PR_NETWORK_UNREACHABLE_ERROR;
374                 break;
375         case ENFILE:
376                 prError = PR_SYS_DESC_TABLE_FULL_ERROR;
377                 break;
378         /*
379          * On SCO OpenServer 5, ENOBUFS is defined as ENOSR.
380          */
381 #if defined(ENOBUFS) && (ENOBUFS != ENOSR)
382         case ENOBUFS:
383                 prError = PR_INSUFFICIENT_RESOURCES_ERROR;
384                 break;
385 #endif
386         case ENODEV:
387                 prError = PR_FILE_NOT_FOUND_ERROR;
388                 break;
389         case ENOENT:
390                 prError = PR_FILE_NOT_FOUND_ERROR;
391                 break;
392         case ENOLCK:
393                 prError = PR_FILE_IS_LOCKED_ERROR;
394                 break;
395 #ifdef ENOLINK 
396         case ENOLINK:
397                 prError = PR_REMOTE_FILE_ERROR;
398                 break;
399 #endif
400         case ENOMEM:
401                 prError = PR_OUT_OF_MEMORY_ERROR;
402                 break;
403         case ENOPROTOOPT:
404                 prError = PR_INVALID_ARGUMENT_ERROR;
405                 break;
406         case ENOSPC:
407                 prError = PR_NO_DEVICE_SPACE_ERROR;
408                 break;
409 #ifdef ENOSR
410         case ENOSR:
411                 prError = PR_INSUFFICIENT_RESOURCES_ERROR;
412                 break;
413 #endif
414         case ENOTCONN:
415                 prError = PR_NOT_CONNECTED_ERROR;
416                 break;
417         case ENOTDIR:
418                 prError = PR_NOT_DIRECTORY_ERROR;
419                 break;
420         case ENOTSOCK:
421                 prError = PR_NOT_SOCKET_ERROR;
422                 break;
423         case ENXIO:
424                 prError = PR_FILE_NOT_FOUND_ERROR;
425                 break;
426         case EOPNOTSUPP:
427                 prError = PR_NOT_TCP_SOCKET_ERROR;
428                 break;
429 #ifdef EOVERFLOW
430         case EOVERFLOW:
431                 prError = PR_BUFFER_OVERFLOW_ERROR;
432                 break;
433 #endif
434         case EPERM:
435                 prError = PR_NO_ACCESS_RIGHTS_ERROR;
436                 break;
437         case EPIPE:
438                 prError = PR_CONNECT_RESET_ERROR;
439                 break;
440 #ifdef EPROTO
441         case EPROTO:
442                 prError = PR_IO_ERROR;
443                 break;
444 #endif
445         case EPROTONOSUPPORT:
446                 prError = PR_PROTOCOL_NOT_SUPPORTED_ERROR;
447                 break;
448         case EPROTOTYPE:
449                 prError = PR_ADDRESS_NOT_SUPPORTED_ERROR;
450                 break;
451         case ERANGE:
452                 prError = PR_INVALID_METHOD_ERROR;
453                 break;
454         case EROFS:
455                 prError = PR_READ_ONLY_FILESYSTEM_ERROR;
456                 break;
457         case ESPIPE:
458                 prError = PR_INVALID_METHOD_ERROR;
459                 break;
460         case ETIMEDOUT:
461                 prError = PR_IO_TIMEOUT_ERROR;
462                 break;
463 #if EWOULDBLOCK != EAGAIN
464         case EWOULDBLOCK:
465                 prError = PR_WOULD_BLOCK_ERROR;
466                 break;
467 #endif
468         case EXDEV:
469                 prError = PR_NOT_SAME_DEVICE_ERROR;
470                 break;
471         default:
472                 prError = PR_UNKNOWN_ERROR;
473                 break;
474         }
475         PR_SetError( prError, err );
476 }
477
478 /*
479  * cipher_list is an integer array with the following values:
480  *   -1: never enable this cipher
481  *    0: cipher disabled
482  *    1: cipher enabled
483  */
484 static int
485 nss_parse_ciphers(const char *cipherstr, int cipher_list[ciphernum])
486 {
487         int i;
488         char *cipher;
489         char *ciphers;
490         char *ciphertip;
491         int action;
492         int rv;
493
494         /* All disabled to start */
495         for (i=0; i<ciphernum; i++)
496                 cipher_list[i] = 0;
497
498         ciphertip = strdup(cipherstr);
499         cipher = ciphers = ciphertip;
500
501         while (ciphers && (strlen(ciphers))) {
502                 while ((*cipher) && (isspace(*cipher)))
503                         ++cipher;
504
505                 action = 1;
506                 switch(*cipher) {
507                 case '+': /* Add something */
508                         action = 1;
509                         cipher++;
510                         break;
511                 case '-': /* Subtract something */
512                         action = 0;
513                         cipher++;
514                         break;
515                 case '!':  /* Disable something */
516                         action = -1;
517                         cipher++;
518                         break;
519                 default:
520                         /* do nothing */
521                         break;
522                 }
523
524                 if ((ciphers = strchr(cipher, ':'))) {
525                         *ciphers++ = '\0';
526                 }
527
528                 /* Do the easy one first */
529                 if (!strcmp(cipher, "ALL")) {
530                         for (i=0; i<ciphernum; i++) {
531                                 if (!(ciphers_def[i].attr & SSL_eNULL))
532                                         cipher_list[i] = action;
533                         }
534                 } else if (!strcmp(cipher, "COMPLEMENTOFALL")) {
535                         for (i=0; i<ciphernum; i++) {
536                                 if ((ciphers_def[i].attr & SSL_eNULL))
537                                         cipher_list[i] = action;
538                         }
539                 } else if (!strcmp(cipher, "DEFAULT")) {
540                         for (i=0; i<ciphernum; i++) {
541                                 cipher_list[i] = ciphers_def[i].enabled == SSL_ALLOWED ? 1 : 0;
542                         }
543                 } else {
544                         int mask = 0;
545                         int strength = 0;
546                         int protocol = 0;
547                         char *c;
548
549                         c = cipher;
550                         while (c && (strlen(c))) {
551
552                                 if ((c = strchr(cipher, '+'))) {
553                                         *c++ = '\0';
554                                 }
555
556                                 if (!strcmp(cipher, "RSA")) {
557                                         mask |= SSL_RSA;
558                                 } else if ((!strcmp(cipher, "NULL")) || (!strcmp(cipher, "eNULL"))) {
559                                         mask |= SSL_eNULL;
560                                 } else if (!strcmp(cipher, "AES")) {
561                                         mask |= SSL_AES;
562                                 } else if (!strcmp(cipher, "3DES")) {
563                                         mask |= SSL_3DES;
564                                 } else if (!strcmp(cipher, "DES")) {
565                                         mask |= SSL_DES;
566                                 } else if (!strcmp(cipher, "RC4")) {
567                                         mask |= SSL_RC4;
568                                 } else if (!strcmp(cipher, "RC2")) {
569                                         mask |= SSL_RC2;
570                                 } else if (!strcmp(cipher, "MD5")) {
571                                         mask |= SSL_MD5;
572                                 } else if ((!strcmp(cipher, "SHA")) || (!strcmp(cipher, "SHA1"))) {
573                                         mask |= SSL_SHA1;
574                                 } else if (!strcmp(cipher, "SSLv2")) {
575                                         protocol |= SSL2;
576                                 } else if (!strcmp(cipher, "SSLv3")) {
577                                         protocol |= SSL3;
578                                 } else if (!strcmp(cipher, "TLSv1")) {
579                                         protocol |= TLS1;
580                                 } else if (!strcmp(cipher, "HIGH")) {
581                                         strength |= SSL_HIGH;
582                                 } else if (!strcmp(cipher, "MEDIUM")) {
583                                         strength |= SSL_MEDIUM;
584                                 } else if (!strcmp(cipher, "LOW")) {
585                                         strength |= SSL_LOW;
586                                 } else if ((!strcmp(cipher, "EXPORT")) || (!strcmp(cipher, "EXP"))) {
587                                         strength |= SSL_EXPORT40|SSL_EXPORT56;
588                                 } else if (!strcmp(cipher, "EXPORT40")) {
589                                         strength |= SSL_EXPORT40;
590                                 } else if (!strcmp(cipher, "EXPORT56")) {
591                                         strength |= SSL_EXPORT56;
592                                 }
593
594                                 if (c)
595                                         cipher = c;
596
597                         } /* while */
598
599                         /* If we have a mask, apply it. If not then perhaps they provided
600                          * a specific cipher to enable.
601                          */
602                         if (mask || strength || protocol) {
603                                 for (i=0; i<ciphernum; i++) {
604                                         if (((ciphers_def[i].attr & mask) ||
605                                                  (ciphers_def[i].strength & strength) ||
606                                                  (ciphers_def[i].version & protocol)) &&
607                                                 (cipher_list[i] != -1)) {
608                                                 /* Enable the NULL ciphers only if explicity
609                                                  * requested */
610                                                 if (ciphers_def[i].attr & SSL_eNULL) {
611                                                         if (mask & SSL_eNULL)
612                                                                 cipher_list[i] = action;
613                                                 } else
614                                                         cipher_list[i] = action;
615                                         }
616                                 }
617                         } else {
618                                 for (i=0; i<ciphernum; i++) {
619                                         if (!strcmp(ciphers_def[i].ossl_name, cipher) &&
620                                                 cipher_list[1] != -1)
621                                                 cipher_list[i] = action;
622                                 }
623                         }
624                 }
625
626                 if (ciphers)
627                         cipher = ciphers;
628         }
629
630         /* See if any ciphers were enabled */
631         rv = 0;
632         for (i=0; i<ciphernum; i++) {
633                 if (cipher_list[i] == 1)
634                         rv = 1;
635         }
636
637         free(ciphertip);
638
639         return rv;
640 }
641
642 static int
643 tlsm_parse_ciphers(tlsm_ctx *ctx, const char *str)
644 {
645         int cipher_state[ciphernum];
646         int rv, i;
647
648         if (!ctx)
649                 return 0;
650
651         rv = nss_parse_ciphers(str, cipher_state);
652
653         if (rv) {
654                 /* First disable everything */
655                 for (i = 0; i < SSL_NumImplementedCiphers; i++)
656                         SSL_CipherPrefSet(ctx->tc_model, SSL_ImplementedCiphers[i], SSL_NOT_ALLOWED);
657
658                 /* Now enable what was requested */
659                 for (i=0; i<ciphernum; i++) {
660                         SSLCipherSuiteInfo suite;
661                         PRBool enabled;
662
663                         if (SSL_GetCipherSuiteInfo(ciphers_def[i].num, &suite, sizeof suite)
664                                 == SECSuccess) {
665                                 enabled = cipher_state[i] < 0 ? 0 : cipher_state[i];
666                                 if (enabled == SSL_ALLOWED) {
667                                         if (PK11_IsFIPS() && !suite.isFIPS)    
668                                                 enabled = SSL_NOT_ALLOWED;
669                                 }
670                                 SSL_CipherPrefSet(ctx->tc_model, ciphers_def[i].num, enabled);
671                         }
672                 }
673         }
674
675         return rv == 1 ? 0 : -1;
676 }
677
678 static SECStatus
679 tlsm_bad_cert_handler(void *arg, PRFileDesc *ssl)
680 {
681         SECStatus success = SECSuccess;
682         PRErrorCode err;
683         tlsm_ctx *ctx = (tlsm_ctx *)arg;
684
685         if (!ssl || !ctx) {
686                 return SECFailure;
687         }
688
689         err = PORT_GetError();
690
691         switch (err) {
692         case SEC_ERROR_UNTRUSTED_ISSUER:
693         case SEC_ERROR_UNKNOWN_ISSUER:
694         case SEC_ERROR_EXPIRED_CERTIFICATE:
695         case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
696                 if (ctx->tc_verify_cert) {
697                         success = SECFailure;
698                 }
699                 break;
700         /* we bypass NSS's hostname checks and do our own */
701         case SSL_ERROR_BAD_CERT_DOMAIN:
702                 break;
703         default:
704                 success = SECFailure;
705                 break;
706         }
707
708         return success;
709 }
710
711 static const char *
712 tlsm_dump_security_status(PRFileDesc *fd)
713 {
714         char * cp;      /* bulk cipher name */
715         char * ip;      /* cert issuer DN */
716         char * sp;      /* cert subject DN */
717         int    op;      /* High, Low, Off */
718         int    kp0;     /* total key bits */
719         int    kp1;     /* secret key bits */
720         SSL3Statistics * ssl3stats = SSL_GetStatistics();
721
722         SSL_SecurityStatus( fd, &op, &cp, &kp0, &kp1, &ip, &sp );
723         Debug( LDAP_DEBUG_TRACE,
724                    "TLS certificate verification: subject: %s, issuer: %s, cipher: %s, ",
725                    sp ? sp : "-unknown-", ip ? ip : "-unknown-", cp ? cp : "-unknown-" );
726         PR_Free(cp);
727         PR_Free(ip);
728         PR_Free(sp);
729         Debug( LDAP_DEBUG_TRACE,
730                    "security level: %s, secret key bits: %d, total key bits: %d, ",
731                    ((op == SSL_SECURITY_STATUS_ON_HIGH) ? "high" :
732                         ((op == SSL_SECURITY_STATUS_ON_LOW) ? "low" : "off")),
733                    kp1, kp0 );
734
735         Debug( LDAP_DEBUG_TRACE,
736                    "cache hits: %ld, cache misses: %ld, cache not reusable: %ld\n",
737                    ssl3stats->hch_sid_cache_hits, ssl3stats->hch_sid_cache_misses,
738                    ssl3stats->hch_sid_cache_not_ok );
739
740         return "";
741 }
742
743 static void
744 tlsm_handshake_complete_cb( PRFileDesc *fd, void *client_data )
745 {
746         tlsm_dump_security_status( fd );
747 }
748
749 #ifdef READ_PASSWORD_FROM_FILE
750 static char *
751 tlsm_get_pin_from_file(const char *token_name, tlsm_ctx *ctx)
752 {
753         char *pwdstr = NULL;
754         char *contents = NULL;
755         char *lasts = NULL;
756         char *line = NULL;
757         char *candidate = NULL;
758         PRFileInfo file_info;
759         PRFileDesc *pwd_fileptr = PR_Open( ctx->tc_pin_file, PR_RDONLY, 00400 );
760
761         /* open the password file */
762         if ( !pwd_fileptr ) {
763                 PRErrorCode errcode = PR_GetError();
764                 Debug( LDAP_DEBUG_ANY,
765                        "TLS: could not open security pin file %s - error %d:%s.\n",
766                        ctx->tc_pin_file, errcode,
767                        PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
768                 goto done;
769         }
770
771         /* get the file size */
772         if ( PR_SUCCESS != PR_GetFileInfo( ctx->tc_pin_file, &file_info ) ) {
773                 PRErrorCode errcode = PR_GetError();
774                 Debug( LDAP_DEBUG_ANY,
775                        "TLS: could not get file info from pin file %s - error %d:%s.\n",
776                        ctx->tc_pin_file, errcode,
777                        PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
778                 goto done;
779         }
780
781         /* create a buffer to hold the file contents */
782         if ( !( contents = PR_MALLOC( file_info.size + 1 ) ) ) {
783                 PRErrorCode errcode = PR_GetError();
784                 Debug( LDAP_DEBUG_ANY,
785                        "TLS: could not alloc a buffer for contents of pin file %s - error %d:%s.\n",
786                        ctx->tc_pin_file, errcode,
787                        PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
788                 goto done;
789         }
790
791         /* read file into the buffer */
792         if( PR_Read( pwd_fileptr, contents, file_info.size ) <= 0 ) {
793                 PRErrorCode errcode = PR_GetError();
794                 Debug( LDAP_DEBUG_ANY,
795                        "TLS: could not read the file contents from pin file %s - error %d:%s.\n",
796                        ctx->tc_pin_file, errcode,
797                        PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
798                 goto done;
799         }
800
801         /* format is [tokenname:]password EOL [tokenname:]password EOL ... */
802         /* if you want to use a password containing a colon character, use
803            the special tokenname "default" */
804         for ( line = PL_strtok_r( contents, "\r\n", &lasts ); line;
805               line = PL_strtok_r( NULL, "\r\n", &lasts ) ) {
806                 char *colon;
807
808                 if ( !*line ) {
809                         continue; /* skip blank lines */
810                 }
811                 colon = PL_strchr( line, ':' );
812                 if ( colon ) {
813                         if ( *(colon + 1) && token_name &&
814                              !PL_strncmp( token_name, line, colon-line ) ) {
815                                 candidate = colon + 1; /* found a definite match */
816                                 break;
817                         } else if ( !PL_strncmp( DEFAULT_TOKEN_NAME, line, colon-line ) ) {
818                                 candidate = colon + 1; /* found possible match */
819                         }
820                 } else { /* no token name */
821                         candidate = line;
822                 }
823         }
824 done:
825         if ( pwd_fileptr ) {
826                 PR_Close( pwd_fileptr );
827         }
828         if ( candidate ) {
829                 pwdstr = PL_strdup( candidate );
830         }
831         PL_strfree( contents );
832
833         return pwdstr;
834 }
835 #endif /* READ_PASSWORD_FROM_FILE */
836
837 #ifdef READ_PASSWORD_FROM_STDIN
838 /*
839  * Turn the echoing off on a tty.
840  */
841 static void
842 echoOff(int fd)
843 {
844         if ( isatty( fd ) ) {
845                 struct termios tio;
846                 tcgetattr( fd, &tio );
847                 tio.c_lflag &= ~ECHO;
848                 tcsetattr( fd, TCSAFLUSH, &tio );
849         }
850 }
851
852 /*
853  * Turn the echoing on on a tty.
854  */
855 static void
856 echoOn(int fd)
857 {
858         if ( isatty( fd ) ) {
859                 struct termios tio;
860                 tcgetattr( fd, &tio );
861                 tio.c_lflag |= ECHO;
862                 tcsetattr( fd, TCSAFLUSH, &tio );
863                 tcsetattr( fd, TCSAFLUSH, &tio );
864         }
865 }
866 #endif /* READ_PASSWORD_FROM_STDIN */
867
868 /*
869  * This does the actual work of reading the pin/password/pass phrase
870  */
871 static char *
872 tlsm_get_pin(PK11SlotInfo *slot, PRBool retry, tlsm_ctx *ctx)
873 {
874         char *token_name = NULL;
875         char *pwdstr = NULL;
876
877         token_name = PK11_GetTokenName( slot );
878 #ifdef READ_PASSWORD_FROM_FILE
879         /* Try to get the passwords from the password file if it exists.
880          * THIS IS UNSAFE and is provided for convenience only. Without this
881          * capability the server would have to be started in foreground mode
882          * if using an encrypted key.
883          */
884         if ( ctx->tc_pin_file ) {
885                 pwdstr = tlsm_get_pin_from_file( token_name, ctx );
886         }
887 #endif /* RETRIEVE_PASSWORD_FROM_FILE */
888 #ifdef READ_PASSWORD_FROM_STDIN
889         if ( !pwdstr ) {
890                 int infd = PR_FileDesc2NativeHandle( PR_STDIN );
891                 int isTTY = isatty( infd );
892                 unsigned char phrase[200];
893                 /* Prompt for password */
894                 if ( isTTY ) {
895                         fprintf( stdout,
896                                  "Please enter pin, password, or pass phrase for security token '%s': ",
897                                  token_name ? token_name : DEFAULT_TOKEN_NAME );
898                         echoOff( infd );
899                 }
900                 fgets( (char*)phrase, sizeof(phrase), stdin );
901                 if ( isTTY ) {
902                         fprintf( stdout, "\n" );
903                         echoOn( infd );
904                 }
905                 /* stomp on newline */
906                 phrase[strlen((char*)phrase)-1] = 0;
907
908                 pwdstr = PL_strdup( (char*)phrase );
909         }
910
911 #endif /* READ_PASSWORD_FROM_STDIN */
912         return pwdstr;
913 }
914
915 /*
916  * PKCS11 devices (including the internal softokn cert/key database)
917  * may be protected by a pin or password or even pass phrase
918  * MozNSS needs a way for the user to provide that
919  */
920 static char *
921 tlsm_pin_prompt(PK11SlotInfo *slot, PRBool retry, void *arg)
922 {
923         tlsm_ctx *ctx = (tlsm_ctx *)arg;
924
925         return tlsm_get_pin( slot, retry, ctx );
926 }
927
928 static SECStatus
929 tlsm_get_basic_constraint_extension( CERTCertificate *cert,
930                                                                          CERTBasicConstraints *cbcval )
931 {
932         SECItem encodedVal = { 0, NULL };
933         SECStatus rc;
934
935         rc = CERT_FindCertExtension( cert, SEC_OID_X509_BASIC_CONSTRAINTS,
936                                                                  &encodedVal);
937         if ( rc != SECSuccess ) {
938                 return rc;
939         }
940
941         rc = CERT_DecodeBasicConstraintValue( cbcval, &encodedVal );
942
943         /* free the raw extension data */
944         PORT_Free( encodedVal.data );
945
946         return rc;
947 }
948
949 static PRBool
950 tlsm_cert_is_self_issued( CERTCertificate *cert )
951 {
952         /* A cert is self-issued if its subject and issuer are equal and
953          * both are of non-zero length. 
954          */
955         PRBool is_self_issued = cert &&
956                 (PRBool)SECITEM_ItemsAreEqual( &cert->derIssuer, 
957                                                                            &cert->derSubject ) &&
958                 cert->derSubject.len > 0;
959         return is_self_issued;
960 }
961
962 static SECStatus
963 tlsm_verify_cert(CERTCertDBHandle *handle, CERTCertificate *cert, void *pinarg,
964                                  PRBool checksig, SECCertificateUsage certUsage, int errorToIgnore )
965 {
966         CERTVerifyLog verifylog;
967         SECStatus ret = SECSuccess;
968         const char *name;
969         int debug_level = LDAP_DEBUG_ANY;
970
971         if ( errorToIgnore == -1 ) {
972                 debug_level = LDAP_DEBUG_TRACE;
973         }
974
975         /* the log captures information about every cert in the chain, so we can tell
976            which cert caused the problem and what the problem was */
977         memset( &verifylog, 0, sizeof( verifylog ) );
978         verifylog.arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE );
979         if ( verifylog.arena == NULL ) {
980                 Debug( LDAP_DEBUG_ANY,
981                            "TLS certificate verification: Out of memory for certificate verification logger\n",
982                            0, 0, 0 );
983                 return SECFailure;
984         }
985         ret = CERT_VerifyCertificate( handle, cert, checksig, certUsage, PR_Now(), pinarg, &verifylog,
986                                                                   NULL );
987         if ( ( name = cert->subjectName ) == NULL ) {
988                 name = cert->nickname;
989         }
990         if ( verifylog.head == NULL ) {
991                 /* it is possible for CERT_VerifyCertificate return with an error with no logging */
992                 if ( ret != SECSuccess ) {
993                         PRErrorCode errcode = PR_GetError();
994                         Debug( debug_level,
995                                    "TLS: certificate [%s] is not valid - error %d:%s.\n",
996                                    name ? name : "(unknown)",
997                                    errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
998                 }
999         } else {
1000                 const char *name;
1001                 CERTVerifyLogNode *node;
1002
1003                 ret = SECSuccess; /* reset */
1004                 node = verifylog.head;
1005                 while ( node ) {
1006                         if ( ( name = node->cert->subjectName ) == NULL ) {
1007                                 name = node->cert->nickname;
1008                         }
1009                         if ( node->error ) {
1010                                 /* NSS does not like CA certs that have the basic constraints extension
1011                                    with the CA flag set to FALSE - openssl doesn't check if the cert
1012                                    is self issued */
1013                                 if ( ( node->error == SEC_ERROR_CA_CERT_INVALID ) &&
1014                                          tlsm_cert_is_self_issued( node->cert ) ) {
1015                                         CERTBasicConstraints basicConstraint;
1016                                         SECStatus rv = tlsm_get_basic_constraint_extension( node->cert, &basicConstraint );
1017                                         if ( ( rv == SECSuccess ) && ( basicConstraint.isCA == PR_FALSE ) ) {
1018                                                 Debug( LDAP_DEBUG_TRACE,
1019                                                            "TLS: certificate [%s] is not correct because it is a CA cert and the "
1020                                                            "BasicConstraint CA flag is set to FALSE - allowing for now, but "
1021                                                            "please fix your certs if possible\n", name, 0, 0 );
1022                                         } else { /* does not have basicconstraint, or some other error */
1023                                                 ret = SECFailure;
1024                                                 Debug( debug_level,
1025                                                            "TLS: certificate [%s] is not valid - CA cert is not valid\n",
1026                                                            name, 0, 0 );
1027                                         }
1028                                 } else if ( errorToIgnore && ( node->error == errorToIgnore ) ) {
1029                                         Debug( debug_level,
1030                                                    "TLS: Warning: ignoring error for certificate [%s] - error %ld:%s.\n",
1031                                                    name, node->error, PR_ErrorToString( node->error, PR_LANGUAGE_I_DEFAULT ) );
1032                                 } else {
1033                                         ret = SECFailure;
1034                                         Debug( debug_level,
1035                                                    "TLS: certificate [%s] is not valid - error %ld:%s.\n",
1036                                                    name, node->error, PR_ErrorToString( node->error, PR_LANGUAGE_I_DEFAULT ) );
1037                                 }
1038                         }
1039                         CERT_DestroyCertificate( node->cert );
1040                         node = node->next;
1041                 }
1042         }
1043
1044         PORT_FreeArena( verifylog.arena, PR_FALSE );
1045
1046         if ( ret == SECSuccess ) {
1047                 Debug( LDAP_DEBUG_TRACE,
1048                            "TLS: certificate [%s] is valid\n", name, 0, 0 );
1049         } else if ( errorToIgnore == -1 ) {
1050                 ret = SECSuccess;
1051         }
1052
1053         return ret;
1054 }
1055
1056 static SECStatus
1057 tlsm_auth_cert_handler(void *arg, PRFileDesc *fd,
1058                        PRBool checksig, PRBool isServer)
1059 {
1060         SECCertificateUsage certUsage = isServer ? certificateUsageSSLClient : certificateUsageSSLServer;
1061         SECStatus ret = SECSuccess;
1062         CERTCertificate *peercert = SSL_PeerCertificate( fd );
1063         int errorToIgnore = 0;
1064         tlsm_ctx *ctx = (tlsm_ctx *)arg;
1065
1066         if (ctx && ctx->tc_warn_only )
1067                 errorToIgnore = -1;
1068
1069         ret = tlsm_verify_cert( ctx->tc_certdb, peercert,
1070                                                         SSL_RevealPinArg( fd ),
1071                                                         checksig, certUsage, errorToIgnore );
1072         CERT_DestroyCertificate( peercert );
1073
1074         return ret;
1075 }
1076
1077 static int
1078 tlsm_authenticate_to_slot( tlsm_ctx *ctx, PK11SlotInfo *slot )
1079 {
1080         int rc = -1;
1081
1082         if ( SECSuccess != PK11_Authenticate( slot, PR_FALSE, ctx ) ) {
1083                 char *token_name = PK11_GetTokenName( slot );
1084                 PRErrorCode errcode = PR_GetError();
1085                 Debug( LDAP_DEBUG_ANY,
1086                            "TLS: could not authenticate to the security token %s - error %d:%s.\n",
1087                            token_name ? token_name : DEFAULT_TOKEN_NAME, errcode,
1088                            PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1089         } else {
1090                 rc = 0; /* success */
1091         }
1092
1093         return rc;
1094 }
1095
1096 static SECStatus
1097 tlsm_nss_shutdown_cb( void *appData, void *nssData )
1098 {
1099         SECStatus rc = SECSuccess;
1100
1101         SSL_ShutdownServerSessionIDCache();
1102
1103         if ( pem_module ) {
1104                 SECMOD_UnloadUserModule( pem_module );
1105                 SECMOD_DestroyModule( pem_module );
1106                 pem_module = NULL;
1107         }
1108         return rc;
1109 }
1110
1111 static PRCallOnceType tlsm_register_shutdown_callonce = {0,0};
1112 static PRStatus PR_CALLBACK
1113 tlsm_register_nss_shutdown_cb( void )
1114 {
1115         if ( SECSuccess == NSS_RegisterShutdown( tlsm_nss_shutdown_cb,
1116                                                                                          NULL ) ) {
1117                 return PR_SUCCESS;
1118         }
1119         return PR_FAILURE;
1120 }
1121
1122 static PRStatus
1123 tlsm_register_nss_shutdown( void )
1124 {
1125         return PR_CallOnce( &tlsm_register_shutdown_callonce,
1126                                                 tlsm_register_nss_shutdown_cb );
1127 }
1128
1129 static int
1130 tlsm_init_pem_module( void )
1131 {
1132         int rc = 0;
1133         char *fullname = NULL;
1134         char *configstring = NULL;
1135
1136         if ( pem_module ) {
1137                 return rc;
1138         }
1139
1140         /* not loaded - load it */
1141         /* get the system dependent library name */
1142         fullname = PR_GetLibraryName( NULL, PEM_LIBRARY );
1143         /* Load our PKCS#11 module */
1144         configstring = PR_smprintf( "library=%s name=" PEM_MODULE " parameters=\"\"", fullname );
1145         PL_strfree( fullname );
1146
1147         pem_module = SECMOD_LoadUserModule( configstring, NULL, PR_FALSE );
1148         PR_smprintf_free( configstring );
1149
1150         if ( !pem_module || !pem_module->loaded ) {
1151                 if ( pem_module ) {
1152                         SECMOD_DestroyModule( pem_module );
1153                         pem_module = NULL;
1154                 }
1155                 rc = -1;
1156         }
1157
1158         return rc;
1159 }
1160
1161 static void
1162 tlsm_add_pem_obj( tlsm_ctx *ctx, PK11GenericObject *obj )
1163 {
1164         int idx = ctx->tc_n_pem_objs;
1165         ctx->tc_n_pem_objs++;
1166         ctx->tc_pem_objs = (PK11GenericObject **)
1167                 PORT_Realloc( ctx->tc_pem_objs, ctx->tc_n_pem_objs * sizeof( PK11GenericObject * ) );
1168         ctx->tc_pem_objs[idx] = obj;                                                                                                              
1169 }
1170
1171 static void
1172 tlsm_free_pem_objs( tlsm_ctx *ctx )
1173 {
1174         /* free in reverse order of allocation */
1175         while ( ctx->tc_n_pem_objs-- ) {
1176                 PK11_DestroyGenericObject( ctx->tc_pem_objs[ctx->tc_n_pem_objs] );
1177                 ctx->tc_pem_objs[ctx->tc_n_pem_objs] = NULL;
1178         }
1179         PORT_Free(ctx->tc_pem_objs);
1180         ctx->tc_pem_objs = NULL;
1181         ctx->tc_n_pem_objs = 0;
1182 }
1183
1184 static int
1185 tlsm_add_cert_from_file( tlsm_ctx *ctx, const char *filename, PRBool isca, PRBool istrusted )
1186 {
1187         CK_SLOT_ID slotID;
1188         PK11SlotInfo *slot = NULL;
1189         PK11GenericObject *rv;
1190         CK_ATTRIBUTE *attrs;
1191         CK_ATTRIBUTE theTemplate[20];
1192         CK_BBOOL cktrue = CK_TRUE;
1193         CK_BBOOL ckfalse = CK_FALSE;
1194         CK_OBJECT_CLASS objClass = CKO_CERTIFICATE;
1195         char tmpslotname[64];
1196         char *slotname = NULL;
1197         const char *ptr = NULL;
1198         char sep = PR_GetDirectorySeparator();
1199         PRFileInfo fi;
1200         PRStatus status;
1201
1202         memset( &fi, 0, sizeof(fi) );
1203         status = PR_GetFileInfo( filename, &fi );
1204         if ( PR_SUCCESS != status) {
1205                 PRErrorCode errcode = PR_GetError();
1206                 Debug( LDAP_DEBUG_ANY,
1207                            "TLS: could not read certificate file %s - error %d:%s.\n",
1208                            filename, errcode,
1209                            PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1210                 return -1;
1211         }
1212
1213         if ( fi.type != PR_FILE_FILE ) {
1214                 PR_SetError(PR_IS_DIRECTORY_ERROR, 0);
1215                 Debug( LDAP_DEBUG_ANY,
1216                            "TLS: error: the certificate file %s is not a file.\n",
1217                            filename, 0 ,0 );
1218                 return -1;
1219         }
1220
1221         attrs = theTemplate;
1222
1223         if ( isca ) {
1224                 slotID = 0; /* CA and trust objects use slot 0 */
1225                 PR_snprintf( tmpslotname, sizeof(tmpslotname), TLSM_PEM_TOKEN_FMT, slotID );
1226                 slotname = tmpslotname;
1227                 istrusted = PR_TRUE;
1228         } else {
1229                 if ( ctx->tc_slotname == NULL ) { /* need new slot */
1230                         if ( istrusted ) {
1231                                 slotID = 0;
1232                         } else {
1233                                 slotID = ++tlsm_slot_count;
1234                         }
1235                         ctx->tc_slotname = PR_smprintf( TLSM_PEM_TOKEN_FMT, slotID );
1236                 }
1237                 slotname = ctx->tc_slotname;
1238
1239                 if ( ( ptr = PL_strrchr( filename, sep ) ) ) {
1240                         PL_strfree( ctx->tc_certname );
1241                         ++ptr;
1242                         if ( istrusted ) {
1243                                 /* pemnss conflates trusted certs with CA certs - since there can
1244                                    be more than one CA cert in a file (e.g. ca-bundle.crt) pemnss
1245                                    numbers each trusted cert - in the case of a server cert, there will be
1246                                    only one, so it will be number 0 */
1247                                 ctx->tc_certname = PR_smprintf( "%s:%s - 0", slotname, ptr );
1248                         } else {
1249                                 ctx->tc_certname = PR_smprintf( "%s:%s", slotname, ptr );
1250                         }
1251                 }
1252         }
1253
1254         slot = PK11_FindSlotByName( slotname );
1255
1256         if ( !slot ) {
1257                 PRErrorCode errcode = PR_GetError();
1258                 Debug( LDAP_DEBUG_ANY,
1259                            "TLS: could not find the slot for certificate %s - error %d:%s.\n",
1260                            ctx->tc_certname, errcode,
1261                            PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1262                 return -1;
1263         }
1264
1265         PK11_SETATTRS( attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++;
1266         PK11_SETATTRS( attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++;
1267         PK11_SETATTRS( attrs, CKA_LABEL, (unsigned char *)filename, strlen(filename)+1 ); attrs++;
1268         if ( istrusted ) {
1269                 PK11_SETATTRS( attrs, CKA_TRUST, &cktrue, sizeof(CK_BBOOL) ); attrs++;
1270         } else {
1271                 PK11_SETATTRS( attrs, CKA_TRUST, &ckfalse, sizeof(CK_BBOOL) ); attrs++;
1272         }
1273         /* This loads the certificate in our PEM module into the appropriate
1274          * slot.
1275          */
1276         rv = PK11_CreateGenericObject( slot, theTemplate, 4, PR_FALSE /* isPerm */ );
1277
1278         PK11_FreeSlot( slot );
1279
1280         if ( !rv ) {
1281                 PRErrorCode errcode = PR_GetError();
1282                 Debug( LDAP_DEBUG_ANY,
1283                            "TLS: could not add the certificate %s - error %d:%s.\n",
1284                            ctx->tc_certname, errcode,
1285                            PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1286                 return -1;
1287         }
1288
1289         tlsm_add_pem_obj( ctx, rv );
1290
1291         return 0;
1292 }
1293
1294 static int
1295 tlsm_add_key_from_file( tlsm_ctx *ctx, const char *filename )
1296 {
1297         CK_SLOT_ID slotID;
1298         PK11SlotInfo * slot = NULL;
1299         PK11GenericObject *rv;
1300         CK_ATTRIBUTE *attrs;
1301         CK_ATTRIBUTE theTemplate[20];
1302         CK_BBOOL cktrue = CK_TRUE;
1303         CK_OBJECT_CLASS objClass = CKO_PRIVATE_KEY;
1304         int retcode = 0;
1305         PRFileInfo fi;
1306         PRStatus status;
1307
1308         memset( &fi, 0, sizeof(fi) );
1309         status = PR_GetFileInfo( filename, &fi );
1310         if ( PR_SUCCESS != status) {
1311                 PRErrorCode errcode = PR_GetError();
1312                 Debug( LDAP_DEBUG_ANY,
1313                            "TLS: could not read key file %s - error %d:%s.\n",
1314                            filename, errcode,
1315                            PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1316                 return -1;
1317         }
1318
1319         if ( fi.type != PR_FILE_FILE ) {
1320                 PR_SetError(PR_IS_DIRECTORY_ERROR, 0);
1321                 Debug( LDAP_DEBUG_ANY,
1322                            "TLS: error: the key file %s is not a file.\n",
1323                            filename, 0 ,0 );
1324                 return -1;
1325         }
1326
1327         attrs = theTemplate;
1328
1329         if ( ctx->tc_slotname == NULL ) { /* need new slot */
1330                 slotID = ++tlsm_slot_count;
1331                 ctx->tc_slotname = PR_smprintf( TLSM_PEM_TOKEN_FMT, slotID );
1332         }
1333         slot = PK11_FindSlotByName( ctx->tc_slotname );
1334
1335         if ( !slot ) {
1336                 PRErrorCode errcode = PR_GetError();
1337                 Debug( LDAP_DEBUG_ANY,
1338                            "TLS: could not find the slot %s for the private key - error %d:%s.\n",
1339                            ctx->tc_slotname, errcode,
1340                            PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1341                 return -1;
1342         }
1343
1344         PK11_SETATTRS( attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++;
1345         PK11_SETATTRS( attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++;
1346         PK11_SETATTRS( attrs, CKA_LABEL, (unsigned char *)filename, strlen(filename)+1 ); attrs++;
1347         rv = PK11_CreateGenericObject( slot, theTemplate, 3, PR_FALSE /* isPerm */ );
1348
1349         if ( !rv ) {
1350                 PRErrorCode errcode = PR_GetError();
1351                 Debug( LDAP_DEBUG_ANY,
1352                            "TLS: could not add the certificate %s - error %d:%s.\n",
1353                            ctx->tc_certname, errcode,
1354                            PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1355                 retcode = -1;
1356         } else {
1357                 /* When adding an encrypted key the PKCS#11 will be set as removed */
1358                 /* This will force the token to be seen as re-inserted */
1359                 SECMOD_WaitForAnyTokenEvent( pem_module, 0, 0 );
1360                 PK11_IsPresent( slot );
1361                 retcode = 0;
1362         }
1363
1364         PK11_FreeSlot( slot );
1365
1366         if ( !retcode ) {
1367                 tlsm_add_pem_obj( ctx, rv );
1368         }
1369         return retcode;
1370 }
1371
1372 static int
1373 tlsm_init_ca_certs( tlsm_ctx *ctx, const char *cacertfile, const char *cacertdir )
1374 {
1375         PRBool isca = PR_TRUE;
1376         PRStatus status = PR_SUCCESS;
1377         PRErrorCode errcode = PR_SUCCESS;
1378
1379         if ( !cacertfile && !cacertdir ) {
1380                 /* no checking - not good, but allowed */
1381                 return 0;
1382         }
1383
1384         if ( cacertfile ) {
1385                 int rc = tlsm_add_cert_from_file( ctx, cacertfile, isca, PR_TRUE );
1386                 if ( rc ) {
1387                         errcode = PR_GetError();
1388                         Debug( LDAP_DEBUG_ANY,
1389                                    "TLS: %s is not a valid CA certificate file - error %d:%s.\n",
1390                                    cacertfile, errcode,
1391                                    PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1392                         /* failure with cacertfile is a hard failure even if cacertdir is
1393                            also specified and contains valid CA cert files */
1394                         status = PR_FAILURE;
1395                 } else {
1396                         Debug( LDAP_DEBUG_TRACE,
1397                                    "TLS: loaded CA certificate file %s.\n",
1398                                    cacertfile, 0, 0 );
1399                 }
1400         }
1401
1402         /* if cacertfile above failed, we will return failure, even
1403            if there is a valid CA cert in cacertdir - but we still
1404            process cacertdir in case the user has enabled trace level
1405            debugging so they can see the processing for cacertdir too */
1406         /* any cacertdir failures are "soft" failures - if the user specifies
1407            no cert checking, then we allow the tls/ssl to continue, no matter
1408            what was specified for cacertdir, or the contents of the directory
1409            - this is different behavior than that of cacertfile */
1410         if ( cacertdir ) {
1411                 PRFileInfo fi;
1412                 PRDir *dir;
1413                 PRDirEntry *entry;
1414                 PRStatus fistatus = PR_FAILURE;
1415
1416                 memset( &fi, 0, sizeof(fi) );
1417                 fistatus = PR_GetFileInfo( cacertdir, &fi );
1418                 if ( PR_SUCCESS != fistatus) {
1419                         errcode = PR_GetError();
1420                         Debug( LDAP_DEBUG_ANY,
1421                                    "TLS: could not get info about the CA certificate directory %s - error %d:%s.\n",
1422                                    cacertdir, errcode,
1423                                    PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1424                         goto done;
1425                 }
1426
1427                 if ( fi.type != PR_FILE_DIRECTORY ) {
1428                         Debug( LDAP_DEBUG_ANY,
1429                                    "TLS: error: the CA certificate directory %s is not a directory.\n",
1430                                    cacertdir, 0 ,0 );
1431                         goto done;
1432                 }
1433
1434                 dir = PR_OpenDir( cacertdir );
1435                 if ( NULL == dir ) {
1436                         errcode = PR_GetError();
1437                         Debug( LDAP_DEBUG_ANY,
1438                                    "TLS: could not open the CA certificate directory %s - error %d:%s.\n",
1439                                    cacertdir, errcode,
1440                                    PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1441                         goto done;
1442                 }
1443
1444                 do {
1445                         entry = PR_ReadDir( dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN );
1446                         if ( ( NULL != entry ) && ( NULL != entry->name ) ) {
1447                                 char *fullpath = NULL;
1448                                 char *ptr;
1449
1450                                 ptr = PL_strrstr( entry->name, PEM_CA_HASH_FILE_SUFFIX );
1451                                 if ( ( ptr == NULL ) || ( *(ptr + PEM_CA_HASH_FILE_SUFFIX_LEN) != '\0' ) ) {
1452                                         Debug( LDAP_DEBUG_TRACE,
1453                                                    "TLS: file %s does not end in [%s] - does not appear to be a CA certificate "
1454                                                    "directory file with a properly hashed file name - skipping.\n",
1455                                                    entry->name, PEM_CA_HASH_FILE_SUFFIX, 0 );
1456                                         continue;
1457                                 }
1458                                 fullpath = PR_smprintf( "%s/%s", cacertdir, entry->name );
1459                                 if ( !tlsm_add_cert_from_file( ctx, fullpath, isca, PR_TRUE ) ) {
1460                                         Debug( LDAP_DEBUG_TRACE,
1461                                                    "TLS: loaded CA certificate file %s from CA certificate directory %s.\n",
1462                                                    fullpath, cacertdir, 0 );
1463                                 } else {
1464                                         errcode = PR_GetError();
1465                                         Debug( LDAP_DEBUG_TRACE,
1466                                                    "TLS: %s is not a valid CA certificate file - error %d:%s.\n",
1467                                                    fullpath, errcode,
1468                                                    PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1469                                 }
1470                                 PR_smprintf_free( fullpath );
1471                         }
1472                 } while ( NULL != entry );
1473                 PR_CloseDir( dir );
1474         }
1475 done:
1476         if ( status != PR_SUCCESS ) {
1477                 return -1;
1478         }
1479
1480         return 0;
1481 }
1482
1483 /*
1484  * NSS supports having multiple cert/key databases in the same
1485  * directory, each one having a unique string prefix e.g.
1486  * slapd-01-cert8.db - the prefix here is "slapd-01-"
1487  * this function examines the given certdir - if it looks like
1488  * /path/to/directory/prefix it will return the
1489  * /path/to/directory part in realcertdir, and the prefix in prefix
1490  */
1491 static void
1492 tlsm_get_certdb_prefix( const char *certdir, char **realcertdir, char **prefix )
1493 {
1494         char sep = PR_GetDirectorySeparator();
1495         char *ptr = NULL;
1496         struct PRFileInfo prfi;
1497         PRStatus prc;
1498
1499         *realcertdir = (char *)certdir; /* default is the one passed in */
1500
1501         /* if certdir is not given, just return */
1502         if ( !certdir ) {
1503                 return;
1504         }
1505
1506         prc = PR_GetFileInfo( certdir, &prfi );
1507         /* if certdir exists (file or directory) then it cannot specify a prefix */
1508         if ( prc == PR_SUCCESS ) {
1509                 return;
1510         }
1511
1512         /* if certdir was given, and there is a '/' in certdir, see if there
1513            is anything after the last '/' - if so, assume it is the prefix */
1514         if ( ( ( ptr = strrchr( certdir, sep ) ) ) && *(ptr+1) ) {
1515                 *realcertdir = PL_strndup( certdir, ptr-certdir );
1516                 *prefix = PL_strdup( ptr+1 );
1517         }
1518
1519         return;
1520 }
1521
1522 /*
1523  * This is the part of the init we defer until we get the
1524  * actual security configuration information.  This is
1525  * only called once, protected by a PRCallOnce
1526  * NOTE: This must be done before the first call to SSL_ImportFD,
1527  * especially the setting of the policy
1528  * NOTE: This must be called after fork()
1529  */
1530 static int
1531 tlsm_deferred_init( void *arg )
1532 {
1533         tlsm_ctx *ctx = (tlsm_ctx *)arg;
1534         struct ldaptls *lt = ctx->tc_config;
1535         const char *securitydirs[3];
1536         int ii;
1537         int nn;
1538         PRErrorCode errcode = 1;
1539 #ifdef HAVE_NSS_INITCONTEXT
1540         NSSInitParameters initParams;
1541         NSSInitContext *initctx = NULL;
1542 #endif
1543         SECStatus rc;
1544         int done = 0;
1545
1546 #ifdef HAVE_SECMOD_RESTARTMODULES
1547         /* NSS enforces the pkcs11 requirement that modules should be unloaded after
1548            a fork() - since there is no portable way to determine if NSS has been
1549            already initialized in a parent process, we just call SECMOD_RestartModules
1550            with force == FALSE - if the module has been unloaded due to a fork, it will
1551            be reloaded, otherwise, it is a no-op */
1552         if ( SECFailure == ( rc = SECMOD_RestartModules(PR_FALSE /* do not force */) ) ) {
1553                 errcode = PORT_GetError();
1554                 if ( errcode != SEC_ERROR_NOT_INITIALIZED ) {
1555                         Debug( LDAP_DEBUG_TRACE,
1556                                    "TLS: could not restart the security modules: %d:%s\n",
1557                                    errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
1558                 } else {
1559                         errcode = 1;
1560                 }
1561         }
1562 #endif
1563
1564 #ifdef HAVE_NSS_INITCONTEXT
1565         memset( &initParams, 0, sizeof( initParams ) );
1566         initParams.length = sizeof( initParams );
1567 #endif /* HAVE_NSS_INITCONTEXT */
1568
1569 #ifdef LDAP_R_COMPILE
1570         if ( PR_CallOnce( &tlsm_init_mutex_callonce, tlsm_thr_init_callonce ) ) {
1571                 return -1;
1572         }
1573 #endif /* LDAP_R_COMPILE */
1574
1575 #ifndef HAVE_NSS_INITCONTEXT
1576         if ( !NSS_IsInitialized() ) {
1577 #endif /* HAVE_NSS_INITCONTEXT */
1578                 /*
1579                   MOZNSS_DIR will override everything else - you can
1580                   always set MOZNSS_DIR to force the use of this
1581                   directory
1582                   If using MOZNSS, specify the location of the moznss db dir
1583                   in the cacertdir directive of the OpenLDAP configuration.
1584                   DEFAULT_MOZNSS_DIR will only be used if the code cannot
1585                   find a security dir to use based on the current
1586                   settings
1587                 */
1588                 nn = 0;
1589                 securitydirs[nn++] = PR_GetEnv( "MOZNSS_DIR" );
1590                 securitydirs[nn++] = lt->lt_cacertdir;
1591                 securitydirs[nn++] = PR_GetEnv( "DEFAULT_MOZNSS_DIR" );
1592                 for ( ii = 0; !done && ( ii < nn ); ++ii ) {
1593                         char *realcertdir = NULL;
1594                         const char *defprefix = "";
1595                         char *prefix = (char *)defprefix;
1596                         const char *securitydir = securitydirs[ii];
1597                         if ( NULL == securitydir ) {
1598                                 continue;
1599                         }
1600
1601                         tlsm_get_certdb_prefix( securitydir, &realcertdir, &prefix );
1602 #ifdef LDAP_R_COMPILE
1603                         LDAP_MUTEX_LOCK( &tlsm_init_mutex );
1604 #endif /* LDAP_R_COMPILE */
1605
1606 #ifdef HAVE_NSS_INITCONTEXT
1607 #ifdef INITCONTEXT_HACK
1608                         if ( !NSS_IsInitialized() && ctx->tc_is_server ) {
1609                                 rc = NSS_Initialize( realcertdir, prefix, prefix, SECMOD_DB, NSS_INIT_READONLY );
1610                         } else {
1611                                 initctx = NSS_InitContext( realcertdir, prefix, prefix, SECMOD_DB,
1612                                                                                    &initParams, NSS_INIT_READONLY );
1613                                 rc = (initctx == NULL) ? SECFailure : SECSuccess;
1614                         }
1615 #else
1616                         initctx = NSS_InitContext( realcertdir, prefix, prefix, SECMOD_DB,
1617                                                                            &initParams, NSS_INIT_READONLY );
1618                         rc = (initctx == NULL) ? SECFailure : SECSuccess;
1619 #endif
1620 #else
1621                         rc = NSS_Initialize( realcertdir, prefix, prefix, SECMOD_DB, NSS_INIT_READONLY );
1622 #endif
1623
1624 #ifdef LDAP_R_COMPILE
1625                         LDAP_MUTEX_UNLOCK( &tlsm_init_mutex );
1626 #endif /* LDAP_R_COMPILE */
1627
1628                         if ( rc != SECSuccess ) {
1629                                 errcode = PORT_GetError();
1630                                 if ( securitydirs[ii] != lt->lt_cacertdir) {
1631                                         Debug( LDAP_DEBUG_TRACE,
1632                                                    "TLS: could not initialize moznss using security dir %s prefix %s - error %d.\n",
1633                                                    realcertdir, prefix, errcode );
1634                                 }
1635                         } else {
1636                                 /* success */
1637                                 Debug( LDAP_DEBUG_TRACE, "TLS: using moznss security dir %s prefix %s.\n",
1638                                            realcertdir, prefix, 0 );
1639                                 errcode = 0;
1640                                 done = 1;
1641                         }
1642                         if ( realcertdir != securitydir ) {
1643                                 PL_strfree( realcertdir );
1644                         }
1645                         if ( prefix != defprefix ) {
1646                                 PL_strfree( prefix );
1647                         }
1648                 }
1649
1650                 if ( errcode ) { /* no moznss db found, or not using moznss db */
1651 #ifdef LDAP_R_COMPILE
1652                         LDAP_MUTEX_LOCK( &tlsm_init_mutex );
1653 #endif /* LDAP_R_COMPILE */
1654 #ifdef HAVE_NSS_INITCONTEXT
1655                         int flags = NSS_INIT_READONLY|NSS_INIT_NOCERTDB|NSS_INIT_NOMODDB;
1656 #ifdef INITCONTEXT_HACK
1657                         if ( !NSS_IsInitialized() && ctx->tc_is_server ) {
1658                                 rc = NSS_NoDB_Init( NULL );
1659                         } else {
1660                                 initctx = NSS_InitContext( "", "", "", SECMOD_DB,
1661                                                                                    &initParams, flags );
1662                                 rc = (initctx == NULL) ? SECFailure : SECSuccess;
1663                         }
1664 #else
1665                         initctx = NSS_InitContext( "", "", "", SECMOD_DB,
1666                                                                            &initParams, flags );
1667                         rc = (initctx == NULL) ? SECFailure : SECSuccess;
1668 #endif
1669 #else
1670                         rc = NSS_NoDB_Init( NULL );
1671 #endif
1672 #ifdef LDAP_R_COMPILE
1673                         LDAP_MUTEX_UNLOCK( &tlsm_init_mutex );
1674 #endif /* LDAP_R_COMPILE */
1675                         if ( rc != SECSuccess ) {
1676                                 errcode = PORT_GetError();
1677                                 Debug( LDAP_DEBUG_ANY,
1678                                            "TLS: could not initialize moznss - error %d:%s.\n",
1679                                            errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
1680                                 return -1;
1681                         }
1682
1683 #ifdef HAVE_NSS_INITCONTEXT
1684                         ctx->tc_initctx = initctx;
1685 #endif
1686
1687                         /* initialize the PEM module */
1688 #ifdef LDAP_R_COMPILE
1689                         LDAP_MUTEX_LOCK( &tlsm_init_mutex );
1690 #endif /* LDAP_R_COMPILE */
1691                         if ( tlsm_init_pem_module() ) {
1692 #ifdef LDAP_R_COMPILE
1693                                 LDAP_MUTEX_UNLOCK( &tlsm_init_mutex );
1694 #endif /* LDAP_R_COMPILE */
1695                                 errcode = PORT_GetError();
1696                                 Debug( LDAP_DEBUG_ANY,
1697                                            "TLS: could not initialize moznss PEM module - error %d:%s.\n",
1698                                            errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
1699                                 return -1;
1700                         }
1701 #ifdef LDAP_R_COMPILE
1702                         LDAP_MUTEX_UNLOCK( &tlsm_init_mutex );
1703 #endif /* LDAP_R_COMPILE */
1704
1705                         if ( tlsm_init_ca_certs( ctx, lt->lt_cacertfile, lt->lt_cacertdir ) ) {
1706                                 /* if we tried to use lt->lt_cacertdir as an NSS key/cert db, errcode 
1707                                    will be a value other than 1 - print an error message so that the
1708                                    user will know that failed too */
1709                                 if ( ( errcode != 1 ) && ( lt->lt_cacertdir ) ) {
1710                                         char *realcertdir = NULL;
1711                                         char *prefix = NULL;
1712                                         tlsm_get_certdb_prefix( lt->lt_cacertdir, &realcertdir, &prefix );
1713                                         Debug( LDAP_DEBUG_TRACE,
1714                                                    "TLS: could not initialize moznss using security dir %s prefix %s - error %d.\n",
1715                                                    realcertdir, prefix ? prefix : "", errcode );
1716                                         if ( realcertdir != lt->lt_cacertdir ) {
1717                                                 PL_strfree( realcertdir );
1718                                         }
1719                                         PL_strfree( prefix );
1720                                 }
1721                                 return -1;
1722                         }
1723
1724                         ctx->tc_using_pem = PR_TRUE;
1725                 }
1726
1727 #ifdef HAVE_NSS_INITCONTEXT
1728                 if ( !ctx->tc_initctx ) {
1729                         ctx->tc_initctx = initctx;
1730                 }
1731 #endif
1732
1733                 NSS_SetDomesticPolicy();
1734
1735                 PK11_SetPasswordFunc( tlsm_pin_prompt );
1736
1737                 /* register cleanup function */
1738                 if ( tlsm_register_nss_shutdown() ) {
1739                         errcode = PORT_GetError();
1740                         Debug( LDAP_DEBUG_ANY,
1741                                    "TLS: could not register NSS shutdown function: %d:%s\n",
1742                                    errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
1743                         return -1;
1744                 }
1745 #ifndef HAVE_NSS_INITCONTEXT
1746         }
1747 #endif /* HAVE_NSS_INITCONTEXT */
1748
1749         return 0;
1750 }
1751
1752 static int
1753 tlsm_authenticate( tlsm_ctx *ctx, const char *certname, const char *pininfo )
1754 {
1755         const char *colon = NULL;
1756         char *token_name = NULL;
1757         PK11SlotInfo *slot = NULL;
1758         int rc = -1;
1759
1760         if ( !certname || !*certname ) {
1761                 return 0;
1762         }
1763
1764         if ( ( colon = PL_strchr( certname, ':' ) ) ) {
1765                 token_name = PL_strndup( certname, colon-certname );
1766         }
1767
1768         if ( token_name ) {
1769                 slot = PK11_FindSlotByName( token_name );
1770         } else {
1771                 slot = PK11_GetInternalKeySlot();
1772         }
1773
1774         if ( !slot ) {
1775                 PRErrorCode errcode = PR_GetError();
1776                 Debug( LDAP_DEBUG_ANY,
1777                            "TLS: could not find the slot for security token %s - error %d:%s.\n",
1778                            token_name ? token_name : DEFAULT_TOKEN_NAME, errcode,
1779                            PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1780                 goto done;
1781         }
1782
1783         rc = tlsm_authenticate_to_slot( ctx, slot );
1784
1785 done:
1786         PL_strfree( token_name );
1787         if ( slot ) {
1788                 PK11_FreeSlot( slot );
1789         }
1790
1791         return rc;
1792 }
1793
1794 /*
1795  * Find and verify the certificate.
1796  * Either fd is given, in which case the cert will be taken from it via SSL_PeerCertificate
1797  * or certname is given, and it will be searched for by name
1798  */
1799 static int
1800 tlsm_find_and_verify_cert_key(tlsm_ctx *ctx, PRFileDesc *fd, const char *certname, int isServer, CERTCertificate **pRetCert, SECKEYPrivateKey **pRetKey)
1801 {
1802         CERTCertificate *cert = NULL;
1803         int rc = -1;
1804         void *pin_arg = NULL;
1805         SECKEYPrivateKey *key = NULL;
1806
1807         pin_arg = SSL_RevealPinArg( fd );
1808         if ( certname ) {
1809                 cert = PK11_FindCertFromNickname( certname, pin_arg );
1810                 if ( !cert ) {
1811                         PRErrorCode errcode = PR_GetError();
1812                         Debug( LDAP_DEBUG_ANY,
1813                                    "TLS: error: the certificate %s could not be found in the database - error %d:%s\n",
1814                                    certname, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1815                         return -1;
1816                 }
1817         } else {
1818                 /* we are verifying the peer cert
1819                    we also need to swap the isServer meaning */
1820                 cert = SSL_PeerCertificate( fd );
1821                 if ( !cert ) {
1822                         PRErrorCode errcode = PR_GetError();
1823                         Debug( LDAP_DEBUG_ANY,
1824                                    "TLS: error: could not get the certificate from the peer connection - error %d:%s\n",
1825                                    errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), NULL );
1826                         return -1;
1827                 }
1828                 isServer = !isServer; /* verify the peer's cert instead */
1829         }
1830
1831         if ( ctx->tc_slotname ) {
1832                 PK11SlotInfo *slot = PK11_FindSlotByName( ctx->tc_slotname );
1833                 key = PK11_FindPrivateKeyFromCert( slot, cert, NULL );
1834                 PK11_FreeSlot( slot );
1835         } else {
1836                 key = PK11_FindKeyByAnyCert( cert, pin_arg );
1837         }
1838
1839         if (key) {
1840                 SECCertificateUsage certUsage;
1841                 PRBool checkSig = PR_TRUE;
1842                 SECStatus status;
1843                 /* may not have a CA cert - ok - ignore SEC_ERROR_UNKNOWN_ISSUER */
1844                 int errorToIgnore = SEC_ERROR_UNKNOWN_ISSUER;
1845
1846                 if ( pRetKey ) {
1847                         *pRetKey = key; /* caller will deal with this */
1848                 } else {
1849                         SECKEY_DestroyPrivateKey( key );
1850                 }
1851                 if ( isServer ) {
1852                         certUsage = certificateUsageSSLServer;
1853                 } else {
1854                         certUsage = certificateUsageSSLClient;
1855                 }
1856                 if ( ctx->tc_verify_cert ) {
1857                         checkSig = PR_TRUE;
1858                 } else {
1859                         checkSig = PR_FALSE;
1860                 }
1861                 if ( ctx->tc_warn_only ) {
1862                         errorToIgnore = -1;
1863                 }
1864                 status = tlsm_verify_cert( ctx->tc_certdb, cert, pin_arg,
1865                                                                    checkSig, certUsage, errorToIgnore );
1866                 if ( status == SECSuccess ) {
1867                         rc = 0;
1868                 }
1869         } else {
1870                 PRErrorCode errcode = PR_GetError();
1871                 Debug( LDAP_DEBUG_ANY,
1872                            "TLS: error: could not find the private key for certificate %s - error %d:%s\n",
1873                            certname, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1874         }
1875
1876         if ( pRetCert ) {
1877                 *pRetCert = cert; /* caller will deal with this */
1878         } else {
1879                 CERT_DestroyCertificate( cert );
1880         }
1881
1882     return rc;
1883 }
1884
1885 static int
1886 tlsm_get_client_auth_data( void *arg, PRFileDesc *fd,
1887                                                    CERTDistNames *caNames, CERTCertificate **pRetCert,
1888                                                    SECKEYPrivateKey **pRetKey )
1889 {
1890         tlsm_ctx *ctx = (tlsm_ctx *)arg;
1891         int rc;
1892         PRBool saveval;
1893
1894         /* don't need caNames - this function will call CERT_VerifyCertificateNow
1895            which will verify the cert against the known CAs */
1896         saveval = ctx->tc_warn_only;
1897         ctx->tc_warn_only = PR_TRUE;
1898         rc = tlsm_find_and_verify_cert_key( ctx, fd, ctx->tc_certname, 0, pRetCert, pRetKey );
1899         ctx->tc_warn_only = saveval;
1900         if ( rc ) {
1901                 Debug( LDAP_DEBUG_ANY,
1902                            "TLS: error: unable to perform client certificate authentication for "
1903                            "certificate named %s\n", ctx->tc_certname, 0, 0 );
1904                 if ( pRetKey && *pRetKey ) {
1905                         SECKEY_DestroyPrivateKey( *pRetKey );
1906                         *pRetKey = NULL;
1907                 }
1908                 if ( pRetCert && *pRetCert ) {
1909                         CERT_DestroyCertificate( *pRetCert );
1910                         *pRetCert = NULL;
1911                 }
1912                 return SECFailure;
1913         }
1914
1915         return SECSuccess;
1916 }
1917
1918 /*
1919  * ctx must have a tc_model that is valid
1920  * certname is in the form [<tokenname>:]<certnickname>
1921  * where <tokenname> is the name of the PKCS11 token
1922  * and <certnickname> is the nickname of the cert/key in
1923  * the database
1924 */
1925 static int
1926 tlsm_clientauth_init( tlsm_ctx *ctx )
1927 {
1928         SECStatus status = SECFailure;
1929         int rc;
1930         PRBool saveval;
1931
1932         saveval = ctx->tc_warn_only;
1933         ctx->tc_warn_only = PR_TRUE;
1934         rc = tlsm_find_and_verify_cert_key( ctx, ctx->tc_model, ctx->tc_certname, 0, NULL, NULL );
1935         ctx->tc_warn_only = saveval;
1936         if ( rc ) {
1937                 Debug( LDAP_DEBUG_ANY,
1938                            "TLS: error: unable to set up client certificate authentication for "
1939                            "certificate named %s\n", ctx->tc_certname, 0, 0 );
1940                 return -1;
1941         }
1942
1943         status = SSL_GetClientAuthDataHook( ctx->tc_model,
1944                                                                                 tlsm_get_client_auth_data,
1945                                                                                 (void *)ctx );
1946
1947         return ( status == SECSuccess ? 0 : -1 );
1948 }
1949
1950 /*
1951  * Tear down the TLS subsystem. Should only be called once.
1952  */
1953 static void
1954 tlsm_destroy( void )
1955 {
1956 #ifdef LDAP_R_COMPILE
1957         ldap_pvt_thread_mutex_destroy( &tlsm_init_mutex );
1958 #endif
1959 }
1960
1961 static tls_ctx *
1962 tlsm_ctx_new ( struct ldapoptions *lo )
1963 {
1964         tlsm_ctx *ctx;
1965
1966         ctx = LDAP_MALLOC( sizeof (*ctx) );
1967         if ( ctx ) {
1968                 ctx->tc_refcnt = 1;
1969 #ifdef LDAP_R_COMPILE
1970                 ldap_pvt_thread_mutex_init( &ctx->tc_refmutex );
1971 #endif
1972                 ctx->tc_config = &lo->ldo_tls_info; /* pointer into lo structure - must have global scope and must not go away before we can do real init */
1973                 ctx->tc_certdb = NULL;
1974                 ctx->tc_certname = NULL;
1975                 ctx->tc_pin_file = NULL;
1976                 ctx->tc_model = NULL;
1977                 memset(&ctx->tc_callonce, 0, sizeof(ctx->tc_callonce));
1978                 ctx->tc_require_cert = lo->ldo_tls_require_cert;
1979                 ctx->tc_verify_cert = PR_FALSE;
1980                 ctx->tc_using_pem = PR_FALSE;
1981                 ctx->tc_slotname = NULL;
1982 #ifdef HAVE_NSS_INITCONTEXT
1983                 ctx->tc_initctx = NULL;
1984 #endif /* HAVE_NSS_INITCONTEXT */
1985                 ctx->tc_pem_objs = NULL;
1986                 ctx->tc_n_pem_objs = 0;
1987                 ctx->tc_warn_only = PR_FALSE;
1988         }
1989         return (tls_ctx *)ctx;
1990 }
1991
1992 static void
1993 tlsm_ctx_ref( tls_ctx *ctx )
1994 {
1995         tlsm_ctx *c = (tlsm_ctx *)ctx;
1996         LDAP_MUTEX_LOCK( &c->tc_refmutex );
1997         c->tc_refcnt++;
1998         LDAP_MUTEX_UNLOCK( &c->tc_refmutex );
1999 }
2000
2001 static void
2002 tlsm_ctx_free ( tls_ctx *ctx )
2003 {
2004         tlsm_ctx *c = (tlsm_ctx *)ctx;
2005         int refcount;
2006
2007         if ( !c ) return;
2008
2009         LDAP_MUTEX_LOCK( &c->tc_refmutex );
2010         refcount = --c->tc_refcnt;
2011         LDAP_MUTEX_UNLOCK( &c->tc_refmutex );
2012         if ( refcount )
2013                 return;
2014         if ( c->tc_model )
2015                 PR_Close( c->tc_model );
2016         c->tc_certdb = NULL; /* if not the default, may have to clean up */
2017         PL_strfree( c->tc_certname );
2018         c->tc_certname = NULL;
2019         PL_strfree( c->tc_pin_file );
2020         c->tc_pin_file = NULL;
2021         PL_strfree( c->tc_slotname );           
2022         tlsm_free_pem_objs( c );
2023 #ifdef HAVE_NSS_INITCONTEXT
2024         if ( c->tc_initctx ) {
2025 #ifdef LDAP_R_COMPILE
2026                 LDAP_MUTEX_LOCK( &tlsm_init_mutex );
2027 #endif /* LDAP_R_COMPILE */
2028                 if ( NSS_ShutdownContext( c->tc_initctx ) ) {
2029                         PRErrorCode errcode = PR_GetError();
2030                         Debug( LDAP_DEBUG_ANY,
2031                                    "TLS: could not shutdown NSS - error %d:%s.\n",
2032                                    errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
2033                 }
2034 #ifdef LDAP_R_COMPILE
2035                 LDAP_MUTEX_UNLOCK( &tlsm_init_mutex );
2036 #endif /* LDAP_R_COMPILE */
2037         }
2038         c->tc_initctx = NULL;
2039 #endif /* HAVE_NSS_INITCONTEXT */
2040 #ifdef LDAP_R_COMPILE
2041         ldap_pvt_thread_mutex_destroy( &c->tc_refmutex );
2042 #endif
2043         LDAP_FREE( c );
2044 }
2045
2046 /*
2047  * initialize a new TLS context
2048  */
2049 static int
2050 tlsm_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server )
2051 {
2052         tlsm_ctx *ctx = (tlsm_ctx *)lo->ldo_tls_ctx;
2053         ctx->tc_is_server = is_server;
2054
2055         return 0;
2056 }
2057
2058 static int
2059 tlsm_deferred_ctx_init( void *arg )
2060 {
2061         tlsm_ctx *ctx = (tlsm_ctx *)arg;
2062         PRBool sslv2 = PR_FALSE;
2063         PRBool sslv3 = PR_TRUE;
2064         PRBool tlsv1 = PR_TRUE;
2065         PRBool request_cert = PR_FALSE;
2066         PRInt32 require_cert = PR_FALSE;
2067         PRFileDesc *fd;
2068         struct ldaptls *lt;
2069
2070         if ( tlsm_deferred_init( ctx ) ) {
2071             Debug( LDAP_DEBUG_ANY,
2072                            "TLS: could perform TLS system initialization.\n",
2073                            0, 0, 0 );
2074             return -1;
2075         }
2076
2077         ctx->tc_certdb = CERT_GetDefaultCertDB(); /* If there is ever a per-context db, change this */
2078
2079         fd = PR_CreateIOLayerStub( tlsm_layer_id, &tlsm_PR_methods );
2080         if ( fd ) {
2081                 ctx->tc_model = SSL_ImportFD( NULL, fd );
2082         }
2083
2084         if ( !ctx->tc_model ) {
2085                 PRErrorCode err = PR_GetError();
2086                 Debug( LDAP_DEBUG_ANY,
2087                            "TLS: could perform TLS socket I/O layer initialization - error %d:%s.\n",
2088                            err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
2089
2090                 if ( fd ) {
2091                         PR_Close( fd );
2092                 }
2093                 return -1;
2094         }
2095
2096         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_SECURITY, PR_TRUE ) ) {
2097                 Debug( LDAP_DEBUG_ANY,
2098                        "TLS: could not set secure mode on.\n",
2099                        0, 0, 0 );
2100                 return -1;
2101         }
2102
2103         lt = ctx->tc_config;
2104
2105         /* default is sslv3 and tlsv1 */
2106         if ( lt->lt_protocol_min ) {
2107                 if ( lt->lt_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_SSL3 ) {
2108                         sslv3 = PR_FALSE;
2109                 } else if ( lt->lt_protocol_min <= LDAP_OPT_X_TLS_PROTOCOL_SSL2 ) {
2110                         sslv2 = PR_TRUE;
2111                         Debug( LDAP_DEBUG_ANY,
2112                                "TLS: warning: minimum TLS protocol level set to "
2113                                "include SSLv2 - SSLv2 is insecure - do not use\n", 0, 0, 0 );
2114                 }
2115         }
2116         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_ENABLE_SSL2, sslv2 ) ) {
2117                 Debug( LDAP_DEBUG_ANY,
2118                        "TLS: could not set SSLv2 mode on.\n",
2119                        0, 0, 0 );
2120                 return -1;
2121         }
2122         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_ENABLE_SSL3, sslv3 ) ) {
2123                 Debug( LDAP_DEBUG_ANY,
2124                        "TLS: could not set SSLv3 mode on.\n",
2125                        0, 0, 0 );
2126                 return -1;
2127         }
2128         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_ENABLE_TLS, tlsv1 ) ) {
2129                 Debug( LDAP_DEBUG_ANY,
2130                        "TLS: could not set TLSv1 mode on.\n",
2131                        0, 0, 0 );
2132                 return -1;
2133         }
2134
2135         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_HANDSHAKE_AS_CLIENT, !ctx->tc_is_server ) ) {
2136                 Debug( LDAP_DEBUG_ANY,
2137                        "TLS: could not set handshake as client.\n",
2138                        0, 0, 0 );
2139                 return -1;
2140         }
2141         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_HANDSHAKE_AS_SERVER, ctx->tc_is_server ) ) {
2142                 Debug( LDAP_DEBUG_ANY,
2143                        "TLS: could not set handshake as server.\n",
2144                        0, 0, 0 );
2145                 return -1;
2146         }
2147
2148         if ( lt->lt_ciphersuite &&
2149              tlsm_parse_ciphers( ctx, lt->lt_ciphersuite )) {
2150                 Debug( LDAP_DEBUG_ANY,
2151                        "TLS: could not set cipher list %s.\n",
2152                        lt->lt_ciphersuite, 0, 0 );
2153                 return -1;
2154         } else if ( tlsm_parse_ciphers( ctx, "DEFAULT" ) ) {
2155                 Debug( LDAP_DEBUG_ANY,
2156                        "TLS: could not set cipher list DEFAULT.\n",
2157                        0, 0, 0 );
2158                 return -1;
2159         }
2160
2161         if ( !ctx->tc_require_cert ) {
2162                 ctx->tc_verify_cert = PR_FALSE;
2163         } else if ( !ctx->tc_is_server ) {
2164                 request_cert = PR_TRUE;
2165                 require_cert = SSL_REQUIRE_NO_ERROR;
2166                 if ( ctx->tc_require_cert == LDAP_OPT_X_TLS_DEMAND ||
2167                      ctx->tc_require_cert == LDAP_OPT_X_TLS_HARD ) {
2168                         require_cert = SSL_REQUIRE_ALWAYS;
2169                 }
2170                 if ( ctx->tc_require_cert != LDAP_OPT_X_TLS_ALLOW )
2171                         ctx->tc_verify_cert = PR_TRUE;
2172         } else { /* server */
2173                 /* server does not request certs by default */
2174                 /* if allow - client may send cert, server will ignore if errors */
2175                 /* if try - client may send cert, server will error if bad cert */
2176                 /* if hard or demand - client must send cert, server will error if bad cert */
2177                 request_cert = PR_TRUE;
2178                 require_cert = SSL_REQUIRE_NO_ERROR;
2179                 if ( ctx->tc_require_cert == LDAP_OPT_X_TLS_DEMAND ||
2180                      ctx->tc_require_cert == LDAP_OPT_X_TLS_HARD ) {
2181                         require_cert = SSL_REQUIRE_ALWAYS;
2182                 }
2183                 if ( ctx->tc_require_cert != LDAP_OPT_X_TLS_ALLOW ) {
2184                         ctx->tc_verify_cert = PR_TRUE;
2185                 } else {
2186                         ctx->tc_warn_only = PR_TRUE;
2187                 }
2188         }
2189
2190         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_REQUEST_CERTIFICATE, request_cert ) ) {
2191                 Debug( LDAP_DEBUG_ANY,
2192                        "TLS: could not set request certificate mode.\n",
2193                        0, 0, 0 );
2194                 return -1;
2195         }
2196                 
2197         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_REQUIRE_CERTIFICATE, require_cert ) ) {
2198                 Debug( LDAP_DEBUG_ANY,
2199                        "TLS: could not set require certificate mode.\n",
2200                        0, 0, 0 );
2201                 return -1;
2202         }
2203
2204         /* set up our cert and key, if any */
2205         if ( lt->lt_certfile ) {
2206                 /* if using the PEM module, load the PEM file specified by lt_certfile */
2207                 /* otherwise, assume this is the name of a cert already in the db */
2208                 if ( ctx->tc_using_pem ) {
2209                         /* this sets ctx->tc_certname to the correct value */
2210                         int rc = tlsm_add_cert_from_file( ctx, lt->lt_certfile, PR_FALSE, PR_TRUE );
2211                         if ( rc ) {
2212                                 return rc;
2213                         }
2214                 } else {
2215                         PL_strfree( ctx->tc_certname );
2216                         ctx->tc_certname = PL_strdup( lt->lt_certfile );
2217                 }
2218         }
2219
2220         if ( lt->lt_keyfile ) {
2221                 /* if using the PEM module, load the PEM file specified by lt_keyfile */
2222                 /* otherwise, assume this is the pininfo for the key */
2223                 if ( ctx->tc_using_pem ) {
2224                         /* this sets ctx->tc_certname to the correct value */
2225                         int rc = tlsm_add_key_from_file( ctx, lt->lt_keyfile );
2226                         if ( rc ) {
2227                                 return rc;
2228                         }
2229                 } else {
2230                         PL_strfree( ctx->tc_pin_file );
2231                         ctx->tc_pin_file = PL_strdup( lt->lt_keyfile );
2232                 }
2233         }
2234
2235         /* Set up callbacks for use by clients */
2236         if ( !ctx->tc_is_server ) {
2237                 if ( SSL_OptionSet( ctx->tc_model, SSL_NO_CACHE, PR_TRUE ) != SECSuccess ) {
2238                         PRErrorCode err = PR_GetError();
2239                         Debug( LDAP_DEBUG_ANY, 
2240                                "TLS: error: could not set nocache option for moznss - error %d:%s\n",
2241                                err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
2242                         return -1;
2243                 }
2244
2245                 if ( SSL_BadCertHook( ctx->tc_model, tlsm_bad_cert_handler, ctx ) != SECSuccess ) {
2246                         PRErrorCode err = PR_GetError();
2247                         Debug( LDAP_DEBUG_ANY, 
2248                                "TLS: error: could not set bad cert handler for moznss - error %d:%s\n",
2249                                err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
2250                         return -1;
2251                 }
2252
2253                 /* 
2254                    since a cert has been specified, assume the client wants to do cert auth
2255                 */
2256                 if ( ctx->tc_certname ) {
2257                         if ( tlsm_authenticate( ctx, ctx->tc_certname, ctx->tc_pin_file ) ) {
2258                                 Debug( LDAP_DEBUG_ANY, 
2259                                        "TLS: error: unable to authenticate to the security device for certificate %s\n",
2260                                        ctx->tc_certname, 0, 0 );
2261                                 return -1;
2262                         }
2263                         if ( tlsm_clientauth_init( ctx ) ) {
2264                                 Debug( LDAP_DEBUG_ANY, 
2265                                        "TLS: error: unable to set up client certificate authentication using %s\n",
2266                                        ctx->tc_certname, 0, 0 );
2267                                 return -1;
2268                         }
2269                 }
2270         } else { /* set up secure server */
2271                 SSLKEAType certKEA;
2272                 CERTCertificate *serverCert;
2273                 SECKEYPrivateKey *serverKey;
2274                 SECStatus status;
2275
2276                 /* must have a certificate for the server to use */
2277                 if ( !ctx->tc_certname ) {
2278                         Debug( LDAP_DEBUG_ANY, 
2279                                "TLS: error: no server certificate: must specify a certificate for the server to use\n",
2280                                0, 0, 0 );
2281                         return -1;
2282                 }
2283
2284                 /* authenticate to the server's token - this will do nothing
2285                    if the key/cert db is not password protected */
2286                 if ( tlsm_authenticate( ctx, ctx->tc_certname, ctx->tc_pin_file ) ) {
2287                         Debug( LDAP_DEBUG_ANY, 
2288                                "TLS: error: unable to authenticate to the security device for certificate %s\n",
2289                                ctx->tc_certname, 0, 0 );
2290                         return -1;
2291                 }
2292
2293                 /* get the server's key and cert */
2294                 if ( tlsm_find_and_verify_cert_key( ctx, ctx->tc_model, ctx->tc_certname, ctx->tc_is_server,
2295                                                     &serverCert, &serverKey ) ) {
2296                         Debug( LDAP_DEBUG_ANY, 
2297                                "TLS: error: unable to find and verify server's cert and key for certificate %s\n",
2298                                ctx->tc_certname, 0, 0 );
2299                         CERT_DestroyCertificate( serverCert );
2300                         SECKEY_DestroyPrivateKey( serverKey );
2301                         return -1;
2302                 }
2303
2304                 certKEA = NSS_FindCertKEAType( serverCert );
2305                 /* configure the socket to be a secure server socket */
2306                 status = SSL_ConfigSecureServer( ctx->tc_model, serverCert, serverKey, certKEA );
2307                 /* SSL_ConfigSecureServer copies these */
2308                 CERT_DestroyCertificate( serverCert );
2309                 SECKEY_DestroyPrivateKey( serverKey );
2310
2311                 if ( SECSuccess != status ) {
2312                         PRErrorCode err = PR_GetError();
2313                         Debug( LDAP_DEBUG_ANY, 
2314                                "TLS: error: unable to configure secure server using certificate %s - error %d:%s\n",
2315                                ctx->tc_certname, err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ) );
2316                         return -1;
2317                 }
2318         }
2319
2320         /* Callback for authenticating certificate */
2321         if ( SSL_AuthCertificateHook( ctx->tc_model, tlsm_auth_cert_handler,
2322                                   ctx ) != SECSuccess ) {
2323                 PRErrorCode err = PR_GetError();
2324                 Debug( LDAP_DEBUG_ANY, 
2325                        "TLS: error: could not set auth cert handler for moznss - error %d:%s\n",
2326                        err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
2327                 return -1;
2328         }
2329
2330         if ( SSL_HandshakeCallback( ctx->tc_model, tlsm_handshake_complete_cb, ctx ) ) {
2331                 PRErrorCode err = PR_GetError();
2332                 Debug( LDAP_DEBUG_ANY, 
2333                        "TLS: error: could not set handshake callback for moznss - error %d:%s\n",
2334                        err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
2335                 return -1;
2336         }
2337
2338         return 0;
2339 }
2340
2341 struct tls_data {
2342         tlsm_session            *session;
2343         Sockbuf_IO_Desc         *sbiod;
2344         /* there seems to be no portable way to determine if the
2345            sockbuf sd has been set to nonblocking mode - the
2346            call to ber_pvt_socket_set_nonblock() takes place
2347            before the tls socket is set up, so we cannot
2348            intercept that call either.
2349            On systems where fcntl is available, we can just
2350            F_GETFL and test for O_NONBLOCK.  On other systems,
2351            we will just see if the IO op returns EAGAIN or EWOULDBLOCK,
2352            and just set this flag */
2353         PRBool              nonblock;
2354         /*
2355          * NSS tries hard to be backwards compatible with SSLv2 clients, or
2356          * clients that send an SSLv2 client hello.  This message is not
2357          * tagged in any way, so NSS has no way to know if the incoming
2358          * message is a valid SSLv2 client hello or just some bogus data
2359          * (or cleartext LDAP).  We store the first byte read from the
2360          * client here.  The most common case will be a client sending
2361          * LDAP data instead of SSL encrypted LDAP data.  This can happen,
2362          * for example, if using ldapsearch -Z - if the starttls fails,
2363          * the client will fallback to plain cleartext LDAP.  So if we
2364          * see that the firstbyte is a valid LDAP tag, we can be
2365          * pretty sure this is happening.
2366          */
2367         ber_tag_t           firsttag;
2368         /*
2369          * NSS doesn't return SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE, etc.
2370          * when it is blocked, so we have to set a flag in the wrapped send
2371          * and recv calls that tells us what operation NSS was last blocked
2372          * on
2373          */
2374 #define TLSM_READ  1
2375 #define TLSM_WRITE 2
2376         int io_flag;
2377 };
2378
2379 static struct tls_data *
2380 tlsm_get_pvt_tls_data( PRFileDesc *fd )
2381 {
2382         struct tls_data         *p;
2383         PRFileDesc *myfd;
2384
2385         if ( !fd ) {
2386                 return NULL;
2387         }
2388
2389         myfd = PR_GetIdentitiesLayer( fd, tlsm_layer_id );
2390
2391         if ( !myfd ) {
2392                 return NULL;
2393         }
2394
2395         p = (struct tls_data *)myfd->secret;
2396
2397         return p;
2398 }
2399
2400 static int
2401 tlsm_is_non_ssl_message( PRFileDesc *fd, ber_tag_t *thebyte )
2402 {
2403         struct tls_data         *p;
2404
2405         if ( thebyte ) {
2406                 *thebyte = LBER_DEFAULT;
2407         }
2408
2409         p = tlsm_get_pvt_tls_data( fd );
2410         if ( p == NULL || p->sbiod == NULL ) {
2411                 return 0;
2412         }
2413
2414         if ( p->firsttag == LBER_SEQUENCE ) {
2415                 if ( thebyte ) {
2416                         *thebyte = p->firsttag;
2417                 }
2418                 return 1;
2419         }
2420
2421         return 0;
2422 }
2423
2424 static tls_session *
2425 tlsm_session_new ( tls_ctx * ctx, int is_server )
2426 {
2427         tlsm_ctx *c = (tlsm_ctx *)ctx;
2428         tlsm_session *session;
2429         PRFileDesc *fd;
2430         PRStatus status;
2431         int rc;
2432
2433         c->tc_is_server = is_server;
2434         status = PR_CallOnceWithArg( &c->tc_callonce, tlsm_deferred_ctx_init, c );
2435         if ( PR_SUCCESS != status ) {
2436                 PRErrorCode err = PR_GetError();
2437                 Debug( LDAP_DEBUG_ANY, 
2438                        "TLS: error: could not initialize moznss security context - error %d:%s\n",
2439                        err, PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT), NULL );
2440                 return NULL;
2441         }
2442
2443         fd = PR_CreateIOLayerStub( tlsm_layer_id, &tlsm_PR_methods );
2444         if ( !fd ) {
2445                 return NULL;
2446         }
2447
2448         session = SSL_ImportFD( c->tc_model, fd );
2449         if ( !session ) {
2450                 PR_DELETE( fd );
2451                 return NULL;
2452         }
2453
2454         if ( is_server ) {
2455                 /* 0 means use the defaults here */
2456                 SSL_ConfigServerSessionIDCache( 0, 0, 0, NULL );
2457         }
2458
2459         rc = SSL_ResetHandshake( session, is_server );
2460         if ( rc ) {
2461                 PRErrorCode err = PR_GetError();
2462                 Debug( LDAP_DEBUG_TRACE, 
2463                            "TLS: error: new session - reset handshake failure %d - error %d:%s\n",
2464                            rc, err,
2465                            err ? PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ) : "unknown" );
2466                 PR_DELETE( fd );
2467                 PR_Close( session );
2468                 session = NULL;
2469         }
2470
2471         return (tls_session *)session;
2472
2473
2474 static int
2475 tlsm_session_accept_or_connect( tls_session *session, int is_accept )
2476 {
2477         tlsm_session *s = (tlsm_session *)session;
2478         int rc = SSL_ForceHandshake( s );
2479         const char *op = is_accept ? "accept" : "connect";
2480
2481         if ( rc ) {
2482                 PRErrorCode err = PR_GetError();
2483                 rc = -1;
2484                 if ( err == PR_WOULD_BLOCK_ERROR ) {
2485                         ber_tag_t thetag = LBER_DEFAULT;
2486                         /* see if we are blocked because of a bogus packet */
2487                         if ( tlsm_is_non_ssl_message( s, &thetag ) ) { /* see if we received a non-SSL message */
2488                                 Debug( LDAP_DEBUG_ANY, 
2489                                            "TLS: error: %s - error - received non-SSL message [0x%x]\n",
2490                                            op, (unsigned int)thetag, 0 );
2491                                 /* reset error to something more descriptive */
2492                                 PR_SetError( SSL_ERROR_RX_MALFORMED_HELLO_REQUEST, EPROTO );
2493                         }
2494                 } else {
2495                         Debug( LDAP_DEBUG_ANY, 
2496                                    "TLS: error: %s - force handshake failure: errno %d - moznss error %d\n",
2497                                    op, errno, err );
2498                 }
2499         }
2500
2501         return rc;
2502 }
2503 static int
2504 tlsm_session_accept( tls_session *session )
2505 {
2506         return tlsm_session_accept_or_connect( session, 1 );
2507 }
2508
2509 static int
2510 tlsm_session_connect( LDAP *ld, tls_session *session )
2511 {
2512         return tlsm_session_accept_or_connect( session, 0 );
2513 }
2514
2515 static int
2516 tlsm_session_upflags( Sockbuf *sb, tls_session *session, int rc )
2517 {
2518         int prerror = PR_GetError();
2519
2520         if ( ( prerror == PR_PENDING_INTERRUPT_ERROR ) || ( prerror == PR_WOULD_BLOCK_ERROR ) ) {
2521                 tlsm_session *s = (tlsm_session *)session;
2522                 struct tls_data *p = tlsm_get_pvt_tls_data( s );
2523
2524                 if ( p && ( p->io_flag == TLSM_READ ) ) {
2525                         sb->sb_trans_needs_read = 1;
2526                         return 1;
2527                 } else if ( p && ( p->io_flag == TLSM_WRITE ) ) {
2528                         sb->sb_trans_needs_write = 1;
2529                         return 1;
2530                 }
2531         }
2532
2533         return 0;
2534 }
2535
2536 static char *
2537 tlsm_session_errmsg( tls_session *sess, int rc, char *buf, size_t len )
2538 {
2539         int i;
2540         int prerror = PR_GetError();
2541
2542         i = PR_GetErrorTextLength();
2543         if ( i > len ) {
2544                 char *msg = LDAP_MALLOC( i+1 );
2545                 PR_GetErrorText( msg );
2546                 memcpy( buf, msg, len );
2547                 LDAP_FREE( msg );
2548         } else if ( i ) {
2549                 PR_GetErrorText( buf );
2550         } else if ( prerror ) {
2551                 i = PR_snprintf( buf, len, "TLS error %d:%s",
2552                                                  prerror, PR_ErrorToString( prerror, PR_LANGUAGE_I_DEFAULT ) );
2553         }
2554
2555         return ( i > 0 ) ? buf : NULL;
2556 }
2557
2558 static int
2559 tlsm_session_my_dn( tls_session *session, struct berval *der_dn )
2560 {
2561         tlsm_session *s = (tlsm_session *)session;
2562         CERTCertificate *cert;
2563
2564         cert = SSL_LocalCertificate( s );
2565         if (!cert) return LDAP_INVALID_CREDENTIALS;
2566
2567         der_dn->bv_val = (char *)cert->derSubject.data;
2568         der_dn->bv_len = cert->derSubject.len;
2569         CERT_DestroyCertificate( cert );
2570         return 0;
2571 }
2572
2573 static int
2574 tlsm_session_peer_dn( tls_session *session, struct berval *der_dn )
2575 {
2576         tlsm_session *s = (tlsm_session *)session;
2577         CERTCertificate *cert;
2578
2579         cert = SSL_PeerCertificate( s );
2580         if (!cert) return LDAP_INVALID_CREDENTIALS;
2581         
2582         der_dn->bv_val = (char *)cert->derSubject.data;
2583         der_dn->bv_len = cert->derSubject.len;
2584         CERT_DestroyCertificate( cert );
2585         return 0;
2586 }
2587
2588 /* what kind of hostname were we given? */
2589 #define IS_DNS  0
2590 #define IS_IP4  1
2591 #define IS_IP6  2
2592
2593 static int
2594 tlsm_session_chkhost( LDAP *ld, tls_session *session, const char *name_in )
2595 {
2596         tlsm_session *s = (tlsm_session *)session;
2597         CERTCertificate *cert;
2598         const char *name, *domain = NULL, *ptr;
2599         int ret, ntype = IS_DNS, nlen, dlen;
2600 #ifdef LDAP_PF_INET6
2601         struct in6_addr addr;
2602 #else
2603         struct in_addr addr;
2604 #endif
2605         SECItem altname;
2606         SECStatus rv;
2607
2608         if( ldap_int_hostname &&
2609                 ( !name_in || !strcasecmp( name_in, "localhost" ) ) )
2610         {
2611                 name = ldap_int_hostname;
2612         } else {
2613                 name = name_in;
2614         }
2615         nlen = strlen( name );
2616
2617         cert = SSL_PeerCertificate( s );
2618         if (!cert) {
2619                 Debug( LDAP_DEBUG_ANY,
2620                         "TLS: unable to get peer certificate.\n",
2621                         0, 0, 0 );
2622                 /* if this was a fatal condition, things would have
2623                  * aborted long before now.
2624                  */
2625                 return LDAP_SUCCESS;
2626         }
2627
2628 #ifdef LDAP_PF_INET6
2629         if (name[0] == '[' && strchr(name, ']')) {
2630                 char *n2 = ldap_strdup(name+1);
2631                 *strchr(n2, ']') = 0;
2632                 if (inet_pton(AF_INET6, n2, &addr))
2633                         ntype = IS_IP6;
2634                 LDAP_FREE(n2);
2635         } else 
2636 #endif
2637         if ((ptr = strrchr(name, '.')) && isdigit((unsigned char)ptr[1])) {
2638                 if (inet_aton(name, (struct in_addr *)&addr)) ntype = IS_IP4;
2639         }
2640         if (ntype == IS_DNS ) {
2641                 domain = strchr( name, '.' );
2642                 if ( domain )
2643                         dlen = nlen - ( domain - name );
2644         }
2645
2646         ret = LDAP_LOCAL_ERROR;
2647
2648         rv = CERT_FindCertExtension( cert, SEC_OID_X509_SUBJECT_ALT_NAME,
2649                 &altname );
2650         if ( rv == SECSuccess && altname.data ) {
2651                 PRArenaPool *arena;
2652                 CERTGeneralName *names, *cur;
2653
2654                 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2655                 if ( !arena ) {
2656                         ret = LDAP_NO_MEMORY;
2657                         goto fail;
2658                 }
2659
2660                 names = cur = CERT_DecodeAltNameExtension(arena, &altname);
2661                 if ( !cur )
2662                         goto altfail;
2663
2664                 do {
2665                         char *host;
2666                         int hlen;
2667
2668                         /* ignore empty */
2669                         if ( !cur->name.other.len ) continue;
2670
2671                         host = (char *)cur->name.other.data;
2672                         hlen = cur->name.other.len;
2673
2674                         if ( cur->type == certDNSName ) {
2675                                 if ( ntype != IS_DNS )  continue;
2676
2677                                 /* is this an exact match? */
2678                                 if ( nlen == hlen && !strncasecmp( name, host, nlen )) {
2679                                         ret = LDAP_SUCCESS;
2680                                         break;
2681                                 }
2682
2683                                 /* is this a wildcard match? */
2684                                 if ( domain && host[0] == '*' && host[1] == '.' &&
2685                                         dlen == hlen-1 && !strncasecmp( domain, host+1, dlen )) {
2686                                         ret = LDAP_SUCCESS;
2687                                         break;
2688                                 }
2689                         } else if ( cur->type == certIPAddress ) {
2690                                 if ( ntype == IS_DNS )  continue;
2691                                 
2692 #ifdef LDAP_PF_INET6
2693                                 if (ntype == IS_IP6 && hlen != sizeof(struct in6_addr)) {
2694                                         continue;
2695                                 } else
2696 #endif
2697                                 if (ntype == IS_IP4 && hlen != sizeof(struct in_addr)) {
2698                                         continue;
2699                                 }
2700                                 if (!memcmp(host, &addr, hlen)) {
2701                                         ret = LDAP_SUCCESS;
2702                                         break;
2703                                 }
2704                         }
2705                 } while (( cur = CERT_GetNextGeneralName( cur )) != names );
2706 altfail:
2707                 PORT_FreeArena( arena, PR_FALSE );
2708                 SECITEM_FreeItem( &altname, PR_FALSE );
2709         }
2710         /* no altnames matched, try the CN */
2711         if ( ret != LDAP_SUCCESS ) {
2712                 /* find the last CN */
2713                 CERTRDN *rdn, **rdns;
2714                 CERTAVA *lastava = NULL;
2715                 char buf[2048];
2716
2717                 buf[0] = '\0';
2718                 rdns = cert->subject.rdns;
2719                 while ( rdns && ( rdn = *rdns++ )) {
2720                         CERTAVA *ava, **avas = rdn->avas;
2721                         while ( avas && ( ava = *avas++ )) {
2722                                 if ( CERT_GetAVATag( ava ) == SEC_OID_AVA_COMMON_NAME )
2723                                         lastava = ava;
2724                         }
2725                 }
2726                 if ( lastava ) {
2727                         SECItem *av = CERT_DecodeAVAValue( &lastava->value );
2728                         if ( av ) {
2729                                 if ( av->len == nlen && !strncasecmp( name, (char *)av->data, nlen )) {
2730                                         ret = LDAP_SUCCESS;
2731                                 } else if ( av->data[0] == '*' && av->data[1] == '.' &&
2732                                         domain && dlen == av->len - 1 && !strncasecmp( name,
2733                                                 (char *)(av->data+1), dlen )) {
2734                                         ret = LDAP_SUCCESS;
2735                                 } else {
2736                                         int len = av->len;
2737                                         if ( len >= sizeof(buf) )
2738                                                 len = sizeof(buf)-1;
2739                                         memcpy( buf, av->data, len );
2740                                         buf[len] = '\0';
2741                                 }
2742                                 SECITEM_FreeItem( av, PR_TRUE );
2743                         }
2744                 }
2745                 if ( ret != LDAP_SUCCESS ) {
2746                         Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match "
2747                                 "common name in certificate (%s).\n", 
2748                                 name, buf, 0 );
2749                         ret = LDAP_CONNECT_ERROR;
2750                         if ( ld->ld_error ) {
2751                                 LDAP_FREE( ld->ld_error );
2752                         }
2753                         ld->ld_error = LDAP_STRDUP(
2754                                 _("TLS: hostname does not match CN in peer certificate"));
2755                 }
2756         }
2757
2758 fail:
2759         CERT_DestroyCertificate( cert );
2760         return ret;
2761 }
2762
2763 static int
2764 tlsm_session_strength( tls_session *session )
2765 {
2766         tlsm_session *s = (tlsm_session *)session;
2767         int rc, keySize;
2768
2769         rc = SSL_SecurityStatus( s, NULL, NULL, NULL, &keySize,
2770                 NULL, NULL );
2771         return rc ? 0 : keySize;
2772 }
2773
2774 /*
2775  * TLS support for LBER Sockbufs
2776  */
2777
2778 static PRStatus PR_CALLBACK
2779 tlsm_PR_Close(PRFileDesc *fd)
2780 {
2781         int rc = PR_SUCCESS;
2782
2783         /* we don't need to actually close anything here, just
2784            pop our io layer off the stack */
2785         fd->secret = NULL; /* must have been freed before calling PR_Close */
2786         if ( fd->lower ) {
2787                 fd = PR_PopIOLayer( fd, tlsm_layer_id );
2788                 /* if we are not the last layer, pass the close along */
2789                 if ( fd ) {
2790                         if ( fd->dtor ) {
2791                                 fd->dtor( fd );
2792                         }
2793                         rc = fd->methods->close( fd );
2794                 }
2795         } else {
2796                 /* we are the last layer - just call our dtor */
2797                 fd->dtor(fd);
2798         }
2799
2800         return rc;
2801 }
2802
2803 static PRStatus PR_CALLBACK
2804 tlsm_PR_Shutdown(PRFileDesc *fd, PRShutdownHow how)
2805 {
2806         int rc = PR_SUCCESS;
2807
2808         if ( fd->lower ) {
2809                 rc = PR_Shutdown( fd->lower, how );
2810         }
2811
2812         return rc;
2813 }
2814
2815 static int PR_CALLBACK
2816 tlsm_PR_Recv(PRFileDesc *fd, void *buf, PRInt32 len, PRIntn flags,
2817          PRIntervalTime timeout)
2818 {
2819         struct tls_data         *p;
2820         int rc;
2821
2822         if ( buf == NULL || len <= 0 ) return 0;
2823
2824         p = tlsm_get_pvt_tls_data( fd );
2825
2826         if ( p == NULL || p->sbiod == NULL ) {
2827                 return 0;
2828         }
2829
2830         rc = LBER_SBIOD_READ_NEXT( p->sbiod, buf, len );
2831         if (rc <= 0) {
2832                 tlsm_map_error( errno );
2833                 if ( errno == EAGAIN || errno == EWOULDBLOCK ) {
2834                         p->nonblock = PR_TRUE; /* fd is using non-blocking io */
2835                 } else if ( errno ) { /* real error */
2836                         Debug( LDAP_DEBUG_TRACE, 
2837                                "TLS: error: tlsm_PR_Recv returned %d - error %d:%s\n",
2838                                rc, errno, STRERROR(errno) );
2839                 }
2840         } else if ( ( rc > 0 ) && ( len > 0 ) && ( p->firsttag == LBER_DEFAULT ) ) {
2841                 p->firsttag = (ber_tag_t)*((char *)buf);
2842         }
2843         p->io_flag = TLSM_READ;
2844
2845         return rc;
2846 }
2847
2848 static int PR_CALLBACK
2849 tlsm_PR_Send(PRFileDesc *fd, const void *buf, PRInt32 len, PRIntn flags,
2850          PRIntervalTime timeout)
2851 {
2852         struct tls_data         *p;
2853         int rc;
2854
2855         if ( buf == NULL || len <= 0 ) return 0;
2856
2857         p = tlsm_get_pvt_tls_data( fd );
2858
2859         if ( p == NULL || p->sbiod == NULL ) {
2860                 return 0;
2861         }
2862
2863         rc = LBER_SBIOD_WRITE_NEXT( p->sbiod, (char *)buf, len );
2864         if (rc <= 0) {
2865                 tlsm_map_error( errno );
2866                 if ( errno == EAGAIN || errno == EWOULDBLOCK ) {
2867                         p->nonblock = PR_TRUE;
2868                 } else if ( errno ) { /* real error */
2869                         Debug( LDAP_DEBUG_TRACE, 
2870                                "TLS: error: tlsm_PR_Send returned %d - error %d:%s\n",
2871                                rc, errno, STRERROR(errno) );
2872                 }
2873         }
2874         p->io_flag = TLSM_WRITE;
2875
2876         return rc;
2877 }
2878
2879 static int PR_CALLBACK
2880 tlsm_PR_Read(PRFileDesc *fd, void *buf, PRInt32 len)
2881 {
2882         return tlsm_PR_Recv( fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
2883 }
2884
2885 static int PR_CALLBACK
2886 tlsm_PR_Write(PRFileDesc *fd, const void *buf, PRInt32 len)
2887 {
2888         return tlsm_PR_Send( fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
2889 }
2890
2891 static PRStatus PR_CALLBACK
2892 tlsm_PR_GetPeerName(PRFileDesc *fd, PRNetAddr *addr)
2893 {
2894         struct tls_data         *p;
2895         ber_socklen_t len;
2896
2897         p = tlsm_get_pvt_tls_data( fd );
2898
2899         if ( p == NULL || p->sbiod == NULL ) {
2900                 return PR_FAILURE;
2901         }
2902         len = sizeof(PRNetAddr);
2903         return getpeername( p->sbiod->sbiod_sb->sb_fd, (struct sockaddr *)addr, &len );
2904 }
2905
2906 static PRStatus PR_CALLBACK
2907 tlsm_PR_GetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
2908 {
2909         struct tls_data         *p;
2910         p = tlsm_get_pvt_tls_data( fd );
2911
2912         if ( p == NULL || data == NULL ) {
2913                 return PR_FAILURE;
2914         }
2915
2916         /* only the nonblocking option is supported at this time
2917            MozNSS SSL code needs it */
2918         if ( data->option != PR_SockOpt_Nonblocking ) {
2919                 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2920                 return PR_FAILURE;
2921         }
2922 #ifdef HAVE_FCNTL
2923         int flags = fcntl( p->sbiod->sbiod_sb->sb_fd, F_GETFL );
2924         data->value.non_blocking = (flags & O_NONBLOCK) ? PR_TRUE : PR_FALSE;           
2925 #else /* punt :P */
2926         data->value.non_blocking = p->nonblock;
2927 #endif
2928         return PR_SUCCESS;
2929 }
2930
2931 static PRStatus PR_CALLBACK
2932 tlsm_PR_prs_unimp()
2933 {
2934     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2935     return PR_FAILURE;
2936 }
2937
2938 static PRFileDesc * PR_CALLBACK
2939 tlsm_PR_pfd_unimp()
2940 {
2941     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2942     return NULL;
2943 }
2944
2945 static PRInt16 PR_CALLBACK
2946 tlsm_PR_i16_unimp()
2947 {
2948     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2949     return SECFailure;
2950 }
2951
2952 static PRInt32 PR_CALLBACK
2953 tlsm_PR_i32_unimp()
2954 {
2955     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2956     return SECFailure;
2957 }
2958
2959 static PRInt64 PR_CALLBACK
2960 tlsm_PR_i64_unimp()
2961 {
2962     PRInt64 res;
2963
2964     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2965     LL_I2L(res, -1L);
2966     return res;
2967 }
2968
2969 static const PRIOMethods tlsm_PR_methods = {
2970     PR_DESC_LAYERED,
2971     tlsm_PR_Close,                      /* close        */
2972     tlsm_PR_Read,                       /* read         */
2973     tlsm_PR_Write,                      /* write        */
2974     tlsm_PR_i32_unimp,          /* available    */
2975     tlsm_PR_i64_unimp,          /* available64  */
2976     tlsm_PR_prs_unimp,          /* fsync        */
2977     tlsm_PR_i32_unimp,          /* seek         */
2978     tlsm_PR_i64_unimp,          /* seek64       */
2979     tlsm_PR_prs_unimp,          /* fileInfo     */
2980     tlsm_PR_prs_unimp,          /* fileInfo64   */
2981     tlsm_PR_i32_unimp,          /* writev       */
2982     tlsm_PR_prs_unimp,          /* connect      */
2983     tlsm_PR_pfd_unimp,          /* accept       */
2984     tlsm_PR_prs_unimp,          /* bind         */
2985     tlsm_PR_prs_unimp,          /* listen       */
2986     (PRShutdownFN)tlsm_PR_Shutdown,                     /* shutdown     */
2987     tlsm_PR_Recv,                       /* recv         */
2988     tlsm_PR_Send,                       /* send         */
2989     tlsm_PR_i32_unimp,          /* recvfrom     */
2990     tlsm_PR_i32_unimp,          /* sendto       */
2991     (PRPollFN)tlsm_PR_i16_unimp,        /* poll         */
2992     tlsm_PR_i32_unimp,          /* acceptread   */
2993     tlsm_PR_i32_unimp,          /* transmitfile */
2994     tlsm_PR_prs_unimp,          /* getsockname  */
2995     tlsm_PR_GetPeerName,        /* getpeername  */
2996     tlsm_PR_i32_unimp,          /* getsockopt   OBSOLETE */
2997     tlsm_PR_i32_unimp,          /* setsockopt   OBSOLETE */
2998     tlsm_PR_GetSocketOption,            /* getsocketoption   */
2999     tlsm_PR_i32_unimp,          /* setsocketoption   */
3000     tlsm_PR_i32_unimp,          /* Send a (partial) file with header/trailer*/
3001     (PRConnectcontinueFN)tlsm_PR_prs_unimp,             /* connectcontinue */
3002     tlsm_PR_i32_unimp,          /* reserved for future use */
3003     tlsm_PR_i32_unimp,          /* reserved for future use */
3004     tlsm_PR_i32_unimp,          /* reserved for future use */
3005     tlsm_PR_i32_unimp           /* reserved for future use */
3006 };
3007
3008 /*
3009  * Initialize TLS subsystem. Should be called only once.
3010  * See tlsm_deferred_init for the bulk of the init process
3011  */
3012 static int
3013 tlsm_init( void )
3014 {
3015         char *nofork = PR_GetEnv( "NSS_STRICT_NOFORK" );
3016
3017         PR_Init(0, 0, 0);
3018
3019         tlsm_layer_id = PR_GetUniqueIdentity( "OpenLDAP" );
3020
3021         /*
3022          * There are some applications that acquire a crypto context in the parent process
3023          * and expect that crypto context to work after a fork().  This does not work
3024          * with NSS using strict PKCS11 compliance mode.  We set this environment
3025          * variable here to tell the software encryption module/token to allow crypto
3026          * contexts to persist across a fork().  However, if you are using some other
3027          * module or encryption device that supports and expects full PKCS11 semantics,
3028          * the only recourse is to rewrite the application with atfork() handlers to save
3029          * the crypto context in the parent and restore (and SECMOD_RestartModules) the
3030          * context in the child.
3031          */
3032         if ( !nofork ) {
3033                 /* will leak one time */
3034                 char *noforkenvvar = PL_strdup( "NSS_STRICT_NOFORK=DISABLED" );
3035                 PR_SetEnv( noforkenvvar );
3036         }
3037
3038         return 0;
3039 }
3040
3041 static int
3042 tlsm_sb_setup( Sockbuf_IO_Desc *sbiod, void *arg )
3043 {
3044         struct tls_data         *p;
3045         tlsm_session    *session = arg;
3046         PRFileDesc *fd;
3047
3048         assert( sbiod != NULL );
3049
3050         p = LBER_MALLOC( sizeof( *p ) );
3051         if ( p == NULL ) {
3052                 return -1;
3053         }
3054
3055         fd = PR_GetIdentitiesLayer( session, tlsm_layer_id );
3056         if ( !fd ) {
3057                 LBER_FREE( p );
3058                 return -1;
3059         }
3060
3061         fd->secret = (PRFilePrivate *)p;
3062         p->session = session;
3063         p->sbiod = sbiod;
3064         p->firsttag = LBER_DEFAULT;
3065         sbiod->sbiod_pvt = p;
3066         return 0;
3067 }
3068
3069 static int
3070 tlsm_sb_remove( Sockbuf_IO_Desc *sbiod )
3071 {
3072         struct tls_data         *p;
3073         
3074         assert( sbiod != NULL );
3075         assert( sbiod->sbiod_pvt != NULL );
3076
3077         p = (struct tls_data *)sbiod->sbiod_pvt;
3078         PR_Close( p->session );
3079         LBER_FREE( sbiod->sbiod_pvt );
3080         sbiod->sbiod_pvt = NULL;
3081         return 0;
3082 }
3083
3084 static int
3085 tlsm_sb_close( Sockbuf_IO_Desc *sbiod )
3086 {
3087         struct tls_data         *p;
3088         
3089         assert( sbiod != NULL );
3090         assert( sbiod->sbiod_pvt != NULL );
3091
3092         p = (struct tls_data *)sbiod->sbiod_pvt;
3093         PR_Shutdown( p->session, PR_SHUTDOWN_BOTH );
3094         return 0;
3095 }
3096
3097 static int
3098 tlsm_sb_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
3099 {
3100         struct tls_data         *p;
3101         
3102         assert( sbiod != NULL );
3103         assert( sbiod->sbiod_pvt != NULL );
3104
3105         p = (struct tls_data *)sbiod->sbiod_pvt;
3106         
3107         if ( opt == LBER_SB_OPT_GET_SSL ) {
3108                 *((tlsm_session **)arg) = p->session;
3109                 return 1;
3110                 
3111         } else if ( opt == LBER_SB_OPT_DATA_READY ) {
3112                 if ( p && ( SSL_DataPending( p->session ) > 0 ) ) {
3113                         return 1;
3114                 }
3115                 
3116         }
3117         
3118         return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
3119 }
3120
3121 static ber_slen_t
3122 tlsm_sb_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
3123 {
3124         struct tls_data         *p;
3125         ber_slen_t              ret;
3126         int                     err;
3127
3128         assert( sbiod != NULL );
3129         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
3130
3131         p = (struct tls_data *)sbiod->sbiod_pvt;
3132
3133         ret = PR_Recv( p->session, buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
3134         if ( ret < 0 ) {
3135                 err = PR_GetError();
3136                 if ( err == PR_PENDING_INTERRUPT_ERROR || err == PR_WOULD_BLOCK_ERROR ) {
3137                         sbiod->sbiod_sb->sb_trans_needs_read = 1;
3138                         sock_errset(EWOULDBLOCK);
3139                 }
3140         } else {
3141                 sbiod->sbiod_sb->sb_trans_needs_read = 0;
3142         }
3143         return ret;
3144 }
3145
3146 static ber_slen_t
3147 tlsm_sb_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
3148 {
3149         struct tls_data         *p;
3150         ber_slen_t              ret;
3151         int                     err;
3152
3153         assert( sbiod != NULL );
3154         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
3155
3156         p = (struct tls_data *)sbiod->sbiod_pvt;
3157
3158         ret = PR_Send( p->session, (char *)buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
3159         if ( ret < 0 ) {
3160                 err = PR_GetError();
3161                 if ( err == PR_PENDING_INTERRUPT_ERROR || err == PR_WOULD_BLOCK_ERROR ) {
3162                         sbiod->sbiod_sb->sb_trans_needs_write = 1;
3163                         sock_errset(EWOULDBLOCK);
3164                         ret = 0;
3165                 }
3166         } else {
3167                 sbiod->sbiod_sb->sb_trans_needs_write = 0;
3168         }
3169         return ret;
3170 }
3171
3172 static Sockbuf_IO tlsm_sbio =
3173 {
3174         tlsm_sb_setup,          /* sbi_setup */
3175         tlsm_sb_remove,         /* sbi_remove */
3176         tlsm_sb_ctrl,           /* sbi_ctrl */
3177         tlsm_sb_read,           /* sbi_read */
3178         tlsm_sb_write,          /* sbi_write */
3179         tlsm_sb_close           /* sbi_close */
3180 };
3181
3182 tls_impl ldap_int_tls_impl = {
3183         "MozNSS",
3184
3185         tlsm_init,
3186         tlsm_destroy,
3187
3188         tlsm_ctx_new,
3189         tlsm_ctx_ref,
3190         tlsm_ctx_free,
3191         tlsm_ctx_init,
3192
3193         tlsm_session_new,
3194         tlsm_session_connect,
3195         tlsm_session_accept,
3196         tlsm_session_upflags,
3197         tlsm_session_errmsg,
3198         tlsm_session_my_dn,
3199         tlsm_session_peer_dn,
3200         tlsm_session_chkhost,
3201         tlsm_session_strength,
3202
3203         &tlsm_sbio,
3204
3205 #ifdef LDAP_R_COMPILE
3206         tlsm_thr_init,
3207 #else
3208         NULL,
3209 #endif
3210
3211         0
3212 };
3213
3214 #endif /* HAVE_MOZNSS */
3215 /*
3216   emacs settings
3217   Local Variables:
3218   indent-tabs-mode: t
3219   tab-width: 4
3220   End:
3221 */