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