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