1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Authors: Jeffrey Stedfast <fejj@ximian.com>
5 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
35 #include <sys/types.h>
38 #include <glib/gstdio.h>
40 #include <libedataserver/e-memory.h>
42 #include "camel-certdb.h"
43 #include "camel-file-utils.h"
44 #include "camel-private.h"
46 #define CAMEL_CERTDB_GET_CLASS(db) ((CamelCertDBClass *) CAMEL_OBJECT_GET_CLASS (db))
48 #define CAMEL_CERTDB_VERSION 0x100
50 static void camel_certdb_class_init (CamelCertDBClass *klass);
51 static void camel_certdb_init (CamelCertDB *certdb);
52 static void camel_certdb_finalize (CamelObject *obj);
54 static int certdb_header_load (CamelCertDB *certdb, FILE *istream);
55 static int certdb_header_save (CamelCertDB *certdb, FILE *ostream);
56 static CamelCert *certdb_cert_load (CamelCertDB *certdb, FILE *istream);
57 static int certdb_cert_save (CamelCertDB *certdb, CamelCert *cert, FILE *ostream);
58 static CamelCert *certdb_cert_new (CamelCertDB *certdb);
59 static void certdb_cert_free (CamelCertDB *certdb, CamelCert *cert);
61 static const char *cert_get_string (CamelCertDB *certdb, CamelCert *cert, int string);
62 static void cert_set_string (CamelCertDB *certdb, CamelCert *cert, int string, const char *value);
65 static CamelObjectClass *parent_class = NULL;
69 camel_certdb_get_type (void)
71 static CamelType type = CAMEL_INVALID_TYPE;
73 if (type == CAMEL_INVALID_TYPE) {
74 type = camel_type_register (camel_object_get_type (),
77 sizeof (CamelCertDBClass),
78 (CamelObjectClassInitFunc) camel_certdb_class_init,
80 (CamelObjectInitFunc) camel_certdb_init,
81 (CamelObjectFinalizeFunc) camel_certdb_finalize);
89 camel_certdb_class_init (CamelCertDBClass *klass)
91 parent_class = camel_type_get_global_classfuncs (camel_object_get_type ());
93 klass->header_load = certdb_header_load;
94 klass->header_save = certdb_header_save;
96 klass->cert_new = certdb_cert_new;
97 klass->cert_load = certdb_cert_load;
98 klass->cert_save = certdb_cert_save;
99 klass->cert_free = certdb_cert_free;
100 klass->cert_get_string = cert_get_string;
101 klass->cert_set_string = cert_set_string;
105 camel_certdb_init (CamelCertDB *certdb)
107 certdb->priv = g_malloc (sizeof (struct _CamelCertDBPrivate));
109 certdb->filename = NULL;
110 certdb->version = CAMEL_CERTDB_VERSION;
111 certdb->saved_certs = 0;
113 certdb->cert_size = sizeof (CamelCert);
115 certdb->cert_chunks = NULL;
117 certdb->certs = g_ptr_array_new ();
118 certdb->cert_hash = g_hash_table_new (g_str_hash, g_str_equal);
120 certdb->priv->db_lock = g_mutex_new ();
121 certdb->priv->io_lock = g_mutex_new ();
122 certdb->priv->alloc_lock = g_mutex_new ();
123 certdb->priv->ref_lock = g_mutex_new ();
127 camel_certdb_finalize (CamelObject *obj)
129 CamelCertDB *certdb = (CamelCertDB *) obj;
130 struct _CamelCertDBPrivate *p;
134 if (certdb->flags & CAMEL_CERTDB_DIRTY)
135 camel_certdb_save (certdb);
137 camel_certdb_clear (certdb);
138 g_ptr_array_free (certdb->certs, TRUE);
139 g_hash_table_destroy (certdb->cert_hash);
141 g_free (certdb->filename);
143 if (certdb->cert_chunks)
144 e_memchunk_destroy (certdb->cert_chunks);
146 g_mutex_free (p->db_lock);
147 g_mutex_free (p->io_lock);
148 g_mutex_free (p->alloc_lock);
149 g_mutex_free (p->ref_lock);
156 camel_certdb_new (void)
158 return (CamelCertDB *) camel_object_new (camel_certdb_get_type ());
162 static CamelCertDB *default_certdb = NULL;
163 static pthread_mutex_t default_certdb_lock = PTHREAD_MUTEX_INITIALIZER;
167 camel_certdb_set_default (CamelCertDB *certdb)
169 pthread_mutex_lock (&default_certdb_lock);
172 camel_object_unref (default_certdb);
175 camel_object_ref (certdb);
177 default_certdb = certdb;
179 pthread_mutex_unlock (&default_certdb_lock);
184 camel_certdb_get_default (void)
188 pthread_mutex_lock (&default_certdb_lock);
191 camel_object_ref (default_certdb);
193 certdb = default_certdb;
195 pthread_mutex_unlock (&default_certdb_lock);
202 camel_certdb_set_filename (CamelCertDB *certdb, const char *filename)
204 g_return_if_fail (CAMEL_IS_CERTDB (certdb));
205 g_return_if_fail (filename != NULL);
207 CAMEL_CERTDB_LOCK (certdb, db_lock);
209 g_free (certdb->filename);
210 certdb->filename = g_strdup (filename);
212 CAMEL_CERTDB_UNLOCK (certdb, db_lock);
217 certdb_header_load (CamelCertDB *certdb, FILE *istream)
219 if (camel_file_util_decode_uint32 (istream, &certdb->version) == -1)
221 if (camel_file_util_decode_uint32 (istream, &certdb->saved_certs) == -1)
228 certdb_cert_load (CamelCertDB *certdb, FILE *istream)
232 cert = camel_certdb_cert_new (certdb);
234 if (camel_file_util_decode_string (istream, &cert->issuer) == -1)
236 if (camel_file_util_decode_string (istream, &cert->subject) == -1)
238 if (camel_file_util_decode_string (istream, &cert->hostname) == -1)
240 if (camel_file_util_decode_string (istream, &cert->fingerprint) == -1)
242 if (camel_file_util_decode_uint32 (istream, &cert->trust) == -1)
249 camel_certdb_cert_unref (certdb, cert);
255 camel_certdb_load (CamelCertDB *certdb)
261 g_return_val_if_fail (CAMEL_IS_CERTDB (certdb), -1);
262 g_return_val_if_fail (certdb->filename, -1);
264 in = g_fopen (certdb->filename, "rb");
268 CAMEL_CERTDB_LOCK (certdb, io_lock);
269 if (CAMEL_CERTDB_GET_CLASS (certdb)->header_load (certdb, in) == -1)
272 for (i = 0; i < certdb->saved_certs; i++) {
273 cert = CAMEL_CERTDB_GET_CLASS (certdb)->cert_load (certdb, in);
278 camel_certdb_add (certdb, cert);
281 CAMEL_CERTDB_UNLOCK (certdb, io_lock);
283 if (fclose (in) != 0)
286 certdb->flags &= ~CAMEL_CERTDB_DIRTY;
292 g_warning ("Cannot load certificate database: %s", strerror (ferror (in)));
294 CAMEL_CERTDB_UNLOCK (certdb, io_lock);
302 certdb_header_save (CamelCertDB *certdb, FILE *ostream)
304 if (camel_file_util_encode_uint32 (ostream, certdb->version) == -1)
306 if (camel_file_util_encode_uint32 (ostream, certdb->saved_certs) == -1)
313 certdb_cert_save (CamelCertDB *certdb, CamelCert *cert, FILE *ostream)
315 if (camel_file_util_encode_string (ostream, cert->issuer) == -1)
317 if (camel_file_util_encode_string (ostream, cert->subject) == -1)
319 if (camel_file_util_encode_string (ostream, cert->hostname) == -1)
321 if (camel_file_util_encode_string (ostream, cert->fingerprint) == -1)
323 if (camel_file_util_encode_uint32 (ostream, cert->trust) == -1)
330 camel_certdb_save (CamelCertDB *certdb)
337 g_return_val_if_fail (CAMEL_IS_CERTDB (certdb), -1);
338 g_return_val_if_fail (certdb->filename, -1);
340 filename = alloca (strlen (certdb->filename) + 4);
341 sprintf (filename, "%s~", certdb->filename);
343 fd = g_open (filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0600);
347 out = fdopen (fd, "wb");
356 CAMEL_CERTDB_LOCK (certdb, io_lock);
358 certdb->saved_certs = certdb->certs->len;
359 if (CAMEL_CERTDB_GET_CLASS (certdb)->header_save (certdb, out) == -1)
362 for (i = 0; i < certdb->saved_certs; i++) {
363 cert = (CamelCert *) certdb->certs->pdata[i];
365 if (CAMEL_CERTDB_GET_CLASS (certdb)->cert_save (certdb, cert, out) == -1)
369 CAMEL_CERTDB_UNLOCK (certdb, io_lock);
371 if (fflush (out) != 0 || fsync (fileno (out)) == -1) {
379 if (fclose (out) != 0) {
386 if (g_rename (filename, certdb->filename) == -1) {
393 certdb->flags &= ~CAMEL_CERTDB_DIRTY;
399 g_warning ("Cannot save certificate database: %s", strerror (ferror (out)));
401 CAMEL_CERTDB_UNLOCK (certdb, io_lock);
412 camel_certdb_touch (CamelCertDB *certdb)
414 g_return_if_fail (CAMEL_IS_CERTDB (certdb));
416 certdb->flags |= CAMEL_CERTDB_DIRTY;
420 camel_certdb_get_cert (CamelCertDB *certdb, const char *fingerprint)
424 g_return_val_if_fail (CAMEL_IS_CERTDB (certdb), NULL);
426 CAMEL_CERTDB_LOCK (certdb, db_lock);
428 cert = g_hash_table_lookup (certdb->cert_hash, fingerprint);
430 camel_certdb_cert_ref (certdb, cert);
432 CAMEL_CERTDB_UNLOCK (certdb, db_lock);
438 camel_certdb_add (CamelCertDB *certdb, CamelCert *cert)
440 g_return_if_fail (CAMEL_IS_CERTDB (certdb));
442 CAMEL_CERTDB_LOCK (certdb, db_lock);
444 if (g_hash_table_lookup (certdb->cert_hash, cert->fingerprint)) {
445 CAMEL_CERTDB_UNLOCK (certdb, db_lock);
449 camel_certdb_cert_ref (certdb, cert);
450 g_ptr_array_add (certdb->certs, cert);
451 g_hash_table_insert (certdb->cert_hash, cert->fingerprint, cert);
453 certdb->flags |= CAMEL_CERTDB_DIRTY;
455 CAMEL_CERTDB_UNLOCK (certdb, db_lock);
459 camel_certdb_remove (CamelCertDB *certdb, CamelCert *cert)
461 g_return_if_fail (CAMEL_IS_CERTDB (certdb));
463 CAMEL_CERTDB_LOCK (certdb, db_lock);
465 if (g_hash_table_lookup (certdb->cert_hash, cert->fingerprint)) {
466 g_hash_table_remove (certdb->cert_hash, cert->fingerprint);
467 g_ptr_array_remove (certdb->certs, cert);
468 camel_certdb_cert_unref (certdb, cert);
470 certdb->flags |= CAMEL_CERTDB_DIRTY;
473 CAMEL_CERTDB_UNLOCK (certdb, db_lock);
477 certdb_cert_new (CamelCertDB *certdb)
481 if (certdb->cert_chunks)
482 cert = e_memchunk_alloc0 (certdb->cert_chunks);
484 cert = g_malloc0 (certdb->cert_size);
492 camel_certdb_cert_new (CamelCertDB *certdb)
496 g_return_val_if_fail (CAMEL_IS_CERTDB (certdb), NULL);
498 CAMEL_CERTDB_LOCK (certdb, alloc_lock);
500 cert = CAMEL_CERTDB_GET_CLASS (certdb)->cert_new (certdb);
502 CAMEL_CERTDB_UNLOCK (certdb, alloc_lock);
508 camel_certdb_cert_ref (CamelCertDB *certdb, CamelCert *cert)
510 g_return_if_fail (CAMEL_IS_CERTDB (certdb));
511 g_return_if_fail (cert != NULL);
513 CAMEL_CERTDB_LOCK (certdb, ref_lock);
515 CAMEL_CERTDB_UNLOCK (certdb, ref_lock);
519 certdb_cert_free (CamelCertDB *certdb, CamelCert *cert)
521 g_free (cert->issuer);
522 g_free (cert->subject);
523 g_free (cert->hostname);
524 g_free (cert->fingerprint);
526 g_byte_array_free(cert->rawcert, TRUE);
530 camel_certdb_cert_unref (CamelCertDB *certdb, CamelCert *cert)
532 g_return_if_fail (CAMEL_IS_CERTDB (certdb));
533 g_return_if_fail (cert != NULL);
535 CAMEL_CERTDB_LOCK (certdb, ref_lock);
537 if (cert->refcount <= 1) {
538 CAMEL_CERTDB_GET_CLASS (certdb)->cert_free (certdb, cert);
539 if (certdb->cert_chunks)
540 e_memchunk_free (certdb->cert_chunks, cert);
547 CAMEL_CERTDB_UNLOCK (certdb, ref_lock);
552 cert_remove (gpointer key, gpointer value, gpointer user_data)
558 camel_certdb_clear (CamelCertDB *certdb)
563 g_return_if_fail (CAMEL_IS_CERTDB (certdb));
565 CAMEL_CERTDB_LOCK (certdb, db_lock);
567 g_hash_table_foreach_remove (certdb->cert_hash, cert_remove, NULL);
568 for (i = 0; i < certdb->certs->len; i++) {
569 cert = (CamelCert *) certdb->certs->pdata[i];
570 camel_certdb_cert_unref (certdb, cert);
573 certdb->saved_certs = 0;
574 g_ptr_array_set_size (certdb->certs, 0);
575 certdb->flags |= CAMEL_CERTDB_DIRTY;
577 CAMEL_CERTDB_UNLOCK (certdb, db_lock);
582 cert_get_string (CamelCertDB *certdb, CamelCert *cert, int string)
585 case CAMEL_CERT_STRING_ISSUER:
587 case CAMEL_CERT_STRING_SUBJECT:
588 return cert->subject;
589 case CAMEL_CERT_STRING_HOSTNAME:
590 return cert->hostname;
591 case CAMEL_CERT_STRING_FINGERPRINT:
592 return cert->fingerprint;
600 camel_cert_get_string (CamelCertDB *certdb, CamelCert *cert, int string)
602 g_return_val_if_fail (CAMEL_IS_CERTDB (certdb), NULL);
603 g_return_val_if_fail (cert != NULL, NULL);
605 /* FIXME: do locking? */
607 return CAMEL_CERTDB_GET_CLASS (certdb)->cert_get_string (certdb, cert, string);
611 cert_set_string (CamelCertDB *certdb, CamelCert *cert, int string, const char *value)
614 case CAMEL_CERT_STRING_ISSUER:
615 g_free (cert->issuer);
616 cert->issuer = g_strdup (value);
618 case CAMEL_CERT_STRING_SUBJECT:
619 g_free (cert->subject);
620 cert->subject = g_strdup (value);
622 case CAMEL_CERT_STRING_HOSTNAME:
623 g_free (cert->hostname);
624 cert->hostname = g_strdup (value);
626 case CAMEL_CERT_STRING_FINGERPRINT:
627 g_free (cert->fingerprint);
628 cert->fingerprint = g_strdup (value);
637 camel_cert_set_string (CamelCertDB *certdb, CamelCert *cert, int string, const char *value)
639 g_return_if_fail (CAMEL_IS_CERTDB (certdb));
640 g_return_if_fail (cert != NULL);
642 /* FIXME: do locking? */
644 CAMEL_CERTDB_GET_CLASS (certdb)->cert_set_string (certdb, cert, string, value);
649 camel_cert_get_trust (CamelCertDB *certdb, CamelCert *cert)
651 g_return_val_if_fail (CAMEL_IS_CERTDB (certdb), CAMEL_CERT_TRUST_UNKNOWN);
652 g_return_val_if_fail (cert != NULL, CAMEL_CERT_TRUST_UNKNOWN);
659 camel_cert_set_trust (CamelCertDB *certdb, CamelCert *cert, CamelCertTrust trust)
661 g_return_if_fail (CAMEL_IS_CERTDB (certdb));
662 g_return_if_fail (cert != NULL);