]> git.sur5r.net Git - openldap/blob - libraries/libldap/tls_m.c
32af7ec7c0a87d4613b9018d830fa8bfa90e0f4d
[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         CERTCertificate *peercert = SSL_PeerCertificate( fd );
1034
1035         ret = tlsm_verify_cert( (CERTCertDBHandle *)arg, peercert,
1036                                                         SSL_RevealPinArg( fd ),
1037                                                         checksig, certUsage, 0 );
1038         CERT_DestroyCertificate( peercert );
1039
1040         return ret;
1041 }
1042
1043 static int
1044 tlsm_authenticate_to_slot( tlsm_ctx *ctx, PK11SlotInfo *slot )
1045 {
1046         int rc = -1;
1047
1048         if ( SECSuccess != PK11_Authenticate( slot, PR_FALSE, ctx ) ) {
1049                 char *token_name = PK11_GetTokenName( slot );
1050                 PRErrorCode errcode = PR_GetError();
1051                 Debug( LDAP_DEBUG_ANY,
1052                            "TLS: could not authenticate to the security token %s - error %d:%s.\n",
1053                            token_name ? token_name : DEFAULT_TOKEN_NAME, errcode,
1054                            PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1055         } else {
1056                 rc = 0; /* success */
1057         }
1058
1059         return rc;
1060 }
1061
1062 static SECStatus
1063 tlsm_nss_shutdown_cb( void *appData, void *nssData )
1064 {
1065         SECStatus rc = SECSuccess;
1066
1067         SSL_ShutdownServerSessionIDCache();
1068         SSL_ClearSessionCache();
1069
1070         if ( pem_module ) {
1071                 SECMOD_UnloadUserModule( pem_module );
1072                 SECMOD_DestroyModule( pem_module );
1073                 pem_module = NULL;
1074         }
1075         return rc;
1076 }
1077
1078 static int
1079 tlsm_init_pem_module( void )
1080 {
1081         int rc = 0;
1082         char *fullname = NULL;
1083         char *configstring = NULL;
1084
1085         if ( pem_module ) {
1086                 return rc;
1087         }
1088
1089         /* not loaded - load it */
1090         /* get the system dependent library name */
1091         fullname = PR_GetLibraryName( NULL, PEM_LIBRARY );
1092         /* Load our PKCS#11 module */
1093         configstring = PR_smprintf( "library=%s name=" PEM_MODULE " parameters=\"\"", fullname );
1094         PL_strfree( fullname );
1095
1096         pem_module = SECMOD_LoadUserModule( configstring, NULL, PR_FALSE );
1097         PR_smprintf_free( configstring );
1098
1099         if ( !pem_module || !pem_module->loaded ) {
1100                 if ( pem_module ) {
1101                         SECMOD_DestroyModule( pem_module );
1102                         pem_module = NULL;
1103                 }
1104                 rc = -1;
1105         }
1106
1107         return rc;
1108 }
1109
1110 static void
1111 tlsm_add_pem_obj( tlsm_ctx *ctx, PK11GenericObject *obj )
1112 {
1113         int idx = ctx->tc_n_pem_objs;
1114         ctx->tc_n_pem_objs++;
1115         ctx->tc_pem_objs = (PK11GenericObject **)
1116                 PORT_Realloc( ctx->tc_pem_objs, ctx->tc_n_pem_objs * sizeof( PK11GenericObject * ) );
1117         ctx->tc_pem_objs[idx] = obj;                                                                                                              
1118 }
1119
1120 static void
1121 tlsm_free_pem_objs( tlsm_ctx *ctx )
1122 {
1123         /* free in reverse order of allocation */
1124         while ( ctx->tc_n_pem_objs-- ) {
1125                 PK11_DestroyGenericObject( ctx->tc_pem_objs[ctx->tc_n_pem_objs] );
1126                 ctx->tc_pem_objs[ctx->tc_n_pem_objs] = NULL;
1127         }
1128         PORT_Free(ctx->tc_pem_objs);
1129         ctx->tc_pem_objs = NULL;
1130         ctx->tc_n_pem_objs = 0;
1131 }
1132
1133 static int
1134 tlsm_add_cert_from_file( tlsm_ctx *ctx, const char *filename, PRBool isca, PRBool istrusted )
1135 {
1136         CK_SLOT_ID slotID;
1137         PK11SlotInfo *slot = NULL;
1138         PK11GenericObject *rv;
1139         CK_ATTRIBUTE *attrs;
1140         CK_ATTRIBUTE theTemplate[20];
1141         CK_BBOOL cktrue = CK_TRUE;
1142         CK_BBOOL ckfalse = CK_FALSE;
1143         CK_OBJECT_CLASS objClass = CKO_CERTIFICATE;
1144         char tmpslotname[64];
1145         char *slotname = NULL;
1146         const char *ptr = NULL;
1147         char sep = PR_GetDirectorySeparator();
1148         PRFileInfo fi;
1149         PRStatus status;
1150
1151         memset( &fi, 0, sizeof(fi) );
1152         status = PR_GetFileInfo( filename, &fi );
1153         if ( PR_SUCCESS != status) {
1154                 PRErrorCode errcode = PR_GetError();
1155                 Debug( LDAP_DEBUG_ANY,
1156                            "TLS: could not read certificate file %s - error %d:%s.\n",
1157                            filename, errcode,
1158                            PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1159                 return -1;
1160         }
1161
1162         if ( fi.type != PR_FILE_FILE ) {
1163                 PR_SetError(PR_IS_DIRECTORY_ERROR, 0);
1164                 Debug( LDAP_DEBUG_ANY,
1165                            "TLS: error: the certificate file %s is not a file.\n",
1166                            filename, 0 ,0 );
1167                 return -1;
1168         }
1169
1170         attrs = theTemplate;
1171
1172         if ( isca ) {
1173                 slotID = 0; /* CA and trust objects use slot 0 */
1174                 PR_snprintf( tmpslotname, sizeof(tmpslotname), TLSM_PEM_TOKEN_FMT, slotID );
1175                 slotname = tmpslotname;
1176                 istrusted = PR_TRUE;
1177         } else {
1178                 if ( ctx->tc_slotname == NULL ) { /* need new slot */
1179                         if ( istrusted ) {
1180                                 slotID = 0;
1181                         } else {
1182                                 slotID = ++tlsm_slot_count;
1183                         }
1184                         ctx->tc_slotname = PR_smprintf( TLSM_PEM_TOKEN_FMT, slotID );
1185                 }
1186                 slotname = ctx->tc_slotname;
1187
1188                 if ( ( ptr = PL_strrchr( filename, sep ) ) ) {
1189                         PL_strfree( ctx->tc_certname );
1190                         ++ptr;
1191                         if ( istrusted ) {
1192                                 /* pemnss conflates trusted certs with CA certs - since there can
1193                                    be more than one CA cert in a file (e.g. ca-bundle.crt) pemnss
1194                                    numbers each trusted cert - in the case of a server cert, there will be
1195                                    only one, so it will be number 0 */
1196                                 ctx->tc_certname = PR_smprintf( "%s:%s - 0", slotname, ptr );
1197                         } else {
1198                                 ctx->tc_certname = PR_smprintf( "%s:%s", slotname, ptr );
1199                         }
1200                 }
1201         }
1202
1203         slot = PK11_FindSlotByName( slotname );
1204
1205         if ( !slot ) {
1206                 PRErrorCode errcode = PR_GetError();
1207                 Debug( LDAP_DEBUG_ANY,
1208                            "TLS: could not find the slot for certificate %s - error %d:%s.\n",
1209                            ctx->tc_certname, errcode,
1210                            PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1211                 return -1;
1212         }
1213
1214         PK11_SETATTRS( attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++;
1215         PK11_SETATTRS( attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++;
1216         PK11_SETATTRS( attrs, CKA_LABEL, (unsigned char *)filename, strlen(filename)+1 ); attrs++;
1217         if ( istrusted ) {
1218                 PK11_SETATTRS( attrs, CKA_TRUST, &cktrue, sizeof(CK_BBOOL) ); attrs++;
1219         } else {
1220                 PK11_SETATTRS( attrs, CKA_TRUST, &ckfalse, sizeof(CK_BBOOL) ); attrs++;
1221         }
1222         /* This loads the certificate in our PEM module into the appropriate
1223          * slot.
1224          */
1225         rv = PK11_CreateGenericObject( slot, theTemplate, 4, PR_FALSE /* isPerm */ );
1226
1227         PK11_FreeSlot( slot );
1228
1229         if ( !rv ) {
1230                 PRErrorCode errcode = PR_GetError();
1231                 Debug( LDAP_DEBUG_ANY,
1232                            "TLS: could not add the certificate %s - error %d:%s.\n",
1233                            ctx->tc_certname, errcode,
1234                            PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1235                 return -1;
1236         }
1237
1238         tlsm_add_pem_obj( ctx, rv );
1239
1240         return 0;
1241 }
1242
1243 static int
1244 tlsm_add_key_from_file( tlsm_ctx *ctx, const char *filename )
1245 {
1246         CK_SLOT_ID slotID;
1247         PK11SlotInfo * slot = NULL;
1248         PK11GenericObject *rv;
1249         CK_ATTRIBUTE *attrs;
1250         CK_ATTRIBUTE theTemplate[20];
1251         CK_BBOOL cktrue = CK_TRUE;
1252         CK_OBJECT_CLASS objClass = CKO_PRIVATE_KEY;
1253         int retcode = 0;
1254         PRFileInfo fi;
1255         PRStatus status;
1256
1257         memset( &fi, 0, sizeof(fi) );
1258         status = PR_GetFileInfo( filename, &fi );
1259         if ( PR_SUCCESS != status) {
1260                 PRErrorCode errcode = PR_GetError();
1261                 Debug( LDAP_DEBUG_ANY,
1262                            "TLS: could not read key file %s - error %d:%s.\n",
1263                            filename, errcode,
1264                            PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1265                 return -1;
1266         }
1267
1268         if ( fi.type != PR_FILE_FILE ) {
1269                 PR_SetError(PR_IS_DIRECTORY_ERROR, 0);
1270                 Debug( LDAP_DEBUG_ANY,
1271                            "TLS: error: the key file %s is not a file.\n",
1272                            filename, 0 ,0 );
1273                 return -1;
1274         }
1275
1276         attrs = theTemplate;
1277
1278         if ( ctx->tc_slotname == NULL ) { /* need new slot */
1279                 slotID = ++tlsm_slot_count;
1280                 ctx->tc_slotname = PR_smprintf( TLSM_PEM_TOKEN_FMT, slotID );
1281         }
1282         slot = PK11_FindSlotByName( ctx->tc_slotname );
1283
1284         if ( !slot ) {
1285                 PRErrorCode errcode = PR_GetError();
1286                 Debug( LDAP_DEBUG_ANY,
1287                            "TLS: could not find the slot %s for the private key - error %d:%s.\n",
1288                            ctx->tc_slotname, errcode,
1289                            PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1290                 return -1;
1291         }
1292
1293         PK11_SETATTRS( attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++;
1294         PK11_SETATTRS( attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++;
1295         PK11_SETATTRS( attrs, CKA_LABEL, (unsigned char *)filename, strlen(filename)+1 ); attrs++;
1296         rv = PK11_CreateGenericObject( slot, theTemplate, 3, PR_FALSE /* isPerm */ );
1297
1298         if ( !rv ) {
1299                 PRErrorCode errcode = PR_GetError();
1300                 Debug( LDAP_DEBUG_ANY,
1301                            "TLS: could not add the certificate %s - error %d:%s.\n",
1302                            ctx->tc_certname, errcode,
1303                            PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1304                 retcode = -1;
1305         } else {
1306                 /* When adding an encrypted key the PKCS#11 will be set as removed */
1307                 /* This will force the token to be seen as re-inserted */
1308                 SECMOD_WaitForAnyTokenEvent( pem_module, 0, 0 );
1309                 PK11_IsPresent( slot );
1310                 retcode = 0;
1311         }
1312
1313         PK11_FreeSlot( slot );
1314
1315         if ( !retcode ) {
1316                 tlsm_add_pem_obj( ctx, rv );
1317         }
1318         return retcode;
1319 }
1320
1321 static int
1322 tlsm_init_ca_certs( tlsm_ctx *ctx, const char *cacertfile, const char *cacertdir )
1323 {
1324         PRBool isca = PR_TRUE;
1325         PRStatus status = PR_SUCCESS;
1326         PRErrorCode errcode = PR_SUCCESS;
1327
1328         if ( !cacertfile && !cacertdir ) {
1329                 /* no checking - not good, but allowed */
1330                 return 0;
1331         }
1332
1333         if ( cacertfile ) {
1334                 int rc = tlsm_add_cert_from_file( ctx, cacertfile, isca, PR_TRUE );
1335                 if ( rc ) {
1336                         errcode = PR_GetError();
1337                         Debug( LDAP_DEBUG_ANY,
1338                                    "TLS: %s is not a valid CA certificate file - error %d:%s.\n",
1339                                    cacertfile, errcode,
1340                                    PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1341                         /* failure with cacertfile is a hard failure even if cacertdir is
1342                            also specified and contains valid CA cert files */
1343                         status = PR_FAILURE;
1344                 } else {
1345                         Debug( LDAP_DEBUG_TRACE,
1346                                    "TLS: loaded CA certificate file %s.\n",
1347                                    cacertfile, 0, 0 );
1348                 }
1349         }
1350
1351         /* if cacertfile above failed, we will return failure, even
1352            if there is a valid CA cert in cacertdir - but we still
1353            process cacertdir in case the user has enabled trace level
1354            debugging so they can see the processing for cacertdir too */
1355         /* any cacertdir failures are "soft" failures - if the user specifies
1356            no cert checking, then we allow the tls/ssl to continue, no matter
1357            what was specified for cacertdir, or the contents of the directory
1358            - this is different behavior than that of cacertfile */
1359         if ( cacertdir ) {
1360                 PRFileInfo fi;
1361                 PRDir *dir;
1362                 PRDirEntry *entry;
1363                 PRStatus fistatus = PR_FAILURE;
1364
1365                 memset( &fi, 0, sizeof(fi) );
1366                 fistatus = PR_GetFileInfo( cacertdir, &fi );
1367                 if ( PR_SUCCESS != fistatus) {
1368                         errcode = PR_GetError();
1369                         Debug( LDAP_DEBUG_ANY,
1370                                    "TLS: could not get info about the CA certificate directory %s - error %d:%s.\n",
1371                                    cacertdir, errcode,
1372                                    PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1373                         goto done;
1374                 }
1375
1376                 if ( fi.type != PR_FILE_DIRECTORY ) {
1377                         Debug( LDAP_DEBUG_ANY,
1378                                    "TLS: error: the CA certificate directory %s is not a directory.\n",
1379                                    cacertdir, 0 ,0 );
1380                         goto done;
1381                 }
1382
1383                 dir = PR_OpenDir( cacertdir );
1384                 if ( NULL == dir ) {
1385                         errcode = PR_GetError();
1386                         Debug( LDAP_DEBUG_ANY,
1387                                    "TLS: could not open the CA certificate directory %s - error %d:%s.\n",
1388                                    cacertdir, errcode,
1389                                    PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1390                         goto done;
1391                 }
1392
1393                 do {
1394                         entry = PR_ReadDir( dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN );
1395                         if ( ( NULL != entry ) && ( NULL != entry->name ) ) {
1396                                 char *fullpath = NULL;
1397                                 char *ptr;
1398
1399                                 ptr = PL_strrstr( entry->name, PEM_CA_HASH_FILE_SUFFIX );
1400                                 if ( ( ptr == NULL ) || ( *(ptr + PEM_CA_HASH_FILE_SUFFIX_LEN) != '\0' ) ) {
1401                                         Debug( LDAP_DEBUG_TRACE,
1402                                                    "TLS: file %s does not end in [%s] - does not appear to be a CA certificate "
1403                                                    "directory file with a properly hashed file name - skipping.\n",
1404                                                    entry->name, PEM_CA_HASH_FILE_SUFFIX, 0 );
1405                                         continue;
1406                                 }
1407                                 fullpath = PR_smprintf( "%s/%s", cacertdir, entry->name );
1408                                 if ( !tlsm_add_cert_from_file( ctx, fullpath, isca, PR_TRUE ) ) {
1409                                         Debug( LDAP_DEBUG_TRACE,
1410                                                    "TLS: loaded CA certificate file %s from CA certificate directory %s.\n",
1411                                                    fullpath, cacertdir, 0 );
1412                                 } else {
1413                                         errcode = PR_GetError();
1414                                         Debug( LDAP_DEBUG_TRACE,
1415                                                    "TLS: %s is not a valid CA certificate file - error %d:%s.\n",
1416                                                    fullpath, errcode,
1417                                                    PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1418                                 }
1419                                 PR_smprintf_free( fullpath );
1420                         }
1421                 } while ( NULL != entry );
1422                 PR_CloseDir( dir );
1423         }
1424 done:
1425         if ( status != PR_SUCCESS ) {
1426                 return -1;
1427         }
1428
1429         return 0;
1430 }
1431
1432 /*
1433  * NSS supports having multiple cert/key databases in the same
1434  * directory, each one having a unique string prefix e.g.
1435  * slapd-01-cert8.db - the prefix here is "slapd-01-"
1436  * this function examines the given certdir - if it looks like
1437  * /path/to/directory/prefix it will return the
1438  * /path/to/directory part in realcertdir, and the prefix in prefix
1439  */
1440 static void
1441 tlsm_get_certdb_prefix( const char *certdir, char **realcertdir, char **prefix )
1442 {
1443         char sep = PR_GetDirectorySeparator();
1444         char *ptr = NULL;
1445         struct PRFileInfo prfi;
1446         PRStatus prc;
1447
1448         *realcertdir = (char *)certdir; /* default is the one passed in */
1449
1450         /* if certdir is not given, just return */
1451         if ( !certdir ) {
1452                 return;
1453         }
1454
1455         prc = PR_GetFileInfo( certdir, &prfi );
1456         /* if certdir exists (file or directory) then it cannot specify a prefix */
1457         if ( prc == PR_SUCCESS ) {
1458                 return;
1459         }
1460
1461         /* if certdir was given, and there is a '/' in certdir, see if there
1462            is anything after the last '/' - if so, assume it is the prefix */
1463         if ( ( ( ptr = strrchr( certdir, sep ) ) ) && *(ptr+1) ) {
1464                 *realcertdir = PL_strndup( certdir, ptr-certdir );
1465                 *prefix = PL_strdup( ptr+1 );
1466         }
1467
1468         return;
1469 }
1470
1471 /*
1472  * This is the part of the init we defer until we get the
1473  * actual security configuration information.  This is
1474  * only called once, protected by a PRCallOnce
1475  * NOTE: This must be done before the first call to SSL_ImportFD,
1476  * especially the setting of the policy
1477  * NOTE: This must be called after fork()
1478  */
1479 static int
1480 tlsm_deferred_init( void *arg )
1481 {
1482         tlsm_ctx *ctx = (tlsm_ctx *)arg;
1483         struct ldaptls *lt = ctx->tc_config;
1484         const char *securitydirs[3];
1485         int ii;
1486         int nn;
1487         PRErrorCode errcode = 1;
1488 #ifdef HAVE_NSS_INITCONTEXT
1489         NSSInitParameters initParams;
1490         NSSInitContext *initctx = NULL;
1491 #endif
1492         SECStatus rc;
1493         int done = 0;
1494
1495 #ifdef HAVE_SECMOD_RESTARTMODULES
1496         /* NSS enforces the pkcs11 requirement that modules should be unloaded after
1497            a fork() - since there is no portable way to determine if NSS has been
1498            already initialized in a parent process, we just call SECMOD_RestartModules
1499            with force == FALSE - if the module has been unloaded due to a fork, it will
1500            be reloaded, otherwise, it is a no-op */
1501         if ( SECFailure == ( rc = SECMOD_RestartModules(PR_FALSE /* do not force */) ) ) {
1502                 errcode = PORT_GetError();
1503                 if ( errcode != SEC_ERROR_NOT_INITIALIZED ) {
1504                         Debug( LDAP_DEBUG_TRACE,
1505                                    "TLS: could not restart the security modules: %d:%s\n",
1506                                    errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
1507                 } else {
1508                         errcode = 1;
1509                 }
1510         }
1511 #endif
1512
1513 #ifdef HAVE_NSS_INITCONTEXT
1514         memset( &initParams, 0, sizeof( initParams ) );
1515         initParams.length = sizeof( initParams );
1516 #endif /* HAVE_NSS_INITCONTEXT */
1517
1518 #ifndef HAVE_NSS_INITCONTEXT
1519         if ( !NSS_IsInitialized() ) {
1520 #endif /* HAVE_NSS_INITCONTEXT */
1521                 /*
1522                   MOZNSS_DIR will override everything else - you can
1523                   always set MOZNSS_DIR to force the use of this
1524                   directory
1525                   If using MOZNSS, specify the location of the moznss db dir
1526                   in the cacertdir directive of the OpenLDAP configuration.
1527                   DEFAULT_MOZNSS_DIR will only be used if the code cannot
1528                   find a security dir to use based on the current
1529                   settings
1530                 */
1531                 nn = 0;
1532                 securitydirs[nn++] = PR_GetEnv( "MOZNSS_DIR" );
1533                 securitydirs[nn++] = lt->lt_cacertdir;
1534                 securitydirs[nn++] = PR_GetEnv( "DEFAULT_MOZNSS_DIR" );
1535                 for ( ii = 0; !done && ( ii < nn ); ++ii ) {
1536                         char *realcertdir = NULL;
1537                         const char *defprefix = "";
1538                         char *prefix = (char *)defprefix;
1539                         const char *securitydir = securitydirs[ii];
1540                         if ( NULL == securitydir ) {
1541                                 continue;
1542                         }
1543
1544                         tlsm_get_certdb_prefix( securitydir, &realcertdir, &prefix );
1545 #ifdef HAVE_NSS_INITCONTEXT
1546 #ifdef INITCONTEXT_HACK
1547                         if ( !NSS_IsInitialized() && ctx->tc_is_server ) {
1548                                 rc = NSS_Initialize( realcertdir, prefix, prefix, SECMOD_DB, NSS_INIT_READONLY );
1549                         } else {
1550                                 initctx = NSS_InitContext( realcertdir, prefix, prefix, SECMOD_DB,
1551                                                                                    &initParams, NSS_INIT_READONLY );
1552                                 rc = (initctx == NULL) ? SECFailure : SECSuccess;
1553                         }
1554 #else
1555                         initctx = NSS_InitContext( realcertdir, prefix, prefix, SECMOD_DB,
1556                                                                            &initParams, NSS_INIT_READONLY );
1557                         rc = (initctx == NULL) ? SECFailure : SECSuccess;
1558 #endif
1559 #else
1560                         rc = NSS_Initialize( realcertdir, prefix, prefix, SECMOD_DB, NSS_INIT_READONLY );
1561 #endif
1562
1563                         if ( rc != SECSuccess ) {
1564                                 errcode = PORT_GetError();
1565                                 if ( securitydirs[ii] != lt->lt_cacertdir) {
1566                                         Debug( LDAP_DEBUG_TRACE,
1567                                                    "TLS: could not initialize moznss using security dir %s prefix %s - error %d.\n",
1568                                                    realcertdir, prefix, errcode );
1569                                 }
1570                         } else {
1571                                 /* success */
1572                                 Debug( LDAP_DEBUG_TRACE, "TLS: using moznss security dir %s prefix %s.\n",
1573                                            realcertdir, prefix, 0 );
1574                                 errcode = 0;
1575                                 done = 1;
1576                         }
1577                         if ( realcertdir != securitydir ) {
1578                                 PL_strfree( realcertdir );
1579                         }
1580                         if ( prefix != defprefix ) {
1581                                 PL_strfree( prefix );
1582                         }
1583                 }
1584
1585                 if ( errcode ) { /* no moznss db found, or not using moznss db */
1586 #ifdef HAVE_NSS_INITCONTEXT
1587                         int flags = NSS_INIT_READONLY|NSS_INIT_NOCERTDB|NSS_INIT_NOMODDB;
1588 #ifdef INITCONTEXT_HACK
1589                         if ( !NSS_IsInitialized() && ctx->tc_is_server ) {
1590                                 rc = NSS_NoDB_Init( NULL );
1591                         } else {
1592                                 initctx = NSS_InitContext( "", "", "", SECMOD_DB,
1593                                                                                    &initParams, flags );
1594                                 rc = (initctx == NULL) ? SECFailure : SECSuccess;
1595                         }
1596 #else
1597                         initctx = NSS_InitContext( "", "", "", SECMOD_DB,
1598                                                                            &initParams, flags );
1599                         rc = (initctx == NULL) ? SECFailure : SECSuccess;
1600 #endif
1601 #else
1602                         rc = NSS_NoDB_Init( NULL );
1603 #endif
1604                         if ( rc != SECSuccess ) {
1605                                 errcode = PORT_GetError();
1606                                 Debug( LDAP_DEBUG_ANY,
1607                                            "TLS: could not initialize moznss - error %d:%s.\n",
1608                                            errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
1609                                 return -1;
1610                         }
1611
1612 #ifdef HAVE_NSS_INITCONTEXT
1613                         ctx->tc_initctx = initctx;
1614 #endif
1615
1616                         /* initialize the PEM module */
1617                         if ( tlsm_init_pem_module() ) {
1618                                 errcode = PORT_GetError();
1619                                 Debug( LDAP_DEBUG_ANY,
1620                                            "TLS: could not initialize moznss PEM module - error %d:%s.\n",
1621                                            errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
1622                                 return -1;
1623                         }
1624
1625                         if ( tlsm_init_ca_certs( ctx, lt->lt_cacertfile, lt->lt_cacertdir ) ) {
1626                                 /* if we tried to use lt->lt_cacertdir as an NSS key/cert db, errcode 
1627                                    will be a value other than 1 - print an error message so that the
1628                                    user will know that failed too */
1629                                 if ( ( errcode != 1 ) && ( lt->lt_cacertdir ) ) {
1630                                         char *realcertdir = NULL;
1631                                         char *prefix = NULL;
1632                                         tlsm_get_certdb_prefix( lt->lt_cacertdir, &realcertdir, &prefix );
1633                                         Debug( LDAP_DEBUG_TRACE,
1634                                                    "TLS: could not initialize moznss using security dir %s prefix %s - error %d.\n",
1635                                                    realcertdir, prefix ? prefix : "", errcode );
1636                                         if ( realcertdir != lt->lt_cacertdir ) {
1637                                                 PL_strfree( realcertdir );
1638                                         }
1639                                         PL_strfree( prefix );
1640                                 }
1641                                 return -1;
1642                         }
1643
1644                         ctx->tc_using_pem = PR_TRUE;
1645                 }
1646
1647 #ifdef HAVE_NSS_INITCONTEXT
1648                 if ( !ctx->tc_initctx ) {
1649                         ctx->tc_initctx = initctx;
1650                 }
1651 #endif
1652
1653                 NSS_SetDomesticPolicy();
1654
1655                 PK11_SetPasswordFunc( tlsm_pin_prompt );
1656
1657                 /* register cleanup function */
1658                 /* delete the old one, if any */
1659                 NSS_UnregisterShutdown( tlsm_nss_shutdown_cb, NULL );
1660                 NSS_RegisterShutdown( tlsm_nss_shutdown_cb, NULL );
1661
1662 #ifndef HAVE_NSS_INITCONTEXT
1663         }
1664 #endif /* HAVE_NSS_INITCONTEXT */
1665
1666         return 0;
1667 }
1668
1669 static int
1670 tlsm_authenticate( tlsm_ctx *ctx, const char *certname, const char *pininfo )
1671 {
1672         const char *colon = NULL;
1673         char *token_name = NULL;
1674         PK11SlotInfo *slot = NULL;
1675         int rc = -1;
1676
1677         if ( !certname || !*certname ) {
1678                 return 0;
1679         }
1680
1681         if ( ( colon = PL_strchr( certname, ':' ) ) ) {
1682                 token_name = PL_strndup( certname, colon-certname );
1683         }
1684
1685         if ( token_name ) {
1686                 slot = PK11_FindSlotByName( token_name );
1687         } else {
1688                 slot = PK11_GetInternalKeySlot();
1689         }
1690
1691         if ( !slot ) {
1692                 PRErrorCode errcode = PR_GetError();
1693                 Debug( LDAP_DEBUG_ANY,
1694                            "TLS: could not find the slot for security token %s - error %d:%s.\n",
1695                            token_name ? token_name : DEFAULT_TOKEN_NAME, errcode,
1696                            PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1697                 goto done;
1698         }
1699
1700         rc = tlsm_authenticate_to_slot( ctx, slot );
1701
1702 done:
1703         PL_strfree( token_name );
1704         if ( slot ) {
1705                 PK11_FreeSlot( slot );
1706         }
1707
1708         return rc;
1709 }
1710
1711 /*
1712  * Find and verify the certificate.
1713  * Either fd is given, in which case the cert will be taken from it via SSL_PeerCertificate
1714  * or certname is given, and it will be searched for by name
1715  */
1716 static int
1717 tlsm_find_and_verify_cert_key(tlsm_ctx *ctx, PRFileDesc *fd, const char *certname, int isServer, CERTCertificate **pRetCert, SECKEYPrivateKey **pRetKey)
1718 {
1719         CERTCertificate *cert = NULL;
1720         int rc = -1;
1721         void *pin_arg = NULL;
1722         SECKEYPrivateKey *key = NULL;
1723
1724         pin_arg = SSL_RevealPinArg( fd );
1725         if ( certname ) {
1726                 cert = PK11_FindCertFromNickname( certname, pin_arg );
1727                 if ( !cert ) {
1728                         PRErrorCode errcode = PR_GetError();
1729                         Debug( LDAP_DEBUG_ANY,
1730                                    "TLS: error: the certificate %s could not be found in the database - error %d:%s\n",
1731                                    certname, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1732                         return -1;
1733                 }
1734         } else {
1735                 /* we are verifying the peer cert
1736                    we also need to swap the isServer meaning */
1737                 cert = SSL_PeerCertificate( fd );
1738                 if ( !cert ) {
1739                         PRErrorCode errcode = PR_GetError();
1740                         Debug( LDAP_DEBUG_ANY,
1741                                    "TLS: error: could not get the certificate from the peer connection - error %d:%s\n",
1742                                    errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), NULL );
1743                         return -1;
1744                 }
1745                 isServer = !isServer; /* verify the peer's cert instead */
1746         }
1747
1748         if ( ctx->tc_slotname ) {
1749                 PK11SlotInfo *slot = PK11_FindSlotByName( ctx->tc_slotname );
1750                 key = PK11_FindPrivateKeyFromCert( slot, cert, NULL );
1751                 PK11_FreeSlot( slot );
1752         } else {
1753                 key = PK11_FindKeyByAnyCert( cert, pin_arg );
1754         }
1755
1756         if (key) {
1757                 SECCertificateUsage certUsage;
1758                 PRBool checkSig = PR_TRUE;
1759                 SECStatus status;
1760
1761                 if ( pRetKey ) {
1762                         *pRetKey = key; /* caller will deal with this */
1763                 } else {
1764                         SECKEY_DestroyPrivateKey( key );
1765                 }
1766                 if ( isServer ) {
1767                         certUsage = certificateUsageSSLServer;
1768                 } else {
1769                         certUsage = certificateUsageSSLClient;
1770                 }
1771                 if ( ctx->tc_verify_cert ) {
1772                         checkSig = PR_TRUE;
1773                 } else {
1774                         checkSig = PR_FALSE;
1775                 }
1776                 /* may not have a CA cert - ok - ignore SEC_ERROR_UNKNOWN_ISSUER */
1777                 status = tlsm_verify_cert( ctx->tc_certdb, cert, pin_arg,
1778                                                                    checkSig, certUsage, SEC_ERROR_UNKNOWN_ISSUER );
1779                 if ( status == SECSuccess ) {
1780                         rc = 0;
1781                 }
1782         } else {
1783                 PRErrorCode errcode = PR_GetError();
1784                 Debug( LDAP_DEBUG_ANY,
1785                            "TLS: error: could not find the private key for certificate %s - error %d:%s\n",
1786                            certname, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1787         }
1788
1789         if ( pRetCert ) {
1790                 *pRetCert = cert; /* caller will deal with this */
1791         } else {
1792                 CERT_DestroyCertificate( cert );
1793         }
1794
1795     return rc;
1796 }
1797
1798 static int
1799 tlsm_get_client_auth_data( void *arg, PRFileDesc *fd,
1800                                                    CERTDistNames *caNames, CERTCertificate **pRetCert,
1801                                                    SECKEYPrivateKey **pRetKey )
1802 {
1803         tlsm_ctx *ctx = (tlsm_ctx *)arg;
1804         int rc;
1805
1806         /* don't need caNames - this function will call CERT_VerifyCertificateNow
1807            which will verify the cert against the known CAs */
1808         rc = tlsm_find_and_verify_cert_key( ctx, fd, ctx->tc_certname, 0, pRetCert, pRetKey );
1809         if ( rc ) {
1810                 Debug( LDAP_DEBUG_ANY,
1811                            "TLS: error: unable to perform client certificate authentication for "
1812                            "certificate named %s\n", ctx->tc_certname, 0, 0 );
1813                 return SECFailure;
1814         }
1815
1816         return SECSuccess;
1817 }
1818
1819 /*
1820  * ctx must have a tc_model that is valid
1821  * certname is in the form [<tokenname>:]<certnickname>
1822  * where <tokenname> is the name of the PKCS11 token
1823  * and <certnickname> is the nickname of the cert/key in
1824  * the database
1825 */
1826 static int
1827 tlsm_clientauth_init( tlsm_ctx *ctx )
1828 {
1829         SECStatus status = SECFailure;
1830         int rc;
1831
1832         rc = tlsm_find_and_verify_cert_key( ctx, ctx->tc_model, ctx->tc_certname, 0, NULL, NULL );
1833         if ( rc ) {
1834                 Debug( LDAP_DEBUG_ANY,
1835                            "TLS: error: unable to set up client certificate authentication for "
1836                            "certificate named %s\n", ctx->tc_certname, 0, 0 );
1837                 return -1;
1838         }
1839
1840         status = SSL_GetClientAuthDataHook( ctx->tc_model,
1841                                                                                 tlsm_get_client_auth_data,
1842                                                                                 (void *)ctx );
1843
1844         return ( status == SECSuccess ? 0 : -1 );
1845 }
1846
1847 /*
1848  * Tear down the TLS subsystem. Should only be called once.
1849  */
1850 static void
1851 tlsm_destroy( void )
1852 {
1853 }
1854
1855 static tls_ctx *
1856 tlsm_ctx_new ( struct ldapoptions *lo )
1857 {
1858         tlsm_ctx *ctx;
1859
1860         ctx = LDAP_MALLOC( sizeof (*ctx) );
1861         if ( ctx ) {
1862                 ctx->tc_refcnt = 1;
1863 #ifdef LDAP_R_COMPILE
1864                 ldap_pvt_thread_mutex_init( &ctx->tc_refmutex );
1865 #endif
1866                 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 */
1867                 ctx->tc_certdb = NULL;
1868                 ctx->tc_certname = NULL;
1869                 ctx->tc_pin_file = NULL;
1870                 ctx->tc_model = NULL;
1871                 memset(&ctx->tc_callonce, 0, sizeof(ctx->tc_callonce));
1872                 ctx->tc_require_cert = lo->ldo_tls_require_cert;
1873                 ctx->tc_verify_cert = PR_FALSE;
1874                 ctx->tc_using_pem = PR_FALSE;
1875                 ctx->tc_slotname = NULL;
1876 #ifdef HAVE_NSS_INITCONTEXT
1877                 ctx->tc_initctx = NULL;
1878 #endif /* HAVE_NSS_INITCONTEXT */
1879                 ctx->tc_pem_objs = NULL;
1880                 ctx->tc_n_pem_objs = 0;
1881         }
1882         return (tls_ctx *)ctx;
1883 }
1884
1885 static void
1886 tlsm_ctx_ref( tls_ctx *ctx )
1887 {
1888         tlsm_ctx *c = (tlsm_ctx *)ctx;
1889         LDAP_MUTEX_LOCK( &c->tc_refmutex );
1890         c->tc_refcnt++;
1891         LDAP_MUTEX_UNLOCK( &c->tc_refmutex );
1892 }
1893
1894 static void
1895 tlsm_ctx_free ( tls_ctx *ctx )
1896 {
1897         tlsm_ctx *c = (tlsm_ctx *)ctx;
1898         int refcount;
1899
1900         if ( !c ) return;
1901
1902         LDAP_MUTEX_LOCK( &c->tc_refmutex );
1903         refcount = --c->tc_refcnt;
1904         LDAP_MUTEX_UNLOCK( &c->tc_refmutex );
1905         if ( refcount )
1906                 return;
1907         if ( c->tc_model )
1908                 PR_Close( c->tc_model );
1909         c->tc_certdb = NULL; /* if not the default, may have to clean up */
1910         PL_strfree( c->tc_certname );
1911         c->tc_certname = NULL;
1912         PL_strfree( c->tc_pin_file );
1913         c->tc_pin_file = NULL;
1914         PL_strfree( c->tc_slotname );           
1915         tlsm_free_pem_objs( c );
1916 #ifdef HAVE_NSS_INITCONTEXT
1917         if (c->tc_initctx)
1918                 NSS_ShutdownContext( c->tc_initctx );
1919         c->tc_initctx = NULL;
1920 #endif /* HAVE_NSS_INITCONTEXT */
1921 #ifdef LDAP_R_COMPILE
1922         ldap_pvt_thread_mutex_destroy( &c->tc_refmutex );
1923 #endif
1924         LDAP_FREE( c );
1925 }
1926
1927 /*
1928  * initialize a new TLS context
1929  */
1930 static int
1931 tlsm_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server )
1932 {
1933         tlsm_ctx *ctx = (tlsm_ctx *)lo->ldo_tls_ctx;
1934         ctx->tc_is_server = is_server;
1935
1936         return 0;
1937 }
1938
1939 static int
1940 tlsm_deferred_ctx_init( void *arg )
1941 {
1942         tlsm_ctx *ctx = (tlsm_ctx *)arg;
1943         PRBool sslv2 = PR_FALSE;
1944         PRBool sslv3 = PR_TRUE;
1945         PRBool tlsv1 = PR_TRUE;
1946         PRBool request_cert = PR_FALSE;
1947         PRInt32 require_cert = PR_FALSE;
1948         PRFileDesc *fd;
1949         struct ldaptls *lt;
1950
1951         if ( tlsm_deferred_init( ctx ) ) {
1952             Debug( LDAP_DEBUG_ANY,
1953                            "TLS: could perform TLS system initialization.\n",
1954                            0, 0, 0 );
1955             return -1;
1956         }
1957
1958         ctx->tc_certdb = CERT_GetDefaultCertDB(); /* If there is ever a per-context db, change this */
1959
1960         fd = PR_CreateIOLayerStub( tlsm_layer_id, &tlsm_PR_methods );
1961         if ( fd ) {
1962                 ctx->tc_model = SSL_ImportFD( NULL, fd );
1963         }
1964
1965         if ( !ctx->tc_model ) {
1966                 PRErrorCode err = PR_GetError();
1967                 Debug( LDAP_DEBUG_ANY,
1968                            "TLS: could perform TLS socket I/O layer initialization - error %d:%s.\n",
1969                            err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
1970
1971                 if ( fd ) {
1972                         PR_Close( fd );
1973                 }
1974                 return -1;
1975         }
1976
1977         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_SECURITY, PR_TRUE ) ) {
1978                 Debug( LDAP_DEBUG_ANY,
1979                        "TLS: could not set secure mode on.\n",
1980                        0, 0, 0 );
1981                 return -1;
1982         }
1983
1984         lt = ctx->tc_config;
1985
1986         /* default is sslv3 and tlsv1 */
1987         if ( lt->lt_protocol_min ) {
1988                 if ( lt->lt_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_SSL3 ) {
1989                         sslv3 = PR_FALSE;
1990                 } else if ( lt->lt_protocol_min <= LDAP_OPT_X_TLS_PROTOCOL_SSL2 ) {
1991                         sslv2 = PR_TRUE;
1992                         Debug( LDAP_DEBUG_ANY,
1993                                "TLS: warning: minimum TLS protocol level set to "
1994                                "include SSLv2 - SSLv2 is insecure - do not use\n", 0, 0, 0 );
1995                 }
1996         }
1997         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_ENABLE_SSL2, sslv2 ) ) {
1998                 Debug( LDAP_DEBUG_ANY,
1999                        "TLS: could not set SSLv2 mode on.\n",
2000                        0, 0, 0 );
2001                 return -1;
2002         }
2003         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_ENABLE_SSL3, sslv3 ) ) {
2004                 Debug( LDAP_DEBUG_ANY,
2005                        "TLS: could not set SSLv3 mode on.\n",
2006                        0, 0, 0 );
2007                 return -1;
2008         }
2009         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_ENABLE_TLS, tlsv1 ) ) {
2010                 Debug( LDAP_DEBUG_ANY,
2011                        "TLS: could not set TLSv1 mode on.\n",
2012                        0, 0, 0 );
2013                 return -1;
2014         }
2015
2016         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_HANDSHAKE_AS_CLIENT, !ctx->tc_is_server ) ) {
2017                 Debug( LDAP_DEBUG_ANY,
2018                        "TLS: could not set handshake as client.\n",
2019                        0, 0, 0 );
2020                 return -1;
2021         }
2022         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_HANDSHAKE_AS_SERVER, ctx->tc_is_server ) ) {
2023                 Debug( LDAP_DEBUG_ANY,
2024                        "TLS: could not set handshake as server.\n",
2025                        0, 0, 0 );
2026                 return -1;
2027         }
2028
2029         if ( lt->lt_ciphersuite &&
2030              tlsm_parse_ciphers( ctx, lt->lt_ciphersuite )) {
2031                 Debug( LDAP_DEBUG_ANY,
2032                        "TLS: could not set cipher list %s.\n",
2033                        lt->lt_ciphersuite, 0, 0 );
2034                 return -1;
2035         } else if ( tlsm_parse_ciphers( ctx, "DEFAULT" ) ) {
2036                 Debug( LDAP_DEBUG_ANY,
2037                        "TLS: could not set cipher list DEFAULT.\n",
2038                        0, 0, 0 );
2039                 return -1;
2040         }
2041
2042         if ( ctx->tc_require_cert ) {
2043                 request_cert = PR_TRUE;
2044                 require_cert = SSL_REQUIRE_NO_ERROR;
2045                 if ( ctx->tc_require_cert == LDAP_OPT_X_TLS_DEMAND ||
2046                      ctx->tc_require_cert == LDAP_OPT_X_TLS_HARD ) {
2047                         require_cert = SSL_REQUIRE_ALWAYS;
2048                 }
2049                 if ( ctx->tc_require_cert != LDAP_OPT_X_TLS_ALLOW )
2050                         ctx->tc_verify_cert = PR_TRUE;
2051         } else {
2052                 ctx->tc_verify_cert = PR_FALSE;
2053         }
2054
2055         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_REQUEST_CERTIFICATE, request_cert ) ) {
2056                 Debug( LDAP_DEBUG_ANY,
2057                        "TLS: could not set request certificate mode.\n",
2058                        0, 0, 0 );
2059                 return -1;
2060         }
2061                 
2062         if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_REQUIRE_CERTIFICATE, require_cert ) ) {
2063                 Debug( LDAP_DEBUG_ANY,
2064                        "TLS: could not set require certificate mode.\n",
2065                        0, 0, 0 );
2066                 return -1;
2067         }
2068
2069         /* set up our cert and key, if any */
2070         if ( lt->lt_certfile ) {
2071                 /* if using the PEM module, load the PEM file specified by lt_certfile */
2072                 /* otherwise, assume this is the name of a cert already in the db */
2073                 if ( ctx->tc_using_pem ) {
2074                         /* this sets ctx->tc_certname to the correct value */
2075                         int rc = tlsm_add_cert_from_file( ctx, lt->lt_certfile, PR_FALSE, PR_TRUE );
2076                         if ( rc ) {
2077                                 return rc;
2078                         }
2079                 } else {
2080                         PL_strfree( ctx->tc_certname );
2081                         ctx->tc_certname = PL_strdup( lt->lt_certfile );
2082                 }
2083         }
2084
2085         if ( lt->lt_keyfile ) {
2086                 /* if using the PEM module, load the PEM file specified by lt_keyfile */
2087                 /* otherwise, assume this is the pininfo for the key */
2088                 if ( ctx->tc_using_pem ) {
2089                         /* this sets ctx->tc_certname to the correct value */
2090                         int rc = tlsm_add_key_from_file( ctx, lt->lt_keyfile );
2091                         if ( rc ) {
2092                                 return rc;
2093                         }
2094                 } else {
2095                         PL_strfree( ctx->tc_pin_file );
2096                         ctx->tc_pin_file = PL_strdup( lt->lt_keyfile );
2097                 }
2098         }
2099
2100         /* Set up callbacks for use by clients */
2101         if ( !ctx->tc_is_server ) {
2102                 if ( SSL_OptionSet( ctx->tc_model, SSL_NO_CACHE, PR_TRUE ) != SECSuccess ) {
2103                         PRErrorCode err = PR_GetError();
2104                         Debug( LDAP_DEBUG_ANY, 
2105                                "TLS: error: could not set nocache option for moznss - error %d:%s\n",
2106                                err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
2107                         return -1;
2108                 }
2109
2110                 if ( SSL_BadCertHook( ctx->tc_model, tlsm_bad_cert_handler, ctx ) != SECSuccess ) {
2111                         PRErrorCode err = PR_GetError();
2112                         Debug( LDAP_DEBUG_ANY, 
2113                                "TLS: error: could not set bad cert handler for moznss - error %d:%s\n",
2114                                err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
2115                         return -1;
2116                 }
2117
2118                 /* 
2119                    since a cert has been specified, assume the client wants to do cert auth
2120                 */
2121                 if ( ctx->tc_certname ) {
2122                         if ( tlsm_authenticate( ctx, ctx->tc_certname, ctx->tc_pin_file ) ) {
2123                                 Debug( LDAP_DEBUG_ANY, 
2124                                        "TLS: error: unable to authenticate to the security device for certificate %s\n",
2125                                        ctx->tc_certname, 0, 0 );
2126                                 return -1;
2127                         }
2128                         if ( tlsm_clientauth_init( ctx ) ) {
2129                                 Debug( LDAP_DEBUG_ANY, 
2130                                        "TLS: error: unable to set up client certificate authentication using %s\n",
2131                                        ctx->tc_certname, 0, 0 );
2132                                 return -1;
2133                         }
2134                 }
2135         } else { /* set up secure server */
2136                 SSLKEAType certKEA;
2137                 CERTCertificate *serverCert;
2138                 SECKEYPrivateKey *serverKey;
2139                 SECStatus status;
2140
2141                 /* must have a certificate for the server to use */
2142                 if ( !ctx->tc_certname ) {
2143                         Debug( LDAP_DEBUG_ANY, 
2144                                "TLS: error: no server certificate: must specify a certificate for the server to use\n",
2145                                0, 0, 0 );
2146                         return -1;
2147                 }
2148
2149                 /* authenticate to the server's token - this will do nothing
2150                    if the key/cert db is not password protected */
2151                 if ( tlsm_authenticate( ctx, ctx->tc_certname, ctx->tc_pin_file ) ) {
2152                         Debug( LDAP_DEBUG_ANY, 
2153                                "TLS: error: unable to authenticate to the security device for certificate %s\n",
2154                                ctx->tc_certname, 0, 0 );
2155                         return -1;
2156                 }
2157
2158                 /* get the server's key and cert */
2159                 if ( tlsm_find_and_verify_cert_key( ctx, ctx->tc_model, ctx->tc_certname, ctx->tc_is_server,
2160                                                     &serverCert, &serverKey ) ) {
2161                         Debug( LDAP_DEBUG_ANY, 
2162                                "TLS: error: unable to find and verify server's cert and key for certificate %s\n",
2163                                ctx->tc_certname, 0, 0 );
2164                         return -1;
2165                 }
2166
2167                 certKEA = NSS_FindCertKEAType( serverCert );
2168                 /* configure the socket to be a secure server socket */
2169                 status = SSL_ConfigSecureServer( ctx->tc_model, serverCert, serverKey, certKEA );
2170                 /* SSL_ConfigSecureServer copies these */
2171                 CERT_DestroyCertificate( serverCert );
2172                 SECKEY_DestroyPrivateKey( serverKey );
2173
2174                 if ( SECSuccess != status ) {
2175                         PRErrorCode err = PR_GetError();
2176                         Debug( LDAP_DEBUG_ANY, 
2177                                "TLS: error: unable to configure secure server using certificate %s - error %d:%s\n",
2178                                ctx->tc_certname, err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ) );
2179                         return -1;
2180                 }
2181         }
2182
2183         /* Callback for authenticating certificate */
2184         if ( SSL_AuthCertificateHook( ctx->tc_model, tlsm_auth_cert_handler,
2185                                   ctx->tc_certdb ) != SECSuccess ) {
2186                 PRErrorCode err = PR_GetError();
2187                 Debug( LDAP_DEBUG_ANY, 
2188                        "TLS: error: could not set auth cert handler for moznss - error %d:%s\n",
2189                        err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
2190                 return -1;
2191         }
2192
2193         if ( SSL_HandshakeCallback( ctx->tc_model, tlsm_handshake_complete_cb, ctx ) ) {
2194                 PRErrorCode err = PR_GetError();
2195                 Debug( LDAP_DEBUG_ANY, 
2196                        "TLS: error: could not set handshake callback for moznss - error %d:%s\n",
2197                        err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ), NULL );
2198                 return -1;
2199         }
2200
2201         return 0;
2202 }
2203
2204 struct tls_data {
2205         tlsm_session            *session;
2206         Sockbuf_IO_Desc         *sbiod;
2207         /* there seems to be no portable way to determine if the
2208            sockbuf sd has been set to nonblocking mode - the
2209            call to ber_pvt_socket_set_nonblock() takes place
2210            before the tls socket is set up, so we cannot
2211            intercept that call either.
2212            On systems where fcntl is available, we can just
2213            F_GETFL and test for O_NONBLOCK.  On other systems,
2214            we will just see if the IO op returns EAGAIN or EWOULDBLOCK,
2215            and just set this flag */
2216         PRBool              nonblock;
2217         /*
2218          * NSS tries hard to be backwards compatible with SSLv2 clients, or
2219          * clients that send an SSLv2 client hello.  This message is not
2220          * tagged in any way, so NSS has no way to know if the incoming
2221          * message is a valid SSLv2 client hello or just some bogus data
2222          * (or cleartext LDAP).  We store the first byte read from the
2223          * client here.  The most common case will be a client sending
2224          * LDAP data instead of SSL encrypted LDAP data.  This can happen,
2225          * for example, if using ldapsearch -Z - if the starttls fails,
2226          * the client will fallback to plain cleartext LDAP.  So if we
2227          * see that the firstbyte is a valid LDAP tag, we can be
2228          * pretty sure this is happening.
2229          */
2230         ber_tag_t           firsttag;
2231         /*
2232          * NSS doesn't return SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE, etc.
2233          * when it is blocked, so we have to set a flag in the wrapped send
2234          * and recv calls that tells us what operation NSS was last blocked
2235          * on
2236          */
2237 #define TLSM_READ  1
2238 #define TLSM_WRITE 2
2239         int io_flag;
2240 };
2241
2242 static struct tls_data *
2243 tlsm_get_pvt_tls_data( PRFileDesc *fd )
2244 {
2245         struct tls_data         *p;
2246         PRFileDesc *myfd;
2247
2248         if ( !fd ) {
2249                 return NULL;
2250         }
2251
2252         myfd = PR_GetIdentitiesLayer( fd, tlsm_layer_id );
2253
2254         if ( !myfd ) {
2255                 return NULL;
2256         }
2257
2258         p = (struct tls_data *)myfd->secret;
2259
2260         return p;
2261 }
2262
2263 static int
2264 tlsm_is_non_ssl_message( PRFileDesc *fd, ber_tag_t *thebyte )
2265 {
2266         struct tls_data         *p;
2267
2268         if ( thebyte ) {
2269                 *thebyte = LBER_DEFAULT;
2270         }
2271
2272         p = tlsm_get_pvt_tls_data( fd );
2273         if ( p == NULL || p->sbiod == NULL ) {
2274                 return 0;
2275         }
2276
2277         if ( p->firsttag == LBER_SEQUENCE ) {
2278                 if ( thebyte ) {
2279                         *thebyte = p->firsttag;
2280                 }
2281                 return 1;
2282         }
2283
2284         return 0;
2285 }
2286
2287 static tls_session *
2288 tlsm_session_new ( tls_ctx * ctx, int is_server )
2289 {
2290         tlsm_ctx *c = (tlsm_ctx *)ctx;
2291         tlsm_session *session;
2292         PRFileDesc *fd;
2293         PRStatus status;
2294         int rc;
2295
2296         c->tc_is_server = is_server;
2297         status = PR_CallOnceWithArg( &c->tc_callonce, tlsm_deferred_ctx_init, c );
2298         if ( PR_SUCCESS != status ) {
2299                 PRErrorCode err = PR_GetError();
2300                 Debug( LDAP_DEBUG_ANY, 
2301                        "TLS: error: could not initialize moznss security context - error %d:%s\n",
2302                        err, PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT), NULL );
2303                 return NULL;
2304         }
2305
2306         fd = PR_CreateIOLayerStub( tlsm_layer_id, &tlsm_PR_methods );
2307         if ( !fd ) {
2308                 return NULL;
2309         }
2310
2311         session = SSL_ImportFD( c->tc_model, fd );
2312         if ( !session ) {
2313                 PR_DELETE( fd );
2314                 return NULL;
2315         }
2316
2317         if ( is_server ) {
2318                 /* 0 means use the defaults here */
2319                 SSL_ConfigServerSessionIDCache( 0, 0, 0, NULL );
2320         }
2321
2322         rc = SSL_ResetHandshake( session, is_server );
2323         if ( rc ) {
2324                 PRErrorCode err = PR_GetError();
2325                 Debug( LDAP_DEBUG_TRACE, 
2326                            "TLS: error: new session - reset handshake failure %d - error %d:%s\n",
2327                            rc, err,
2328                            err ? PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ) : "unknown" );
2329                 PR_DELETE( fd );
2330                 PR_Close( session );
2331                 session = NULL;
2332         }
2333
2334         return (tls_session *)session;
2335
2336
2337 static int
2338 tlsm_session_accept_or_connect( tls_session *session, int is_accept )
2339 {
2340         tlsm_session *s = (tlsm_session *)session;
2341         int rc = SSL_ForceHandshake( s );
2342         const char *op = is_accept ? "accept" : "connect";
2343
2344         if ( rc ) {
2345                 PRErrorCode err = PR_GetError();
2346                 rc = -1;
2347                 if ( err == PR_WOULD_BLOCK_ERROR ) {
2348                         ber_tag_t thetag = LBER_DEFAULT;
2349                         /* see if we are blocked because of a bogus packet */
2350                         if ( tlsm_is_non_ssl_message( s, &thetag ) ) { /* see if we received a non-SSL message */
2351                                 Debug( LDAP_DEBUG_ANY, 
2352                                            "TLS: error: %s - error - received non-SSL message [0x%x]\n",
2353                                            op, (unsigned int)thetag, 0 );
2354                                 /* reset error to something more descriptive */
2355                                 PR_SetError( SSL_ERROR_RX_MALFORMED_HELLO_REQUEST, EPROTO );
2356                         }
2357                 } else {
2358                         Debug( LDAP_DEBUG_ANY, 
2359                                    "TLS: error: %s - force handshake failure: errno %d - moznss error %d\n",
2360                                    op, errno, err );
2361                 }
2362         }
2363
2364         return rc;
2365 }
2366 static int
2367 tlsm_session_accept( tls_session *session )
2368 {
2369         return tlsm_session_accept_or_connect( session, 1 );
2370 }
2371
2372 static int
2373 tlsm_session_connect( LDAP *ld, tls_session *session )
2374 {
2375         return tlsm_session_accept_or_connect( session, 0 );
2376 }
2377
2378 static int
2379 tlsm_session_upflags( Sockbuf *sb, tls_session *session, int rc )
2380 {
2381         int prerror = PR_GetError();
2382
2383         if ( ( prerror == PR_PENDING_INTERRUPT_ERROR ) || ( prerror == PR_WOULD_BLOCK_ERROR ) ) {
2384                 tlsm_session *s = (tlsm_session *)session;
2385                 struct tls_data *p = tlsm_get_pvt_tls_data( s );
2386
2387                 if ( p && ( p->io_flag == TLSM_READ ) ) {
2388                         sb->sb_trans_needs_read = 1;
2389                         return 1;
2390                 } else if ( p && ( p->io_flag == TLSM_WRITE ) ) {
2391                         sb->sb_trans_needs_write = 1;
2392                         return 1;
2393                 }
2394         }
2395
2396         return 0;
2397 }
2398
2399 static char *
2400 tlsm_session_errmsg( tls_session *sess, int rc, char *buf, size_t len )
2401 {
2402         int i;
2403         int prerror = PR_GetError();
2404
2405         i = PR_GetErrorTextLength();
2406         if ( i > len ) {
2407                 char *msg = LDAP_MALLOC( i+1 );
2408                 PR_GetErrorText( msg );
2409                 memcpy( buf, msg, len );
2410                 LDAP_FREE( msg );
2411         } else if ( i ) {
2412                 PR_GetErrorText( buf );
2413         } else if ( prerror ) {
2414                 i = PR_snprintf( buf, len, "TLS error %d:%s",
2415                                                  prerror, PR_ErrorToString( prerror, PR_LANGUAGE_I_DEFAULT ) );
2416         }
2417
2418         return ( i > 0 ) ? buf : NULL;
2419 }
2420
2421 static int
2422 tlsm_session_my_dn( tls_session *session, struct berval *der_dn )
2423 {
2424         tlsm_session *s = (tlsm_session *)session;
2425         CERTCertificate *cert;
2426
2427         cert = SSL_LocalCertificate( s );
2428         if (!cert) return LDAP_INVALID_CREDENTIALS;
2429
2430         der_dn->bv_val = (char *)cert->derSubject.data;
2431         der_dn->bv_len = cert->derSubject.len;
2432         CERT_DestroyCertificate( cert );
2433         return 0;
2434 }
2435
2436 static int
2437 tlsm_session_peer_dn( tls_session *session, struct berval *der_dn )
2438 {
2439         tlsm_session *s = (tlsm_session *)session;
2440         CERTCertificate *cert;
2441
2442         cert = SSL_PeerCertificate( s );
2443         if (!cert) return LDAP_INVALID_CREDENTIALS;
2444         
2445         der_dn->bv_val = (char *)cert->derSubject.data;
2446         der_dn->bv_len = cert->derSubject.len;
2447         CERT_DestroyCertificate( cert );
2448         return 0;
2449 }
2450
2451 /* what kind of hostname were we given? */
2452 #define IS_DNS  0
2453 #define IS_IP4  1
2454 #define IS_IP6  2
2455
2456 static int
2457 tlsm_session_chkhost( LDAP *ld, tls_session *session, const char *name_in )
2458 {
2459         tlsm_session *s = (tlsm_session *)session;
2460         CERTCertificate *cert;
2461         const char *name, *domain = NULL, *ptr;
2462         int ret, ntype = IS_DNS, nlen, dlen;
2463 #ifdef LDAP_PF_INET6
2464         struct in6_addr addr;
2465 #else
2466         struct in_addr addr;
2467 #endif
2468         SECItem altname;
2469         SECStatus rv;
2470
2471         if( ldap_int_hostname &&
2472                 ( !name_in || !strcasecmp( name_in, "localhost" ) ) )
2473         {
2474                 name = ldap_int_hostname;
2475         } else {
2476                 name = name_in;
2477         }
2478         nlen = strlen( name );
2479
2480         cert = SSL_PeerCertificate( s );
2481         if (!cert) {
2482                 Debug( LDAP_DEBUG_ANY,
2483                         "TLS: unable to get peer certificate.\n",
2484                         0, 0, 0 );
2485                 /* if this was a fatal condition, things would have
2486                  * aborted long before now.
2487                  */
2488                 return LDAP_SUCCESS;
2489         }
2490
2491 #ifdef LDAP_PF_INET6
2492         if (name[0] == '[' && strchr(name, ']')) {
2493                 char *n2 = ldap_strdup(name+1);
2494                 *strchr(n2, ']') = 0;
2495                 if (inet_pton(AF_INET6, n2, &addr))
2496                         ntype = IS_IP6;
2497                 LDAP_FREE(n2);
2498         } else 
2499 #endif
2500         if ((ptr = strrchr(name, '.')) && isdigit((unsigned char)ptr[1])) {
2501                 if (inet_aton(name, (struct in_addr *)&addr)) ntype = IS_IP4;
2502         }
2503         if (ntype == IS_DNS ) {
2504                 domain = strchr( name, '.' );
2505                 if ( domain )
2506                         dlen = nlen - ( domain - name );
2507         }
2508
2509         ret = LDAP_LOCAL_ERROR;
2510
2511         rv = CERT_FindCertExtension( cert, SEC_OID_X509_SUBJECT_ALT_NAME,
2512                 &altname );
2513         if ( rv == SECSuccess && altname.data ) {
2514                 PRArenaPool *arena;
2515                 CERTGeneralName *names, *cur;
2516
2517                 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2518                 if ( !arena ) {
2519                         ret = LDAP_NO_MEMORY;
2520                         goto fail;
2521                 }
2522
2523                 names = cur = CERT_DecodeAltNameExtension(arena, &altname);
2524                 if ( !cur )
2525                         goto altfail;
2526
2527                 do {
2528                         char *host;
2529                         int hlen;
2530
2531                         /* ignore empty */
2532                         if ( !cur->name.other.len ) continue;
2533
2534                         host = (char *)cur->name.other.data;
2535                         hlen = cur->name.other.len;
2536
2537                         if ( cur->type == certDNSName ) {
2538                                 if ( ntype != IS_DNS )  continue;
2539
2540                                 /* is this an exact match? */
2541                                 if ( nlen == hlen && !strncasecmp( name, host, nlen )) {
2542                                         ret = LDAP_SUCCESS;
2543                                         break;
2544                                 }
2545
2546                                 /* is this a wildcard match? */
2547                                 if ( domain && host[0] == '*' && host[1] == '.' &&
2548                                         dlen == hlen-1 && !strncasecmp( domain, host+1, dlen )) {
2549                                         ret = LDAP_SUCCESS;
2550                                         break;
2551                                 }
2552                         } else if ( cur->type == certIPAddress ) {
2553                                 if ( ntype == IS_DNS )  continue;
2554                                 
2555 #ifdef LDAP_PF_INET6
2556                                 if (ntype == IS_IP6 && hlen != sizeof(struct in6_addr)) {
2557                                         continue;
2558                                 } else
2559 #endif
2560                                 if (ntype == IS_IP4 && hlen != sizeof(struct in_addr)) {
2561                                         continue;
2562                                 }
2563                                 if (!memcmp(host, &addr, hlen)) {
2564                                         ret = LDAP_SUCCESS;
2565                                         break;
2566                                 }
2567                         }
2568                 } while (( cur = CERT_GetNextGeneralName( cur )) != names );
2569 altfail:
2570                 PORT_FreeArena( arena, PR_FALSE );
2571                 SECITEM_FreeItem( &altname, PR_FALSE );
2572         }
2573         /* no altnames matched, try the CN */
2574         if ( ret != LDAP_SUCCESS ) {
2575                 /* find the last CN */
2576                 CERTRDN *rdn, **rdns;
2577                 CERTAVA *lastava = NULL;
2578                 char buf[2048];
2579
2580                 buf[0] = '\0';
2581                 rdns = cert->subject.rdns;
2582                 while ( rdns && ( rdn = *rdns++ )) {
2583                         CERTAVA *ava, **avas = rdn->avas;
2584                         while ( avas && ( ava = *avas++ )) {
2585                                 if ( CERT_GetAVATag( ava ) == SEC_OID_AVA_COMMON_NAME )
2586                                         lastava = ava;
2587                         }
2588                 }
2589                 if ( lastava ) {
2590                         SECItem *av = CERT_DecodeAVAValue( &lastava->value );
2591                         if ( av ) {
2592                                 if ( av->len == nlen && !strncasecmp( name, (char *)av->data, nlen )) {
2593                                         ret = LDAP_SUCCESS;
2594                                 } else if ( av->data[0] == '*' && av->data[1] == '.' &&
2595                                         domain && dlen == av->len - 1 && !strncasecmp( name,
2596                                                 (char *)(av->data+1), dlen )) {
2597                                         ret = LDAP_SUCCESS;
2598                                 } else {
2599                                         int len = av->len;
2600                                         if ( len >= sizeof(buf) )
2601                                                 len = sizeof(buf)-1;
2602                                         memcpy( buf, av->data, len );
2603                                         buf[len] = '\0';
2604                                 }
2605                                 SECITEM_FreeItem( av, PR_TRUE );
2606                         }
2607                 }
2608                 if ( ret != LDAP_SUCCESS ) {
2609                         Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match "
2610                                 "common name in certificate (%s).\n", 
2611                                 name, buf, 0 );
2612                         ret = LDAP_CONNECT_ERROR;
2613                         if ( ld->ld_error ) {
2614                                 LDAP_FREE( ld->ld_error );
2615                         }
2616                         ld->ld_error = LDAP_STRDUP(
2617                                 _("TLS: hostname does not match CN in peer certificate"));
2618                 }
2619         }
2620
2621 fail:
2622         CERT_DestroyCertificate( cert );
2623         return ret;
2624 }
2625
2626 static int
2627 tlsm_session_strength( tls_session *session )
2628 {
2629         tlsm_session *s = (tlsm_session *)session;
2630         int rc, keySize;
2631
2632         rc = SSL_SecurityStatus( s, NULL, NULL, NULL, &keySize,
2633                 NULL, NULL );
2634         return rc ? 0 : keySize;
2635 }
2636
2637 /*
2638  * TLS support for LBER Sockbufs
2639  */
2640
2641 static PRStatus PR_CALLBACK
2642 tlsm_PR_Close(PRFileDesc *fd)
2643 {
2644         int rc = PR_SUCCESS;
2645
2646         /* we don't need to actually close anything here, just
2647            pop our io layer off the stack */
2648         fd->secret = NULL; /* must have been freed before calling PR_Close */
2649         if ( fd->lower ) {
2650                 fd = PR_PopIOLayer( fd, tlsm_layer_id );
2651                 /* if we are not the last layer, pass the close along */
2652                 if ( fd ) {
2653                         if ( fd->dtor ) {
2654                                 fd->dtor( fd );
2655                         }
2656                         rc = fd->methods->close( fd );
2657                 }
2658         } else {
2659                 /* we are the last layer - just call our dtor */
2660                 fd->dtor(fd);
2661         }
2662
2663         return rc;
2664 }
2665
2666 static PRStatus PR_CALLBACK
2667 tlsm_PR_Shutdown(PRFileDesc *fd, PRShutdownHow how)
2668 {
2669         int rc = PR_SUCCESS;
2670
2671         if ( fd->lower ) {
2672                 rc = PR_Shutdown( fd->lower, how );
2673         }
2674
2675         return rc;
2676 }
2677
2678 static int PR_CALLBACK
2679 tlsm_PR_Recv(PRFileDesc *fd, void *buf, PRInt32 len, PRIntn flags,
2680          PRIntervalTime timeout)
2681 {
2682         struct tls_data         *p;
2683         int rc;
2684
2685         if ( buf == NULL || len <= 0 ) return 0;
2686
2687         p = tlsm_get_pvt_tls_data( fd );
2688
2689         if ( p == NULL || p->sbiod == NULL ) {
2690                 return 0;
2691         }
2692
2693         rc = LBER_SBIOD_READ_NEXT( p->sbiod, buf, len );
2694         if (rc <= 0) {
2695                 tlsm_map_error( errno );
2696                 if ( errno == EAGAIN || errno == EWOULDBLOCK ) {
2697                         p->nonblock = PR_TRUE; /* fd is using non-blocking io */
2698                 } else if ( errno ) { /* real error */
2699                         Debug( LDAP_DEBUG_TRACE, 
2700                                "TLS: error: tlsm_PR_Recv returned %d - error %d:%s\n",
2701                                rc, errno, STRERROR(errno) );
2702                 }
2703         } else if ( ( rc > 0 ) && ( len > 0 ) && ( p->firsttag == LBER_DEFAULT ) ) {
2704                 p->firsttag = (ber_tag_t)*((char *)buf);
2705         }
2706         p->io_flag = TLSM_READ;
2707
2708         return rc;
2709 }
2710
2711 static int PR_CALLBACK
2712 tlsm_PR_Send(PRFileDesc *fd, const void *buf, PRInt32 len, PRIntn flags,
2713          PRIntervalTime timeout)
2714 {
2715         struct tls_data         *p;
2716         int rc;
2717
2718         if ( buf == NULL || len <= 0 ) return 0;
2719
2720         p = tlsm_get_pvt_tls_data( fd );
2721
2722         if ( p == NULL || p->sbiod == NULL ) {
2723                 return 0;
2724         }
2725
2726         rc = LBER_SBIOD_WRITE_NEXT( p->sbiod, (char *)buf, len );
2727         if (rc <= 0) {
2728                 tlsm_map_error( errno );
2729                 if ( errno == EAGAIN || errno == EWOULDBLOCK ) {
2730                         p->nonblock = PR_TRUE;
2731                 } else if ( errno ) { /* real error */
2732                         Debug( LDAP_DEBUG_TRACE, 
2733                                "TLS: error: tlsm_PR_Send returned %d - error %d:%s\n",
2734                                rc, errno, STRERROR(errno) );
2735                 }
2736         }
2737         p->io_flag = TLSM_WRITE;
2738
2739         return rc;
2740 }
2741
2742 static int PR_CALLBACK
2743 tlsm_PR_Read(PRFileDesc *fd, void *buf, PRInt32 len)
2744 {
2745         return tlsm_PR_Recv( fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
2746 }
2747
2748 static int PR_CALLBACK
2749 tlsm_PR_Write(PRFileDesc *fd, const void *buf, PRInt32 len)
2750 {
2751         return tlsm_PR_Send( fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
2752 }
2753
2754 static PRStatus PR_CALLBACK
2755 tlsm_PR_GetPeerName(PRFileDesc *fd, PRNetAddr *addr)
2756 {
2757         struct tls_data         *p;
2758         ber_socklen_t len;
2759
2760         p = tlsm_get_pvt_tls_data( fd );
2761
2762         if ( p == NULL || p->sbiod == NULL ) {
2763                 return PR_FAILURE;
2764         }
2765         len = sizeof(PRNetAddr);
2766         return getpeername( p->sbiod->sbiod_sb->sb_fd, (struct sockaddr *)addr, &len );
2767 }
2768
2769 static PRStatus PR_CALLBACK
2770 tlsm_PR_GetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
2771 {
2772         struct tls_data         *p;
2773         p = tlsm_get_pvt_tls_data( fd );
2774
2775         if ( p == NULL || data == NULL ) {
2776                 return PR_FAILURE;
2777         }
2778
2779         /* only the nonblocking option is supported at this time
2780            MozNSS SSL code needs it */
2781         if ( data->option != PR_SockOpt_Nonblocking ) {
2782                 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2783                 return PR_FAILURE;
2784         }
2785 #ifdef HAVE_FCNTL
2786         int flags = fcntl( p->sbiod->sbiod_sb->sb_fd, F_GETFL );
2787         data->value.non_blocking = (flags & O_NONBLOCK) ? PR_TRUE : PR_FALSE;           
2788 #else /* punt :P */
2789         data->value.non_blocking = p->nonblock;
2790 #endif
2791         return PR_SUCCESS;
2792 }
2793
2794 static PRStatus PR_CALLBACK
2795 tlsm_PR_prs_unimp()
2796 {
2797     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2798     return PR_FAILURE;
2799 }
2800
2801 static PRFileDesc * PR_CALLBACK
2802 tlsm_PR_pfd_unimp()
2803 {
2804     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2805     return NULL;
2806 }
2807
2808 static PRInt16 PR_CALLBACK
2809 tlsm_PR_i16_unimp()
2810 {
2811     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2812     return SECFailure;
2813 }
2814
2815 static PRInt32 PR_CALLBACK
2816 tlsm_PR_i32_unimp()
2817 {
2818     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2819     return SECFailure;
2820 }
2821
2822 static PRInt64 PR_CALLBACK
2823 tlsm_PR_i64_unimp()
2824 {
2825     PRInt64 res;
2826
2827     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2828     LL_I2L(res, -1L);
2829     return res;
2830 }
2831
2832 static const PRIOMethods tlsm_PR_methods = {
2833     PR_DESC_LAYERED,
2834     tlsm_PR_Close,                      /* close        */
2835     tlsm_PR_Read,                       /* read         */
2836     tlsm_PR_Write,                      /* write        */
2837     tlsm_PR_i32_unimp,          /* available    */
2838     tlsm_PR_i64_unimp,          /* available64  */
2839     tlsm_PR_prs_unimp,          /* fsync        */
2840     tlsm_PR_i32_unimp,          /* seek         */
2841     tlsm_PR_i64_unimp,          /* seek64       */
2842     tlsm_PR_prs_unimp,          /* fileInfo     */
2843     tlsm_PR_prs_unimp,          /* fileInfo64   */
2844     tlsm_PR_i32_unimp,          /* writev       */
2845     tlsm_PR_prs_unimp,          /* connect      */
2846     tlsm_PR_pfd_unimp,          /* accept       */
2847     tlsm_PR_prs_unimp,          /* bind         */
2848     tlsm_PR_prs_unimp,          /* listen       */
2849     (PRShutdownFN)tlsm_PR_Shutdown,                     /* shutdown     */
2850     tlsm_PR_Recv,                       /* recv         */
2851     tlsm_PR_Send,                       /* send         */
2852     tlsm_PR_i32_unimp,          /* recvfrom     */
2853     tlsm_PR_i32_unimp,          /* sendto       */
2854     (PRPollFN)tlsm_PR_i16_unimp,        /* poll         */
2855     tlsm_PR_i32_unimp,          /* acceptread   */
2856     tlsm_PR_i32_unimp,          /* transmitfile */
2857     tlsm_PR_prs_unimp,          /* getsockname  */
2858     tlsm_PR_GetPeerName,        /* getpeername  */
2859     tlsm_PR_i32_unimp,          /* getsockopt   OBSOLETE */
2860     tlsm_PR_i32_unimp,          /* setsockopt   OBSOLETE */
2861     tlsm_PR_GetSocketOption,            /* getsocketoption   */
2862     tlsm_PR_i32_unimp,          /* setsocketoption   */
2863     tlsm_PR_i32_unimp,          /* Send a (partial) file with header/trailer*/
2864     (PRConnectcontinueFN)tlsm_PR_prs_unimp,             /* connectcontinue */
2865     tlsm_PR_i32_unimp,          /* reserved for future use */
2866     tlsm_PR_i32_unimp,          /* reserved for future use */
2867     tlsm_PR_i32_unimp,          /* reserved for future use */
2868     tlsm_PR_i32_unimp           /* reserved for future use */
2869 };
2870
2871 /*
2872  * Initialize TLS subsystem. Should be called only once.
2873  * See tlsm_deferred_init for the bulk of the init process
2874  */
2875 static int
2876 tlsm_init( void )
2877 {
2878         char *nofork = PR_GetEnv( "NSS_STRICT_NOFORK" );
2879
2880         PR_Init(0, 0, 0);
2881
2882         tlsm_layer_id = PR_GetUniqueIdentity( "OpenLDAP" );
2883
2884         /*
2885          * There are some applications that acquire a crypto context in the parent process
2886          * and expect that crypto context to work after a fork().  This does not work
2887          * with NSS using strict PKCS11 compliance mode.  We set this environment
2888          * variable here to tell the software encryption module/token to allow crypto
2889          * contexts to persist across a fork().  However, if you are using some other
2890          * module or encryption device that supports and expects full PKCS11 semantics,
2891          * the only recourse is to rewrite the application with atfork() handlers to save
2892          * the crypto context in the parent and restore (and SECMOD_RestartModules) the
2893          * context in the child.
2894          */
2895         if ( !nofork ) {
2896                 /* will leak one time */
2897                 char *noforkenvvar = PL_strdup( "NSS_STRICT_NOFORK=DISABLED" );
2898                 PR_SetEnv( noforkenvvar );
2899         }
2900
2901         return 0;
2902 }
2903
2904 static int
2905 tlsm_sb_setup( Sockbuf_IO_Desc *sbiod, void *arg )
2906 {
2907         struct tls_data         *p;
2908         tlsm_session    *session = arg;
2909         PRFileDesc *fd;
2910
2911         assert( sbiod != NULL );
2912
2913         p = LBER_MALLOC( sizeof( *p ) );
2914         if ( p == NULL ) {
2915                 return -1;
2916         }
2917
2918         fd = PR_GetIdentitiesLayer( session, tlsm_layer_id );
2919         if ( !fd ) {
2920                 LBER_FREE( p );
2921                 return -1;
2922         }
2923
2924         fd->secret = (PRFilePrivate *)p;
2925         p->session = session;
2926         p->sbiod = sbiod;
2927         p->firsttag = LBER_DEFAULT;
2928         sbiod->sbiod_pvt = p;
2929         return 0;
2930 }
2931
2932 static int
2933 tlsm_sb_remove( Sockbuf_IO_Desc *sbiod )
2934 {
2935         struct tls_data         *p;
2936         
2937         assert( sbiod != NULL );
2938         assert( sbiod->sbiod_pvt != NULL );
2939
2940         p = (struct tls_data *)sbiod->sbiod_pvt;
2941         PR_Close( p->session );
2942         LBER_FREE( sbiod->sbiod_pvt );
2943         sbiod->sbiod_pvt = NULL;
2944         return 0;
2945 }
2946
2947 static int
2948 tlsm_sb_close( Sockbuf_IO_Desc *sbiod )
2949 {
2950         struct tls_data         *p;
2951         
2952         assert( sbiod != NULL );
2953         assert( sbiod->sbiod_pvt != NULL );
2954
2955         p = (struct tls_data *)sbiod->sbiod_pvt;
2956         PR_Shutdown( p->session, PR_SHUTDOWN_BOTH );
2957         return 0;
2958 }
2959
2960 static int
2961 tlsm_sb_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
2962 {
2963         struct tls_data         *p;
2964         
2965         assert( sbiod != NULL );
2966         assert( sbiod->sbiod_pvt != NULL );
2967
2968         p = (struct tls_data *)sbiod->sbiod_pvt;
2969         
2970         if ( opt == LBER_SB_OPT_GET_SSL ) {
2971                 *((tlsm_session **)arg) = p->session;
2972                 return 1;
2973                 
2974         } else if ( opt == LBER_SB_OPT_DATA_READY ) {
2975                 if ( p && ( SSL_DataPending( p->session ) > 0 ) ) {
2976                         return 1;
2977                 }
2978                 
2979         }
2980         
2981         return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
2982 }
2983
2984 static ber_slen_t
2985 tlsm_sb_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
2986 {
2987         struct tls_data         *p;
2988         ber_slen_t              ret;
2989         int                     err;
2990
2991         assert( sbiod != NULL );
2992         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
2993
2994         p = (struct tls_data *)sbiod->sbiod_pvt;
2995
2996         ret = PR_Recv( p->session, buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
2997         if ( ret < 0 ) {
2998                 err = PR_GetError();
2999                 if ( err == PR_PENDING_INTERRUPT_ERROR || err == PR_WOULD_BLOCK_ERROR ) {
3000                         sbiod->sbiod_sb->sb_trans_needs_read = 1;
3001                         sock_errset(EWOULDBLOCK);
3002                 }
3003         } else {
3004                 sbiod->sbiod_sb->sb_trans_needs_read = 0;
3005         }
3006         return ret;
3007 }
3008
3009 static ber_slen_t
3010 tlsm_sb_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
3011 {
3012         struct tls_data         *p;
3013         ber_slen_t              ret;
3014         int                     err;
3015
3016         assert( sbiod != NULL );
3017         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
3018
3019         p = (struct tls_data *)sbiod->sbiod_pvt;
3020
3021         ret = PR_Send( p->session, (char *)buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
3022         if ( ret < 0 ) {
3023                 err = PR_GetError();
3024                 if ( err == PR_PENDING_INTERRUPT_ERROR || err == PR_WOULD_BLOCK_ERROR ) {
3025                         sbiod->sbiod_sb->sb_trans_needs_write = 1;
3026                         sock_errset(EWOULDBLOCK);
3027                         ret = 0;
3028                 }
3029         } else {
3030                 sbiod->sbiod_sb->sb_trans_needs_write = 0;
3031         }
3032         return ret;
3033 }
3034
3035 static Sockbuf_IO tlsm_sbio =
3036 {
3037         tlsm_sb_setup,          /* sbi_setup */
3038         tlsm_sb_remove,         /* sbi_remove */
3039         tlsm_sb_ctrl,           /* sbi_ctrl */
3040         tlsm_sb_read,           /* sbi_read */
3041         tlsm_sb_write,          /* sbi_write */
3042         tlsm_sb_close           /* sbi_close */
3043 };
3044
3045 tls_impl ldap_int_tls_impl = {
3046         "MozNSS",
3047
3048         tlsm_init,
3049         tlsm_destroy,
3050
3051         tlsm_ctx_new,
3052         tlsm_ctx_ref,
3053         tlsm_ctx_free,
3054         tlsm_ctx_init,
3055
3056         tlsm_session_new,
3057         tlsm_session_connect,
3058         tlsm_session_accept,
3059         tlsm_session_upflags,
3060         tlsm_session_errmsg,
3061         tlsm_session_my_dn,
3062         tlsm_session_peer_dn,
3063         tlsm_session_chkhost,
3064         tlsm_session_strength,
3065
3066         &tlsm_sbio,
3067
3068 #ifdef LDAP_R_COMPILE
3069         tlsm_thr_init,
3070 #else
3071         NULL,
3072 #endif
3073
3074         0
3075 };
3076
3077 #endif /* HAVE_MOZNSS */
3078 /*
3079   emacs settings
3080   Local Variables:
3081   indent-tabs-mode: t
3082   tab-width: 4
3083   End:
3084 */