]> git.sur5r.net Git - openldap/blob - libraries/libldap/tls_m.c
Merge branch 'mdb.master' of /home/hyc/OD/mdb
[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                         LDAP_MUTEX_LOCK( &tlsm_init_mutex );
1603
1604 #ifdef HAVE_NSS_INITCONTEXT
1605 #ifdef INITCONTEXT_HACK
1606                         if ( !NSS_IsInitialized() && ctx->tc_is_server ) {
1607                                 rc = NSS_Initialize( realcertdir, prefix, prefix, SECMOD_DB, NSS_INIT_READONLY );
1608                         } else {
1609                                 initctx = NSS_InitContext( realcertdir, prefix, prefix, SECMOD_DB,
1610                                                                                    &initParams, NSS_INIT_READONLY );
1611                                 rc = (initctx == NULL) ? SECFailure : SECSuccess;
1612                         }
1613 #else
1614                         initctx = NSS_InitContext( realcertdir, prefix, prefix, SECMOD_DB,
1615                                                                            &initParams, NSS_INIT_READONLY );
1616                         rc = (initctx == NULL) ? SECFailure : SECSuccess;
1617 #endif
1618 #else
1619                         rc = NSS_Initialize( realcertdir, prefix, prefix, SECMOD_DB, NSS_INIT_READONLY );
1620 #endif
1621
1622                         LDAP_MUTEX_UNLOCK( &tlsm_init_mutex );
1623
1624                         if ( rc != SECSuccess ) {
1625                                 errcode = PORT_GetError();
1626                                 if ( securitydirs[ii] != lt->lt_cacertdir) {
1627                                         Debug( LDAP_DEBUG_TRACE,
1628                                                    "TLS: could not initialize moznss using security dir %s prefix %s - error %d.\n",
1629                                                    realcertdir, prefix, errcode );
1630                                 }
1631                         } else {
1632                                 /* success */
1633                                 Debug( LDAP_DEBUG_TRACE, "TLS: using moznss security dir %s prefix %s.\n",
1634                                            realcertdir, prefix, 0 );
1635                                 errcode = 0;
1636                                 done = 1;
1637                         }
1638                         if ( realcertdir != securitydir ) {
1639                                 PL_strfree( realcertdir );
1640                         }
1641                         if ( prefix != defprefix ) {
1642                                 PL_strfree( prefix );
1643                         }
1644                 }
1645
1646                 if ( errcode ) { /* no moznss db found, or not using moznss db */
1647                         LDAP_MUTEX_LOCK( &tlsm_init_mutex );
1648 #ifdef HAVE_NSS_INITCONTEXT
1649                         int flags = NSS_INIT_READONLY|NSS_INIT_NOCERTDB|NSS_INIT_NOMODDB;
1650 #ifdef INITCONTEXT_HACK
1651                         if ( !NSS_IsInitialized() && ctx->tc_is_server ) {
1652                                 rc = NSS_NoDB_Init( NULL );
1653                         } else {
1654                                 initctx = NSS_InitContext( "", "", "", SECMOD_DB,
1655                                                                                    &initParams, flags );
1656                                 rc = (initctx == NULL) ? SECFailure : SECSuccess;
1657                         }
1658 #else
1659                         initctx = NSS_InitContext( "", "", "", SECMOD_DB,
1660                                                                            &initParams, flags );
1661                         rc = (initctx == NULL) ? SECFailure : SECSuccess;
1662 #endif
1663 #else
1664                         rc = NSS_NoDB_Init( NULL );
1665 #endif
1666                         LDAP_MUTEX_UNLOCK( &tlsm_init_mutex );
1667                         if ( rc != SECSuccess ) {
1668                                 errcode = PORT_GetError();
1669                                 Debug( LDAP_DEBUG_ANY,
1670                                            "TLS: could not initialize moznss - error %d:%s.\n",
1671                                            errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
1672                                 return -1;
1673                         }
1674
1675 #ifdef HAVE_NSS_INITCONTEXT
1676                         ctx->tc_initctx = initctx;
1677 #endif
1678
1679                         /* initialize the PEM module */
1680                         LDAP_MUTEX_LOCK( &tlsm_init_mutex );
1681                         if ( tlsm_init_pem_module() ) {
1682                                 LDAP_MUTEX_UNLOCK( &tlsm_init_mutex );
1683                                 errcode = PORT_GetError();
1684                                 Debug( LDAP_DEBUG_ANY,
1685                                            "TLS: could not initialize moznss PEM module - error %d:%s.\n",
1686                                            errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
1687                                 return -1;
1688                         }
1689                         LDAP_MUTEX_UNLOCK( &tlsm_init_mutex );
1690
1691                         if ( tlsm_init_ca_certs( ctx, lt->lt_cacertfile, lt->lt_cacertdir ) ) {
1692                                 /* if we tried to use lt->lt_cacertdir as an NSS key/cert db, errcode 
1693                                    will be a value other than 1 - print an error message so that the
1694                                    user will know that failed too */
1695                                 if ( ( errcode != 1 ) && ( lt->lt_cacertdir ) ) {
1696                                         char *realcertdir = NULL;
1697                                         char *prefix = NULL;
1698                                         tlsm_get_certdb_prefix( lt->lt_cacertdir, &realcertdir, &prefix );
1699                                         Debug( LDAP_DEBUG_TRACE,
1700                                                    "TLS: could not initialize moznss using security dir %s prefix %s - error %d.\n",
1701                                                    realcertdir, prefix ? prefix : "", errcode );
1702                                         if ( realcertdir != lt->lt_cacertdir ) {
1703                                                 PL_strfree( realcertdir );
1704                                         }
1705                                         PL_strfree( prefix );
1706                                 }
1707                                 return -1;
1708                         }
1709
1710                         ctx->tc_using_pem = PR_TRUE;
1711                 }
1712
1713 #ifdef HAVE_NSS_INITCONTEXT
1714                 if ( !ctx->tc_initctx ) {
1715                         ctx->tc_initctx = initctx;
1716                 }
1717 #endif
1718
1719                 NSS_SetDomesticPolicy();
1720
1721                 PK11_SetPasswordFunc( tlsm_pin_prompt );
1722
1723                 /* register cleanup function */
1724                 if ( tlsm_register_nss_shutdown() ) {
1725                         errcode = PORT_GetError();
1726                         Debug( LDAP_DEBUG_ANY,
1727                                    "TLS: could not register NSS shutdown function: %d:%s\n",
1728                                    errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
1729                         return -1;
1730                 }
1731 #ifndef HAVE_NSS_INITCONTEXT
1732         }
1733 #endif /* HAVE_NSS_INITCONTEXT */
1734
1735         return 0;
1736 }
1737
1738 static int
1739 tlsm_authenticate( tlsm_ctx *ctx, const char *certname, const char *pininfo )
1740 {
1741         const char *colon = NULL;
1742         char *token_name = NULL;
1743         PK11SlotInfo *slot = NULL;
1744         int rc = -1;
1745
1746         if ( !certname || !*certname ) {
1747                 return 0;
1748         }
1749
1750         if ( ( colon = PL_strchr( certname, ':' ) ) ) {
1751                 token_name = PL_strndup( certname, colon-certname );
1752         }
1753
1754         if ( token_name ) {
1755                 slot = PK11_FindSlotByName( token_name );
1756         } else {
1757                 slot = PK11_GetInternalKeySlot();
1758         }
1759
1760         if ( !slot ) {
1761                 PRErrorCode errcode = PR_GetError();
1762                 Debug( LDAP_DEBUG_ANY,
1763                            "TLS: could not find the slot for security token %s - error %d:%s.\n",
1764                            token_name ? token_name : DEFAULT_TOKEN_NAME, errcode,
1765                            PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1766                 goto done;
1767         }
1768
1769         rc = tlsm_authenticate_to_slot( ctx, slot );
1770
1771 done:
1772         PL_strfree( token_name );
1773         if ( slot ) {
1774                 PK11_FreeSlot( slot );
1775         }
1776
1777         return rc;
1778 }
1779
1780 /*
1781  * Find and verify the certificate.
1782  * Either fd is given, in which case the cert will be taken from it via SSL_PeerCertificate
1783  * or certname is given, and it will be searched for by name
1784  */
1785 static int
1786 tlsm_find_and_verify_cert_key(tlsm_ctx *ctx, PRFileDesc *fd, const char *certname, int isServer, CERTCertificate **pRetCert, SECKEYPrivateKey **pRetKey)
1787 {
1788         CERTCertificate *cert = NULL;
1789         int rc = -1;
1790         void *pin_arg = NULL;
1791         SECKEYPrivateKey *key = NULL;
1792
1793         pin_arg = SSL_RevealPinArg( fd );
1794         if ( certname ) {
1795                 cert = PK11_FindCertFromNickname( certname, pin_arg );
1796                 if ( !cert ) {
1797                         PRErrorCode errcode = PR_GetError();
1798                         Debug( LDAP_DEBUG_ANY,
1799                                    "TLS: error: the certificate %s could not be found in the database - error %d:%s\n",
1800                                    certname, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1801                         return -1;
1802                 }
1803         } else {
1804                 /* we are verifying the peer cert
1805                    we also need to swap the isServer meaning */
1806                 cert = SSL_PeerCertificate( fd );
1807                 if ( !cert ) {
1808                         PRErrorCode errcode = PR_GetError();
1809                         Debug( LDAP_DEBUG_ANY,
1810                                    "TLS: error: could not get the certificate from the peer connection - error %d:%s\n",
1811                                    errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), NULL );
1812                         return -1;
1813                 }
1814                 isServer = !isServer; /* verify the peer's cert instead */
1815         }
1816
1817         if ( ctx->tc_slotname ) {
1818                 PK11SlotInfo *slot = PK11_FindSlotByName( ctx->tc_slotname );
1819                 key = PK11_FindPrivateKeyFromCert( slot, cert, NULL );
1820                 PK11_FreeSlot( slot );
1821         } else {
1822                 key = PK11_FindKeyByAnyCert( cert, pin_arg );
1823         }
1824
1825         if (key) {
1826                 SECCertificateUsage certUsage;
1827                 PRBool checkSig = PR_TRUE;
1828                 SECStatus status;
1829                 /* may not have a CA cert - ok - ignore SEC_ERROR_UNKNOWN_ISSUER */
1830                 int errorToIgnore = SEC_ERROR_UNKNOWN_ISSUER;
1831
1832                 if ( pRetKey ) {
1833                         *pRetKey = key; /* caller will deal with this */
1834                 } else {
1835                         SECKEY_DestroyPrivateKey( key );
1836                 }
1837                 if ( isServer ) {
1838                         certUsage = certificateUsageSSLServer;
1839                 } else {
1840                         certUsage = certificateUsageSSLClient;
1841                 }
1842                 if ( ctx->tc_verify_cert ) {
1843                         checkSig = PR_TRUE;
1844                 } else {
1845                         checkSig = PR_FALSE;
1846                 }
1847                 if ( ctx->tc_warn_only ) {
1848                         errorToIgnore = -1;
1849                 }
1850                 status = tlsm_verify_cert( ctx->tc_certdb, cert, pin_arg,
1851                                                                    checkSig, certUsage, errorToIgnore );
1852                 if ( status == SECSuccess ) {
1853                         rc = 0;
1854                 }
1855         } else {
1856                 PRErrorCode errcode = PR_GetError();
1857                 Debug( LDAP_DEBUG_ANY,
1858                            "TLS: error: could not find the private key for certificate %s - error %d:%s\n",
1859                            certname, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1860         }
1861
1862         if ( pRetCert ) {
1863                 *pRetCert = cert; /* caller will deal with this */
1864         } else {
1865                 CERT_DestroyCertificate( cert );
1866         }
1867
1868     return rc;
1869 }
1870
1871 static int
1872 tlsm_get_client_auth_data( void *arg, PRFileDesc *fd,
1873                                                    CERTDistNames *caNames, CERTCertificate **pRetCert,
1874                                                    SECKEYPrivateKey **pRetKey )
1875 {
1876         tlsm_ctx *ctx = (tlsm_ctx *)arg;
1877         int rc;
1878         PRBool saveval;
1879
1880         /* don't need caNames - this function will call CERT_VerifyCertificateNow
1881            which will verify the cert against the known CAs */
1882         saveval = ctx->tc_warn_only;
1883         ctx->tc_warn_only = PR_TRUE;
1884         rc = tlsm_find_and_verify_cert_key( ctx, fd, ctx->tc_certname, 0, pRetCert, pRetKey );
1885         ctx->tc_warn_only = saveval;
1886         if ( rc ) {
1887                 Debug( LDAP_DEBUG_ANY,
1888                            "TLS: error: unable to perform client certificate authentication for "
1889                            "certificate named %s\n", ctx->tc_certname, 0, 0 );
1890                 if ( pRetKey && *pRetKey ) {
1891                         SECKEY_DestroyPrivateKey( *pRetKey );
1892                         *pRetKey = NULL;
1893                 }
1894                 if ( pRetCert && *pRetCert ) {
1895                         CERT_DestroyCertificate( *pRetCert );
1896                         *pRetCert = NULL;
1897                 }
1898                 return SECFailure;
1899         }
1900
1901         return SECSuccess;
1902 }
1903
1904 /*
1905  * ctx must have a tc_model that is valid
1906  * certname is in the form [<tokenname>:]<certnickname>
1907  * where <tokenname> is the name of the PKCS11 token
1908  * and <certnickname> is the nickname of the cert/key in
1909  * the database
1910 */
1911 static int
1912 tlsm_clientauth_init( tlsm_ctx *ctx )
1913 {
1914         SECStatus status = SECFailure;
1915         int rc;
1916         PRBool saveval;
1917
1918         saveval = ctx->tc_warn_only;
1919         ctx->tc_warn_only = PR_TRUE;
1920         rc = tlsm_find_and_verify_cert_key( ctx, ctx->tc_model, ctx->tc_certname, 0, NULL, NULL );
1921         ctx->tc_warn_only = saveval;
1922         if ( rc ) {
1923                 Debug( LDAP_DEBUG_ANY,
1924                            "TLS: error: unable to set up client certificate authentication for "
1925                            "certificate named %s\n", ctx->tc_certname, 0, 0 );
1926                 return -1;
1927         }
1928
1929         status = SSL_GetClientAuthDataHook( ctx->tc_model,
1930                                                                                 tlsm_get_client_auth_data,
1931                                                                                 (void *)ctx );
1932
1933         return ( status == SECSuccess ? 0 : -1 );
1934 }
1935
1936 /*
1937  * Tear down the TLS subsystem. Should only be called once.
1938  */
1939 static void
1940 tlsm_destroy( void )
1941 {
1942 #ifdef LDAP_R_COMPILE
1943         ldap_pvt_thread_mutex_destroy( &tlsm_init_mutex );
1944 #endif
1945 }
1946
1947 static tls_ctx *
1948 tlsm_ctx_new ( struct ldapoptions *lo )
1949 {
1950         tlsm_ctx *ctx;
1951
1952         ctx = LDAP_MALLOC( sizeof (*ctx) );
1953         if ( ctx ) {
1954                 ctx->tc_refcnt = 1;
1955 #ifdef LDAP_R_COMPILE
1956                 ldap_pvt_thread_mutex_init( &ctx->tc_refmutex );
1957 #endif
1958                 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 */
1959                 ctx->tc_certdb = NULL;
1960                 ctx->tc_certname = NULL;
1961                 ctx->tc_pin_file = NULL;
1962                 ctx->tc_model = NULL;
1963                 memset(&ctx->tc_callonce, 0, sizeof(ctx->tc_callonce));
1964                 ctx->tc_require_cert = lo->ldo_tls_require_cert;
1965                 ctx->tc_verify_cert = PR_FALSE;
1966                 ctx->tc_using_pem = PR_FALSE;
1967                 ctx->tc_slotname = NULL;
1968 #ifdef HAVE_NSS_INITCONTEXT
1969                 ctx->tc_initctx = NULL;
1970 #endif /* HAVE_NSS_INITCONTEXT */
1971                 ctx->tc_pem_objs = NULL;
1972                 ctx->tc_n_pem_objs = 0;
1973                 ctx->tc_warn_only = PR_FALSE;
1974         }
1975         return (tls_ctx *)ctx;
1976 }
1977
1978 static void
1979 tlsm_ctx_ref( tls_ctx *ctx )
1980 {
1981         tlsm_ctx *c = (tlsm_ctx *)ctx;
1982         LDAP_MUTEX_LOCK( &c->tc_refmutex );
1983         c->tc_refcnt++;
1984         LDAP_MUTEX_UNLOCK( &c->tc_refmutex );
1985 }
1986
1987 static void
1988 tlsm_ctx_free ( tls_ctx *ctx )
1989 {
1990         tlsm_ctx *c = (tlsm_ctx *)ctx;
1991         int refcount;
1992
1993         if ( !c ) return;
1994
1995         LDAP_MUTEX_LOCK( &c->tc_refmutex );
1996         refcount = --c->tc_refcnt;
1997         LDAP_MUTEX_UNLOCK( &c->tc_refmutex );
1998         if ( refcount )
1999                 return;
2000         if ( c->tc_model )
2001                 PR_Close( c->tc_model );
2002         c->tc_certdb = NULL; /* if not the default, may have to clean up */
2003         PL_strfree( c->tc_certname );
2004         c->tc_certname = NULL;
2005         PL_strfree( c->tc_pin_file );
2006         c->tc_pin_file = NULL;
2007         PL_strfree( c->tc_slotname );           
2008         tlsm_free_pem_objs( c );
2009 #ifdef HAVE_NSS_INITCONTEXT
2010         if ( c->tc_initctx ) {
2011                 LDAP_MUTEX_LOCK( &tlsm_init_mutex );
2012                 if ( NSS_ShutdownContext( c->tc_initctx ) ) {
2013                         PRErrorCode errcode = PR_GetError();
2014                         Debug( LDAP_DEBUG_ANY,
2015                                    "TLS: could not shutdown NSS - error %d:%s.\n",
2016                                    errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
2017                 }
2018                 LDAP_MUTEX_UNLOCK( &tlsm_init_mutex );
2019         }
2020         c->tc_initctx = NULL;
2021 #endif /* HAVE_NSS_INITCONTEXT */
2022 #ifdef LDAP_R_COMPILE
2023         ldap_pvt_thread_mutex_destroy( &c->tc_refmutex );
2024 #endif
2025         LDAP_FREE( c );
2026 }
2027
2028 /*
2029  * initialize a new TLS context
2030  */
2031 static int
2032 tlsm_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server )
2033 {
2034         tlsm_ctx *ctx = (tlsm_ctx *)lo->ldo_tls_ctx;
2035         ctx->tc_is_server = is_server;
2036
2037         return 0;
2038 }
2039
2040 static int
2041 tlsm_deferred_ctx_init( void *arg )
2042 {
2043         tlsm_ctx *ctx = (tlsm_ctx *)arg;
2044         PRBool sslv2 = PR_FALSE;
2045         PRBool sslv3 = PR_TRUE;
2046         PRBool tlsv1 = PR_TRUE;
2047         PRBool request_cert = PR_FALSE;
2048         PRInt32 require_cert = PR_FALSE;
2049         PRFileDesc *fd;
2050         struct ldaptls *lt;
2051
2052         if ( tlsm_deferred_init( ctx ) ) {
2053             Debug( LDAP_DEBUG_ANY,
2054                            "TLS: could perform TLS system initialization.\n",
2055                            0, 0, 0 );
2056             return -1;
2057         }
2058
2059         ctx->tc_certdb = CERT_GetDefaultCertDB(); /* If there is ever a per-context db, change this */
2060
2061         fd = PR_CreateIOLayerStub( tlsm_layer_id, &tlsm_PR_methods );
2062         if ( fd ) {
2063                 ctx->tc_model = SSL_ImportFD( NULL, fd );
2064         }
2065
2066         if ( !ctx->tc_model ) {
2067                 PRErrorCode err = PR_GetError();
2068                 Debug( LDAP_DEBUG_ANY,
2069                            "TLS: could perform TLS socket I/O layer initialization - error %d:%s.\n",
2070                            err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
2071
2072                 if ( fd ) {
2073                         PR_Close( fd );
2074                 }
2075                 return -1;
2076         }
2077
2078         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_SECURITY, PR_TRUE ) ) {
2079                 Debug( LDAP_DEBUG_ANY,
2080                        "TLS: could not set secure mode on.\n",
2081                        0, 0, 0 );
2082                 return -1;
2083         }
2084
2085         lt = ctx->tc_config;
2086
2087         /* default is sslv3 and tlsv1 */
2088         if ( lt->lt_protocol_min ) {
2089                 if ( lt->lt_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_SSL3 ) {
2090                         sslv3 = PR_FALSE;
2091                 } else if ( lt->lt_protocol_min <= LDAP_OPT_X_TLS_PROTOCOL_SSL2 ) {
2092                         sslv2 = PR_TRUE;
2093                         Debug( LDAP_DEBUG_ANY,
2094                                "TLS: warning: minimum TLS protocol level set to "
2095                                "include SSLv2 - SSLv2 is insecure - do not use\n", 0, 0, 0 );
2096                 }
2097         }
2098         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_ENABLE_SSL2, sslv2 ) ) {
2099                 Debug( LDAP_DEBUG_ANY,
2100                        "TLS: could not set SSLv2 mode on.\n",
2101                        0, 0, 0 );
2102                 return -1;
2103         }
2104         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_ENABLE_SSL3, sslv3 ) ) {
2105                 Debug( LDAP_DEBUG_ANY,
2106                        "TLS: could not set SSLv3 mode on.\n",
2107                        0, 0, 0 );
2108                 return -1;
2109         }
2110         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_ENABLE_TLS, tlsv1 ) ) {
2111                 Debug( LDAP_DEBUG_ANY,
2112                        "TLS: could not set TLSv1 mode on.\n",
2113                        0, 0, 0 );
2114                 return -1;
2115         }
2116
2117         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_HANDSHAKE_AS_CLIENT, !ctx->tc_is_server ) ) {
2118                 Debug( LDAP_DEBUG_ANY,
2119                        "TLS: could not set handshake as client.\n",
2120                        0, 0, 0 );
2121                 return -1;
2122         }
2123         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_HANDSHAKE_AS_SERVER, ctx->tc_is_server ) ) {
2124                 Debug( LDAP_DEBUG_ANY,
2125                        "TLS: could not set handshake as server.\n",
2126                        0, 0, 0 );
2127                 return -1;
2128         }
2129
2130         if ( lt->lt_ciphersuite &&
2131              tlsm_parse_ciphers( ctx, lt->lt_ciphersuite )) {
2132                 Debug( LDAP_DEBUG_ANY,
2133                        "TLS: could not set cipher list %s.\n",
2134                        lt->lt_ciphersuite, 0, 0 );
2135                 return -1;
2136         } else if ( tlsm_parse_ciphers( ctx, "DEFAULT" ) ) {
2137                 Debug( LDAP_DEBUG_ANY,
2138                        "TLS: could not set cipher list DEFAULT.\n",
2139                        0, 0, 0 );
2140                 return -1;
2141         }
2142
2143         if ( !ctx->tc_require_cert ) {
2144                 ctx->tc_verify_cert = PR_FALSE;
2145         } else if ( !ctx->tc_is_server ) {
2146                 request_cert = PR_TRUE;
2147                 require_cert = SSL_REQUIRE_NO_ERROR;
2148                 if ( ctx->tc_require_cert == LDAP_OPT_X_TLS_DEMAND ||
2149                      ctx->tc_require_cert == LDAP_OPT_X_TLS_HARD ) {
2150                         require_cert = SSL_REQUIRE_ALWAYS;
2151                 }
2152                 if ( ctx->tc_require_cert != LDAP_OPT_X_TLS_ALLOW )
2153                         ctx->tc_verify_cert = PR_TRUE;
2154         } else { /* server */
2155                 /* server does not request certs by default */
2156                 /* if allow - client may send cert, server will ignore if errors */
2157                 /* if try - client may send cert, server will error if bad cert */
2158                 /* if hard or demand - client must send cert, server will error if bad cert */
2159                 request_cert = PR_TRUE;
2160                 require_cert = SSL_REQUIRE_NO_ERROR;
2161                 if ( ctx->tc_require_cert == LDAP_OPT_X_TLS_DEMAND ||
2162                      ctx->tc_require_cert == LDAP_OPT_X_TLS_HARD ) {
2163                         require_cert = SSL_REQUIRE_ALWAYS;
2164                 }
2165                 if ( ctx->tc_require_cert != LDAP_OPT_X_TLS_ALLOW ) {
2166                         ctx->tc_verify_cert = PR_TRUE;
2167                 } else {
2168                         ctx->tc_warn_only = PR_TRUE;
2169                 }
2170         }
2171
2172         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_REQUEST_CERTIFICATE, request_cert ) ) {
2173                 Debug( LDAP_DEBUG_ANY,
2174                        "TLS: could not set request certificate mode.\n",
2175                        0, 0, 0 );
2176                 return -1;
2177         }
2178                 
2179         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_REQUIRE_CERTIFICATE, require_cert ) ) {
2180                 Debug( LDAP_DEBUG_ANY,
2181                        "TLS: could not set require certificate mode.\n",
2182                        0, 0, 0 );
2183                 return -1;
2184         }
2185
2186         /* set up our cert and key, if any */
2187         if ( lt->lt_certfile ) {
2188                 /* if using the PEM module, load the PEM file specified by lt_certfile */
2189                 /* otherwise, assume this is the name of a cert already in the db */
2190                 if ( ctx->tc_using_pem ) {
2191                         /* this sets ctx->tc_certname to the correct value */
2192                         int rc = tlsm_add_cert_from_file( ctx, lt->lt_certfile, PR_FALSE, PR_TRUE );
2193                         if ( rc ) {
2194                                 return rc;
2195                         }
2196                 } else {
2197                         PL_strfree( ctx->tc_certname );
2198                         ctx->tc_certname = PL_strdup( lt->lt_certfile );
2199                 }
2200         }
2201
2202         if ( lt->lt_keyfile ) {
2203                 /* if using the PEM module, load the PEM file specified by lt_keyfile */
2204                 /* otherwise, assume this is the pininfo for the key */
2205                 if ( ctx->tc_using_pem ) {
2206                         /* this sets ctx->tc_certname to the correct value */
2207                         int rc = tlsm_add_key_from_file( ctx, lt->lt_keyfile );
2208                         if ( rc ) {
2209                                 return rc;
2210                         }
2211                 } else {
2212                         PL_strfree( ctx->tc_pin_file );
2213                         ctx->tc_pin_file = PL_strdup( lt->lt_keyfile );
2214                 }
2215         }
2216
2217         /* Set up callbacks for use by clients */
2218         if ( !ctx->tc_is_server ) {
2219                 if ( SSL_OptionSet( ctx->tc_model, SSL_NO_CACHE, PR_TRUE ) != SECSuccess ) {
2220                         PRErrorCode err = PR_GetError();
2221                         Debug( LDAP_DEBUG_ANY, 
2222                                "TLS: error: could not set nocache option for moznss - error %d:%s\n",
2223                                err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
2224                         return -1;
2225                 }
2226
2227                 if ( SSL_BadCertHook( ctx->tc_model, tlsm_bad_cert_handler, ctx ) != SECSuccess ) {
2228                         PRErrorCode err = PR_GetError();
2229                         Debug( LDAP_DEBUG_ANY, 
2230                                "TLS: error: could not set bad cert handler for moznss - error %d:%s\n",
2231                                err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
2232                         return -1;
2233                 }
2234
2235                 /* 
2236                    since a cert has been specified, assume the client wants to do cert auth
2237                 */
2238                 if ( ctx->tc_certname ) {
2239                         if ( tlsm_authenticate( ctx, ctx->tc_certname, ctx->tc_pin_file ) ) {
2240                                 Debug( LDAP_DEBUG_ANY, 
2241                                        "TLS: error: unable to authenticate to the security device for certificate %s\n",
2242                                        ctx->tc_certname, 0, 0 );
2243                                 return -1;
2244                         }
2245                         if ( tlsm_clientauth_init( ctx ) ) {
2246                                 Debug( LDAP_DEBUG_ANY, 
2247                                        "TLS: error: unable to set up client certificate authentication using %s\n",
2248                                        ctx->tc_certname, 0, 0 );
2249                                 return -1;
2250                         }
2251                 }
2252         } else { /* set up secure server */
2253                 SSLKEAType certKEA;
2254                 CERTCertificate *serverCert;
2255                 SECKEYPrivateKey *serverKey;
2256                 SECStatus status;
2257
2258                 /* must have a certificate for the server to use */
2259                 if ( !ctx->tc_certname ) {
2260                         Debug( LDAP_DEBUG_ANY, 
2261                                "TLS: error: no server certificate: must specify a certificate for the server to use\n",
2262                                0, 0, 0 );
2263                         return -1;
2264                 }
2265
2266                 /* authenticate to the server's token - this will do nothing
2267                    if the key/cert db is not password protected */
2268                 if ( tlsm_authenticate( ctx, ctx->tc_certname, ctx->tc_pin_file ) ) {
2269                         Debug( LDAP_DEBUG_ANY, 
2270                                "TLS: error: unable to authenticate to the security device for certificate %s\n",
2271                                ctx->tc_certname, 0, 0 );
2272                         return -1;
2273                 }
2274
2275                 /* get the server's key and cert */
2276                 if ( tlsm_find_and_verify_cert_key( ctx, ctx->tc_model, ctx->tc_certname, ctx->tc_is_server,
2277                                                     &serverCert, &serverKey ) ) {
2278                         Debug( LDAP_DEBUG_ANY, 
2279                                "TLS: error: unable to find and verify server's cert and key for certificate %s\n",
2280                                ctx->tc_certname, 0, 0 );
2281                         CERT_DestroyCertificate( serverCert );
2282                         SECKEY_DestroyPrivateKey( serverKey );
2283                         return -1;
2284                 }
2285
2286                 certKEA = NSS_FindCertKEAType( serverCert );
2287                 /* configure the socket to be a secure server socket */
2288                 status = SSL_ConfigSecureServer( ctx->tc_model, serverCert, serverKey, certKEA );
2289                 /* SSL_ConfigSecureServer copies these */
2290                 CERT_DestroyCertificate( serverCert );
2291                 SECKEY_DestroyPrivateKey( serverKey );
2292
2293                 if ( SECSuccess != status ) {
2294                         PRErrorCode err = PR_GetError();
2295                         Debug( LDAP_DEBUG_ANY, 
2296                                "TLS: error: unable to configure secure server using certificate %s - error %d:%s\n",
2297                                ctx->tc_certname, err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ) );
2298                         return -1;
2299                 }
2300         }
2301
2302         /* Callback for authenticating certificate */
2303         if ( SSL_AuthCertificateHook( ctx->tc_model, tlsm_auth_cert_handler,
2304                                   ctx ) != SECSuccess ) {
2305                 PRErrorCode err = PR_GetError();
2306                 Debug( LDAP_DEBUG_ANY, 
2307                        "TLS: error: could not set auth cert handler for moznss - error %d:%s\n",
2308                        err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
2309                 return -1;
2310         }
2311
2312         if ( SSL_HandshakeCallback( ctx->tc_model, tlsm_handshake_complete_cb, ctx ) ) {
2313                 PRErrorCode err = PR_GetError();
2314                 Debug( LDAP_DEBUG_ANY, 
2315                        "TLS: error: could not set handshake callback for moznss - error %d:%s\n",
2316                        err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
2317                 return -1;
2318         }
2319
2320         return 0;
2321 }
2322
2323 struct tls_data {
2324         tlsm_session            *session;
2325         Sockbuf_IO_Desc         *sbiod;
2326         /* there seems to be no portable way to determine if the
2327            sockbuf sd has been set to nonblocking mode - the
2328            call to ber_pvt_socket_set_nonblock() takes place
2329            before the tls socket is set up, so we cannot
2330            intercept that call either.
2331            On systems where fcntl is available, we can just
2332            F_GETFL and test for O_NONBLOCK.  On other systems,
2333            we will just see if the IO op returns EAGAIN or EWOULDBLOCK,
2334            and just set this flag */
2335         PRBool              nonblock;
2336         /*
2337          * NSS tries hard to be backwards compatible with SSLv2 clients, or
2338          * clients that send an SSLv2 client hello.  This message is not
2339          * tagged in any way, so NSS has no way to know if the incoming
2340          * message is a valid SSLv2 client hello or just some bogus data
2341          * (or cleartext LDAP).  We store the first byte read from the
2342          * client here.  The most common case will be a client sending
2343          * LDAP data instead of SSL encrypted LDAP data.  This can happen,
2344          * for example, if using ldapsearch -Z - if the starttls fails,
2345          * the client will fallback to plain cleartext LDAP.  So if we
2346          * see that the firstbyte is a valid LDAP tag, we can be
2347          * pretty sure this is happening.
2348          */
2349         ber_tag_t           firsttag;
2350         /*
2351          * NSS doesn't return SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE, etc.
2352          * when it is blocked, so we have to set a flag in the wrapped send
2353          * and recv calls that tells us what operation NSS was last blocked
2354          * on
2355          */
2356 #define TLSM_READ  1
2357 #define TLSM_WRITE 2
2358         int io_flag;
2359 };
2360
2361 static struct tls_data *
2362 tlsm_get_pvt_tls_data( PRFileDesc *fd )
2363 {
2364         struct tls_data         *p;
2365         PRFileDesc *myfd;
2366
2367         if ( !fd ) {
2368                 return NULL;
2369         }
2370
2371         myfd = PR_GetIdentitiesLayer( fd, tlsm_layer_id );
2372
2373         if ( !myfd ) {
2374                 return NULL;
2375         }
2376
2377         p = (struct tls_data *)myfd->secret;
2378
2379         return p;
2380 }
2381
2382 static int
2383 tlsm_is_non_ssl_message( PRFileDesc *fd, ber_tag_t *thebyte )
2384 {
2385         struct tls_data         *p;
2386
2387         if ( thebyte ) {
2388                 *thebyte = LBER_DEFAULT;
2389         }
2390
2391         p = tlsm_get_pvt_tls_data( fd );
2392         if ( p == NULL || p->sbiod == NULL ) {
2393                 return 0;
2394         }
2395
2396         if ( p->firsttag == LBER_SEQUENCE ) {
2397                 if ( thebyte ) {
2398                         *thebyte = p->firsttag;
2399                 }
2400                 return 1;
2401         }
2402
2403         return 0;
2404 }
2405
2406 static tls_session *
2407 tlsm_session_new ( tls_ctx * ctx, int is_server )
2408 {
2409         tlsm_ctx *c = (tlsm_ctx *)ctx;
2410         tlsm_session *session;
2411         PRFileDesc *fd;
2412         PRStatus status;
2413         int rc;
2414
2415         c->tc_is_server = is_server;
2416         status = PR_CallOnceWithArg( &c->tc_callonce, tlsm_deferred_ctx_init, c );
2417         if ( PR_SUCCESS != status ) {
2418                 PRErrorCode err = PR_GetError();
2419                 Debug( LDAP_DEBUG_ANY, 
2420                        "TLS: error: could not initialize moznss security context - error %d:%s\n",
2421                        err, PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT), NULL );
2422                 return NULL;
2423         }
2424
2425         fd = PR_CreateIOLayerStub( tlsm_layer_id, &tlsm_PR_methods );
2426         if ( !fd ) {
2427                 return NULL;
2428         }
2429
2430         session = SSL_ImportFD( c->tc_model, fd );
2431         if ( !session ) {
2432                 PR_DELETE( fd );
2433                 return NULL;
2434         }
2435
2436         if ( is_server ) {
2437                 /* 0 means use the defaults here */
2438                 SSL_ConfigServerSessionIDCache( 0, 0, 0, NULL );
2439         }
2440
2441         rc = SSL_ResetHandshake( session, is_server );
2442         if ( rc ) {
2443                 PRErrorCode err = PR_GetError();
2444                 Debug( LDAP_DEBUG_TRACE, 
2445                            "TLS: error: new session - reset handshake failure %d - error %d:%s\n",
2446                            rc, err,
2447                            err ? PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ) : "unknown" );
2448                 PR_DELETE( fd );
2449                 PR_Close( session );
2450                 session = NULL;
2451         }
2452
2453         return (tls_session *)session;
2454
2455
2456 static int
2457 tlsm_session_accept_or_connect( tls_session *session, int is_accept )
2458 {
2459         tlsm_session *s = (tlsm_session *)session;
2460         int rc = SSL_ForceHandshake( s );
2461         const char *op = is_accept ? "accept" : "connect";
2462
2463         if ( rc ) {
2464                 PRErrorCode err = PR_GetError();
2465                 rc = -1;
2466                 if ( err == PR_WOULD_BLOCK_ERROR ) {
2467                         ber_tag_t thetag = LBER_DEFAULT;
2468                         /* see if we are blocked because of a bogus packet */
2469                         if ( tlsm_is_non_ssl_message( s, &thetag ) ) { /* see if we received a non-SSL message */
2470                                 Debug( LDAP_DEBUG_ANY, 
2471                                            "TLS: error: %s - error - received non-SSL message [0x%x]\n",
2472                                            op, (unsigned int)thetag, 0 );
2473                                 /* reset error to something more descriptive */
2474                                 PR_SetError( SSL_ERROR_RX_MALFORMED_HELLO_REQUEST, EPROTO );
2475                         }
2476                 } else {
2477                         Debug( LDAP_DEBUG_ANY, 
2478                                    "TLS: error: %s - force handshake failure: errno %d - moznss error %d\n",
2479                                    op, errno, err );
2480                 }
2481         }
2482
2483         return rc;
2484 }
2485 static int
2486 tlsm_session_accept( tls_session *session )
2487 {
2488         return tlsm_session_accept_or_connect( session, 1 );
2489 }
2490
2491 static int
2492 tlsm_session_connect( LDAP *ld, tls_session *session )
2493 {
2494         return tlsm_session_accept_or_connect( session, 0 );
2495 }
2496
2497 static int
2498 tlsm_session_upflags( Sockbuf *sb, tls_session *session, int rc )
2499 {
2500         int prerror = PR_GetError();
2501
2502         if ( ( prerror == PR_PENDING_INTERRUPT_ERROR ) || ( prerror == PR_WOULD_BLOCK_ERROR ) ) {
2503                 tlsm_session *s = (tlsm_session *)session;
2504                 struct tls_data *p = tlsm_get_pvt_tls_data( s );
2505
2506                 if ( p && ( p->io_flag == TLSM_READ ) ) {
2507                         sb->sb_trans_needs_read = 1;
2508                         return 1;
2509                 } else if ( p && ( p->io_flag == TLSM_WRITE ) ) {
2510                         sb->sb_trans_needs_write = 1;
2511                         return 1;
2512                 }
2513         }
2514
2515         return 0;
2516 }
2517
2518 static char *
2519 tlsm_session_errmsg( tls_session *sess, int rc, char *buf, size_t len )
2520 {
2521         int i;
2522         int prerror = PR_GetError();
2523
2524         i = PR_GetErrorTextLength();
2525         if ( i > len ) {
2526                 char *msg = LDAP_MALLOC( i+1 );
2527                 PR_GetErrorText( msg );
2528                 memcpy( buf, msg, len );
2529                 LDAP_FREE( msg );
2530         } else if ( i ) {
2531                 PR_GetErrorText( buf );
2532         } else if ( prerror ) {
2533                 i = PR_snprintf( buf, len, "TLS error %d:%s",
2534                                                  prerror, PR_ErrorToString( prerror, PR_LANGUAGE_I_DEFAULT ) );
2535         }
2536
2537         return ( i > 0 ) ? buf : NULL;
2538 }
2539
2540 static int
2541 tlsm_session_my_dn( tls_session *session, struct berval *der_dn )
2542 {
2543         tlsm_session *s = (tlsm_session *)session;
2544         CERTCertificate *cert;
2545
2546         cert = SSL_LocalCertificate( s );
2547         if (!cert) return LDAP_INVALID_CREDENTIALS;
2548
2549         der_dn->bv_val = (char *)cert->derSubject.data;
2550         der_dn->bv_len = cert->derSubject.len;
2551         CERT_DestroyCertificate( cert );
2552         return 0;
2553 }
2554
2555 static int
2556 tlsm_session_peer_dn( tls_session *session, struct berval *der_dn )
2557 {
2558         tlsm_session *s = (tlsm_session *)session;
2559         CERTCertificate *cert;
2560
2561         cert = SSL_PeerCertificate( s );
2562         if (!cert) return LDAP_INVALID_CREDENTIALS;
2563         
2564         der_dn->bv_val = (char *)cert->derSubject.data;
2565         der_dn->bv_len = cert->derSubject.len;
2566         CERT_DestroyCertificate( cert );
2567         return 0;
2568 }
2569
2570 /* what kind of hostname were we given? */
2571 #define IS_DNS  0
2572 #define IS_IP4  1
2573 #define IS_IP6  2
2574
2575 static int
2576 tlsm_session_chkhost( LDAP *ld, tls_session *session, const char *name_in )
2577 {
2578         tlsm_session *s = (tlsm_session *)session;
2579         CERTCertificate *cert;
2580         const char *name, *domain = NULL, *ptr;
2581         int ret, ntype = IS_DNS, nlen, dlen;
2582 #ifdef LDAP_PF_INET6
2583         struct in6_addr addr;
2584 #else
2585         struct in_addr addr;
2586 #endif
2587         SECItem altname;
2588         SECStatus rv;
2589
2590         if( ldap_int_hostname &&
2591                 ( !name_in || !strcasecmp( name_in, "localhost" ) ) )
2592         {
2593                 name = ldap_int_hostname;
2594         } else {
2595                 name = name_in;
2596         }
2597         nlen = strlen( name );
2598
2599         cert = SSL_PeerCertificate( s );
2600         if (!cert) {
2601                 Debug( LDAP_DEBUG_ANY,
2602                         "TLS: unable to get peer certificate.\n",
2603                         0, 0, 0 );
2604                 /* if this was a fatal condition, things would have
2605                  * aborted long before now.
2606                  */
2607                 return LDAP_SUCCESS;
2608         }
2609
2610 #ifdef LDAP_PF_INET6
2611         if (name[0] == '[' && strchr(name, ']')) {
2612                 char *n2 = ldap_strdup(name+1);
2613                 *strchr(n2, ']') = 0;
2614                 if (inet_pton(AF_INET6, n2, &addr))
2615                         ntype = IS_IP6;
2616                 LDAP_FREE(n2);
2617         } else 
2618 #endif
2619         if ((ptr = strrchr(name, '.')) && isdigit((unsigned char)ptr[1])) {
2620                 if (inet_aton(name, (struct in_addr *)&addr)) ntype = IS_IP4;
2621         }
2622         if (ntype == IS_DNS ) {
2623                 domain = strchr( name, '.' );
2624                 if ( domain )
2625                         dlen = nlen - ( domain - name );
2626         }
2627
2628         ret = LDAP_LOCAL_ERROR;
2629
2630         rv = CERT_FindCertExtension( cert, SEC_OID_X509_SUBJECT_ALT_NAME,
2631                 &altname );
2632         if ( rv == SECSuccess && altname.data ) {
2633                 PRArenaPool *arena;
2634                 CERTGeneralName *names, *cur;
2635
2636                 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2637                 if ( !arena ) {
2638                         ret = LDAP_NO_MEMORY;
2639                         goto fail;
2640                 }
2641
2642                 names = cur = CERT_DecodeAltNameExtension(arena, &altname);
2643                 if ( !cur )
2644                         goto altfail;
2645
2646                 do {
2647                         char *host;
2648                         int hlen;
2649
2650                         /* ignore empty */
2651                         if ( !cur->name.other.len ) continue;
2652
2653                         host = (char *)cur->name.other.data;
2654                         hlen = cur->name.other.len;
2655
2656                         if ( cur->type == certDNSName ) {
2657                                 if ( ntype != IS_DNS )  continue;
2658
2659                                 /* is this an exact match? */
2660                                 if ( nlen == hlen && !strncasecmp( name, host, nlen )) {
2661                                         ret = LDAP_SUCCESS;
2662                                         break;
2663                                 }
2664
2665                                 /* is this a wildcard match? */
2666                                 if ( domain && host[0] == '*' && host[1] == '.' &&
2667                                         dlen == hlen-1 && !strncasecmp( domain, host+1, dlen )) {
2668                                         ret = LDAP_SUCCESS;
2669                                         break;
2670                                 }
2671                         } else if ( cur->type == certIPAddress ) {
2672                                 if ( ntype == IS_DNS )  continue;
2673                                 
2674 #ifdef LDAP_PF_INET6
2675                                 if (ntype == IS_IP6 && hlen != sizeof(struct in6_addr)) {
2676                                         continue;
2677                                 } else
2678 #endif
2679                                 if (ntype == IS_IP4 && hlen != sizeof(struct in_addr)) {
2680                                         continue;
2681                                 }
2682                                 if (!memcmp(host, &addr, hlen)) {
2683                                         ret = LDAP_SUCCESS;
2684                                         break;
2685                                 }
2686                         }
2687                 } while (( cur = CERT_GetNextGeneralName( cur )) != names );
2688 altfail:
2689                 PORT_FreeArena( arena, PR_FALSE );
2690                 SECITEM_FreeItem( &altname, PR_FALSE );
2691         }
2692         /* no altnames matched, try the CN */
2693         if ( ret != LDAP_SUCCESS ) {
2694                 /* find the last CN */
2695                 CERTRDN *rdn, **rdns;
2696                 CERTAVA *lastava = NULL;
2697                 char buf[2048];
2698
2699                 buf[0] = '\0';
2700                 rdns = cert->subject.rdns;
2701                 while ( rdns && ( rdn = *rdns++ )) {
2702                         CERTAVA *ava, **avas = rdn->avas;
2703                         while ( avas && ( ava = *avas++ )) {
2704                                 if ( CERT_GetAVATag( ava ) == SEC_OID_AVA_COMMON_NAME )
2705                                         lastava = ava;
2706                         }
2707                 }
2708                 if ( lastava ) {
2709                         SECItem *av = CERT_DecodeAVAValue( &lastava->value );
2710                         if ( av ) {
2711                                 if ( av->len == nlen && !strncasecmp( name, (char *)av->data, nlen )) {
2712                                         ret = LDAP_SUCCESS;
2713                                 } else if ( av->data[0] == '*' && av->data[1] == '.' &&
2714                                         domain && dlen == av->len - 1 && !strncasecmp( name,
2715                                                 (char *)(av->data+1), dlen )) {
2716                                         ret = LDAP_SUCCESS;
2717                                 } else {
2718                                         int len = av->len;
2719                                         if ( len >= sizeof(buf) )
2720                                                 len = sizeof(buf)-1;
2721                                         memcpy( buf, av->data, len );
2722                                         buf[len] = '\0';
2723                                 }
2724                                 SECITEM_FreeItem( av, PR_TRUE );
2725                         }
2726                 }
2727                 if ( ret != LDAP_SUCCESS ) {
2728                         Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match "
2729                                 "common name in certificate (%s).\n", 
2730                                 name, buf, 0 );
2731                         ret = LDAP_CONNECT_ERROR;
2732                         if ( ld->ld_error ) {
2733                                 LDAP_FREE( ld->ld_error );
2734                         }
2735                         ld->ld_error = LDAP_STRDUP(
2736                                 _("TLS: hostname does not match CN in peer certificate"));
2737                 }
2738         }
2739
2740 fail:
2741         CERT_DestroyCertificate( cert );
2742         return ret;
2743 }
2744
2745 static int
2746 tlsm_session_strength( tls_session *session )
2747 {
2748         tlsm_session *s = (tlsm_session *)session;
2749         int rc, keySize;
2750
2751         rc = SSL_SecurityStatus( s, NULL, NULL, NULL, &keySize,
2752                 NULL, NULL );
2753         return rc ? 0 : keySize;
2754 }
2755
2756 /*
2757  * TLS support for LBER Sockbufs
2758  */
2759
2760 static PRStatus PR_CALLBACK
2761 tlsm_PR_Close(PRFileDesc *fd)
2762 {
2763         int rc = PR_SUCCESS;
2764
2765         /* we don't need to actually close anything here, just
2766            pop our io layer off the stack */
2767         fd->secret = NULL; /* must have been freed before calling PR_Close */
2768         if ( fd->lower ) {
2769                 fd = PR_PopIOLayer( fd, tlsm_layer_id );
2770                 /* if we are not the last layer, pass the close along */
2771                 if ( fd ) {
2772                         if ( fd->dtor ) {
2773                                 fd->dtor( fd );
2774                         }
2775                         rc = fd->methods->close( fd );
2776                 }
2777         } else {
2778                 /* we are the last layer - just call our dtor */
2779                 fd->dtor(fd);
2780         }
2781
2782         return rc;
2783 }
2784
2785 static PRStatus PR_CALLBACK
2786 tlsm_PR_Shutdown(PRFileDesc *fd, PRShutdownHow how)
2787 {
2788         int rc = PR_SUCCESS;
2789
2790         if ( fd->lower ) {
2791                 rc = PR_Shutdown( fd->lower, how );
2792         }
2793
2794         return rc;
2795 }
2796
2797 static int PR_CALLBACK
2798 tlsm_PR_Recv(PRFileDesc *fd, void *buf, PRInt32 len, PRIntn flags,
2799          PRIntervalTime timeout)
2800 {
2801         struct tls_data         *p;
2802         int rc;
2803
2804         if ( buf == NULL || len <= 0 ) return 0;
2805
2806         p = tlsm_get_pvt_tls_data( fd );
2807
2808         if ( p == NULL || p->sbiod == NULL ) {
2809                 return 0;
2810         }
2811
2812         rc = LBER_SBIOD_READ_NEXT( p->sbiod, buf, len );
2813         if (rc <= 0) {
2814                 tlsm_map_error( errno );
2815                 if ( errno == EAGAIN || errno == EWOULDBLOCK ) {
2816                         p->nonblock = PR_TRUE; /* fd is using non-blocking io */
2817                 } else if ( errno ) { /* real error */
2818                         Debug( LDAP_DEBUG_TRACE, 
2819                                "TLS: error: tlsm_PR_Recv returned %d - error %d:%s\n",
2820                                rc, errno, STRERROR(errno) );
2821                 }
2822         } else if ( ( rc > 0 ) && ( len > 0 ) && ( p->firsttag == LBER_DEFAULT ) ) {
2823                 p->firsttag = (ber_tag_t)*((char *)buf);
2824         }
2825         p->io_flag = TLSM_READ;
2826
2827         return rc;
2828 }
2829
2830 static int PR_CALLBACK
2831 tlsm_PR_Send(PRFileDesc *fd, const void *buf, PRInt32 len, PRIntn flags,
2832          PRIntervalTime timeout)
2833 {
2834         struct tls_data         *p;
2835         int rc;
2836
2837         if ( buf == NULL || len <= 0 ) return 0;
2838
2839         p = tlsm_get_pvt_tls_data( fd );
2840
2841         if ( p == NULL || p->sbiod == NULL ) {
2842                 return 0;
2843         }
2844
2845         rc = LBER_SBIOD_WRITE_NEXT( p->sbiod, (char *)buf, len );
2846         if (rc <= 0) {
2847                 tlsm_map_error( errno );
2848                 if ( errno == EAGAIN || errno == EWOULDBLOCK ) {
2849                         p->nonblock = PR_TRUE;
2850                 } else if ( errno ) { /* real error */
2851                         Debug( LDAP_DEBUG_TRACE, 
2852                                "TLS: error: tlsm_PR_Send returned %d - error %d:%s\n",
2853                                rc, errno, STRERROR(errno) );
2854                 }
2855         }
2856         p->io_flag = TLSM_WRITE;
2857
2858         return rc;
2859 }
2860
2861 static int PR_CALLBACK
2862 tlsm_PR_Read(PRFileDesc *fd, void *buf, PRInt32 len)
2863 {
2864         return tlsm_PR_Recv( fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
2865 }
2866
2867 static int PR_CALLBACK
2868 tlsm_PR_Write(PRFileDesc *fd, const void *buf, PRInt32 len)
2869 {
2870         return tlsm_PR_Send( fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
2871 }
2872
2873 static PRStatus PR_CALLBACK
2874 tlsm_PR_GetPeerName(PRFileDesc *fd, PRNetAddr *addr)
2875 {
2876         struct tls_data         *p;
2877         ber_socklen_t len;
2878
2879         p = tlsm_get_pvt_tls_data( fd );
2880
2881         if ( p == NULL || p->sbiod == NULL ) {
2882                 return PR_FAILURE;
2883         }
2884         len = sizeof(PRNetAddr);
2885         return getpeername( p->sbiod->sbiod_sb->sb_fd, (struct sockaddr *)addr, &len );
2886 }
2887
2888 static PRStatus PR_CALLBACK
2889 tlsm_PR_GetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
2890 {
2891         struct tls_data         *p;
2892         p = tlsm_get_pvt_tls_data( fd );
2893
2894         if ( p == NULL || data == NULL ) {
2895                 return PR_FAILURE;
2896         }
2897
2898         /* only the nonblocking option is supported at this time
2899            MozNSS SSL code needs it */
2900         if ( data->option != PR_SockOpt_Nonblocking ) {
2901                 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2902                 return PR_FAILURE;
2903         }
2904 #ifdef HAVE_FCNTL
2905         int flags = fcntl( p->sbiod->sbiod_sb->sb_fd, F_GETFL );
2906         data->value.non_blocking = (flags & O_NONBLOCK) ? PR_TRUE : PR_FALSE;           
2907 #else /* punt :P */
2908         data->value.non_blocking = p->nonblock;
2909 #endif
2910         return PR_SUCCESS;
2911 }
2912
2913 static PRStatus PR_CALLBACK
2914 tlsm_PR_prs_unimp()
2915 {
2916     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2917     return PR_FAILURE;
2918 }
2919
2920 static PRFileDesc * PR_CALLBACK
2921 tlsm_PR_pfd_unimp()
2922 {
2923     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2924     return NULL;
2925 }
2926
2927 static PRInt16 PR_CALLBACK
2928 tlsm_PR_i16_unimp()
2929 {
2930     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2931     return SECFailure;
2932 }
2933
2934 static PRInt32 PR_CALLBACK
2935 tlsm_PR_i32_unimp()
2936 {
2937     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2938     return SECFailure;
2939 }
2940
2941 static PRInt64 PR_CALLBACK
2942 tlsm_PR_i64_unimp()
2943 {
2944     PRInt64 res;
2945
2946     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2947     LL_I2L(res, -1L);
2948     return res;
2949 }
2950
2951 static const PRIOMethods tlsm_PR_methods = {
2952     PR_DESC_LAYERED,
2953     tlsm_PR_Close,                      /* close        */
2954     tlsm_PR_Read,                       /* read         */
2955     tlsm_PR_Write,                      /* write        */
2956     tlsm_PR_i32_unimp,          /* available    */
2957     tlsm_PR_i64_unimp,          /* available64  */
2958     tlsm_PR_prs_unimp,          /* fsync        */
2959     tlsm_PR_i32_unimp,          /* seek         */
2960     tlsm_PR_i64_unimp,          /* seek64       */
2961     tlsm_PR_prs_unimp,          /* fileInfo     */
2962     tlsm_PR_prs_unimp,          /* fileInfo64   */
2963     tlsm_PR_i32_unimp,          /* writev       */
2964     tlsm_PR_prs_unimp,          /* connect      */
2965     tlsm_PR_pfd_unimp,          /* accept       */
2966     tlsm_PR_prs_unimp,          /* bind         */
2967     tlsm_PR_prs_unimp,          /* listen       */
2968     (PRShutdownFN)tlsm_PR_Shutdown,                     /* shutdown     */
2969     tlsm_PR_Recv,                       /* recv         */
2970     tlsm_PR_Send,                       /* send         */
2971     tlsm_PR_i32_unimp,          /* recvfrom     */
2972     tlsm_PR_i32_unimp,          /* sendto       */
2973     (PRPollFN)tlsm_PR_i16_unimp,        /* poll         */
2974     tlsm_PR_i32_unimp,          /* acceptread   */
2975     tlsm_PR_i32_unimp,          /* transmitfile */
2976     tlsm_PR_prs_unimp,          /* getsockname  */
2977     tlsm_PR_GetPeerName,        /* getpeername  */
2978     tlsm_PR_i32_unimp,          /* getsockopt   OBSOLETE */
2979     tlsm_PR_i32_unimp,          /* setsockopt   OBSOLETE */
2980     tlsm_PR_GetSocketOption,            /* getsocketoption   */
2981     tlsm_PR_i32_unimp,          /* setsocketoption   */
2982     tlsm_PR_i32_unimp,          /* Send a (partial) file with header/trailer*/
2983     (PRConnectcontinueFN)tlsm_PR_prs_unimp,             /* connectcontinue */
2984     tlsm_PR_i32_unimp,          /* reserved for future use */
2985     tlsm_PR_i32_unimp,          /* reserved for future use */
2986     tlsm_PR_i32_unimp,          /* reserved for future use */
2987     tlsm_PR_i32_unimp           /* reserved for future use */
2988 };
2989
2990 /*
2991  * Initialize TLS subsystem. Should be called only once.
2992  * See tlsm_deferred_init for the bulk of the init process
2993  */
2994 static int
2995 tlsm_init( void )
2996 {
2997         char *nofork = PR_GetEnv( "NSS_STRICT_NOFORK" );
2998
2999         PR_Init(0, 0, 0);
3000
3001         tlsm_layer_id = PR_GetUniqueIdentity( "OpenLDAP" );
3002
3003         /*
3004          * There are some applications that acquire a crypto context in the parent process
3005          * and expect that crypto context to work after a fork().  This does not work
3006          * with NSS using strict PKCS11 compliance mode.  We set this environment
3007          * variable here to tell the software encryption module/token to allow crypto
3008          * contexts to persist across a fork().  However, if you are using some other
3009          * module or encryption device that supports and expects full PKCS11 semantics,
3010          * the only recourse is to rewrite the application with atfork() handlers to save
3011          * the crypto context in the parent and restore (and SECMOD_RestartModules) the
3012          * context in the child.
3013          */
3014         if ( !nofork ) {
3015                 /* will leak one time */
3016                 char *noforkenvvar = PL_strdup( "NSS_STRICT_NOFORK=DISABLED" );
3017                 PR_SetEnv( noforkenvvar );
3018         }
3019
3020         return 0;
3021 }
3022
3023 static int
3024 tlsm_sb_setup( Sockbuf_IO_Desc *sbiod, void *arg )
3025 {
3026         struct tls_data         *p;
3027         tlsm_session    *session = arg;
3028         PRFileDesc *fd;
3029
3030         assert( sbiod != NULL );
3031
3032         p = LBER_MALLOC( sizeof( *p ) );
3033         if ( p == NULL ) {
3034                 return -1;
3035         }
3036
3037         fd = PR_GetIdentitiesLayer( session, tlsm_layer_id );
3038         if ( !fd ) {
3039                 LBER_FREE( p );
3040                 return -1;
3041         }
3042
3043         fd->secret = (PRFilePrivate *)p;
3044         p->session = session;
3045         p->sbiod = sbiod;
3046         p->firsttag = LBER_DEFAULT;
3047         sbiod->sbiod_pvt = p;
3048         return 0;
3049 }
3050
3051 static int
3052 tlsm_sb_remove( Sockbuf_IO_Desc *sbiod )
3053 {
3054         struct tls_data         *p;
3055         
3056         assert( sbiod != NULL );
3057         assert( sbiod->sbiod_pvt != NULL );
3058
3059         p = (struct tls_data *)sbiod->sbiod_pvt;
3060         PR_Close( p->session );
3061         LBER_FREE( sbiod->sbiod_pvt );
3062         sbiod->sbiod_pvt = NULL;
3063         return 0;
3064 }
3065
3066 static int
3067 tlsm_sb_close( Sockbuf_IO_Desc *sbiod )
3068 {
3069         struct tls_data         *p;
3070         
3071         assert( sbiod != NULL );
3072         assert( sbiod->sbiod_pvt != NULL );
3073
3074         p = (struct tls_data *)sbiod->sbiod_pvt;
3075         PR_Shutdown( p->session, PR_SHUTDOWN_BOTH );
3076         return 0;
3077 }
3078
3079 static int
3080 tlsm_sb_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
3081 {
3082         struct tls_data         *p;
3083         
3084         assert( sbiod != NULL );
3085         assert( sbiod->sbiod_pvt != NULL );
3086
3087         p = (struct tls_data *)sbiod->sbiod_pvt;
3088         
3089         if ( opt == LBER_SB_OPT_GET_SSL ) {
3090                 *((tlsm_session **)arg) = p->session;
3091                 return 1;
3092                 
3093         } else if ( opt == LBER_SB_OPT_DATA_READY ) {
3094                 if ( p && ( SSL_DataPending( p->session ) > 0 ) ) {
3095                         return 1;
3096                 }
3097                 
3098         }
3099         
3100         return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
3101 }
3102
3103 static ber_slen_t
3104 tlsm_sb_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
3105 {
3106         struct tls_data         *p;
3107         ber_slen_t              ret;
3108         int                     err;
3109
3110         assert( sbiod != NULL );
3111         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
3112
3113         p = (struct tls_data *)sbiod->sbiod_pvt;
3114
3115         ret = PR_Recv( p->session, buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
3116         if ( ret < 0 ) {
3117                 err = PR_GetError();
3118                 if ( err == PR_PENDING_INTERRUPT_ERROR || err == PR_WOULD_BLOCK_ERROR ) {
3119                         sbiod->sbiod_sb->sb_trans_needs_read = 1;
3120                         sock_errset(EWOULDBLOCK);
3121                 }
3122         } else {
3123                 sbiod->sbiod_sb->sb_trans_needs_read = 0;
3124         }
3125         return ret;
3126 }
3127
3128 static ber_slen_t
3129 tlsm_sb_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
3130 {
3131         struct tls_data         *p;
3132         ber_slen_t              ret;
3133         int                     err;
3134
3135         assert( sbiod != NULL );
3136         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
3137
3138         p = (struct tls_data *)sbiod->sbiod_pvt;
3139
3140         ret = PR_Send( p->session, (char *)buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
3141         if ( ret < 0 ) {
3142                 err = PR_GetError();
3143                 if ( err == PR_PENDING_INTERRUPT_ERROR || err == PR_WOULD_BLOCK_ERROR ) {
3144                         sbiod->sbiod_sb->sb_trans_needs_write = 1;
3145                         sock_errset(EWOULDBLOCK);
3146                         ret = 0;
3147                 }
3148         } else {
3149                 sbiod->sbiod_sb->sb_trans_needs_write = 0;
3150         }
3151         return ret;
3152 }
3153
3154 static Sockbuf_IO tlsm_sbio =
3155 {
3156         tlsm_sb_setup,          /* sbi_setup */
3157         tlsm_sb_remove,         /* sbi_remove */
3158         tlsm_sb_ctrl,           /* sbi_ctrl */
3159         tlsm_sb_read,           /* sbi_read */
3160         tlsm_sb_write,          /* sbi_write */
3161         tlsm_sb_close           /* sbi_close */
3162 };
3163
3164 tls_impl ldap_int_tls_impl = {
3165         "MozNSS",
3166
3167         tlsm_init,
3168         tlsm_destroy,
3169
3170         tlsm_ctx_new,
3171         tlsm_ctx_ref,
3172         tlsm_ctx_free,
3173         tlsm_ctx_init,
3174
3175         tlsm_session_new,
3176         tlsm_session_connect,
3177         tlsm_session_accept,
3178         tlsm_session_upflags,
3179         tlsm_session_errmsg,
3180         tlsm_session_my_dn,
3181         tlsm_session_peer_dn,
3182         tlsm_session_chkhost,
3183         tlsm_session_strength,
3184
3185         &tlsm_sbio,
3186
3187 #ifdef LDAP_R_COMPILE
3188         tlsm_thr_init,
3189 #else
3190         NULL,
3191 #endif
3192
3193         0
3194 };
3195
3196 #endif /* HAVE_MOZNSS */
3197 /*
3198   emacs settings
3199   Local Variables:
3200   indent-tabs-mode: t
3201   tab-width: 4
3202   End:
3203 */