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