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