1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Authors: Jeffrey Stedfast <fejj@ximian.com>
5 * Copyright 2002 Ximian, Inc. (www.ximian.com)
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU 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 General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
31 #include <sys/types.h>
38 #include "camel-certdb.h"
39 #include "camel-private.h"
41 #include <camel/camel-file-utils.h>
43 #include <e-util/e-memory.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 #ifdef ENABLE_THREADS
121 certdb->priv->db_lock = g_mutex_new ();
122 certdb->priv->io_lock = g_mutex_new ();
123 certdb->priv->alloc_lock = g_mutex_new ();
124 certdb->priv->ref_lock = g_mutex_new ();
129 camel_certdb_finalize (CamelObject *obj)
131 CamelCertDB *certdb = (CamelCertDB *) obj;
132 struct _CamelCertDBPrivate *p;
136 if (certdb->flags & CAMEL_CERTDB_DIRTY)
137 camel_certdb_save (certdb);
139 camel_certdb_clear (certdb);
140 g_ptr_array_free (certdb->certs, TRUE);
141 g_hash_table_destroy (certdb->cert_hash);
143 g_free (certdb->filename);
145 if (certdb->cert_chunks)
146 e_memchunk_destroy (certdb->cert_chunks);
148 #ifdef ENABLE_THREADS
149 g_mutex_free (p->db_lock);
150 g_mutex_free (p->io_lock);
151 g_mutex_free (p->alloc_lock);
152 g_mutex_free (p->ref_lock);
160 camel_certdb_new (void)
162 return (CamelCertDB *) camel_object_new (camel_certdb_get_type ());
166 static CamelCertDB *default_certdb = NULL;
167 static pthread_mutex_t default_certdb_lock = PTHREAD_MUTEX_INITIALIZER;
171 camel_certdb_set_default (CamelCertDB *certdb)
173 pthread_mutex_lock (&default_certdb_lock);
176 camel_object_unref (default_certdb);
179 camel_object_ref (certdb);
181 default_certdb = certdb;
183 pthread_mutex_unlock (&default_certdb_lock);
188 camel_certdb_get_default (void)
192 pthread_mutex_lock (&default_certdb_lock);
195 camel_object_ref (default_certdb);
197 certdb = default_certdb;
199 pthread_mutex_unlock (&default_certdb_lock);
206 camel_certdb_set_filename (CamelCertDB *certdb, const char *filename)
208 g_return_if_fail (CAMEL_IS_CERTDB (certdb));
209 g_return_if_fail (filename != NULL);
211 CAMEL_CERTDB_LOCK (certdb, db_lock);
213 g_free (certdb->filename);
214 certdb->filename = g_strdup (filename);
216 CAMEL_CERTDB_UNLOCK (certdb, db_lock);
221 certdb_header_load (CamelCertDB *certdb, FILE *istream)
223 if (camel_file_util_decode_uint32 (istream, &certdb->version) == -1)
225 if (camel_file_util_decode_uint32 (istream, &certdb->saved_certs) == -1)
232 certdb_cert_load (CamelCertDB *certdb, FILE *istream)
236 cert = camel_certdb_cert_new (certdb);
238 if (camel_file_util_decode_string (istream, &cert->issuer) == -1)
240 if (camel_file_util_decode_string (istream, &cert->subject) == -1)
242 if (camel_file_util_decode_string (istream, &cert->hostname) == -1)
244 if (camel_file_util_decode_string (istream, &cert->fingerprint) == -1)
246 if (camel_file_util_decode_uint32 (istream, &cert->trust) == -1)
253 camel_certdb_cert_unref (certdb, cert);
259 camel_certdb_load (CamelCertDB *certdb)
265 g_return_val_if_fail (CAMEL_IS_CERTDB (certdb), -1);
266 g_return_val_if_fail (certdb->filename, -1);
268 in = fopen (certdb->filename, "r");
272 CAMEL_CERTDB_LOCK (certdb, io_lock);
273 if (CAMEL_CERTDB_GET_CLASS (certdb)->header_load (certdb, in) == -1)
276 for (i = 0; i < certdb->saved_certs; i++) {
277 cert = CAMEL_CERTDB_GET_CLASS (certdb)->cert_load (certdb, in);
282 camel_certdb_add (certdb, cert);
285 CAMEL_CERTDB_UNLOCK (certdb, io_lock);
287 if (fclose (in) != 0)
290 certdb->flags &= ~CAMEL_CERTDB_DIRTY;
296 g_warning ("Cannot load certificate database: %s", strerror (ferror (in)));
298 CAMEL_CERTDB_UNLOCK (certdb, io_lock);
306 certdb_header_save (CamelCertDB *certdb, FILE *ostream)
308 if (camel_file_util_encode_uint32 (ostream, certdb->version) == -1)
310 if (camel_file_util_encode_uint32 (ostream, certdb->saved_certs) == -1)
317 certdb_cert_save (CamelCertDB *certdb, CamelCert *cert, FILE *ostream)
319 if (camel_file_util_encode_string (ostream, cert->issuer) == -1)
321 if (camel_file_util_encode_string (ostream, cert->subject) == -1)
323 if (camel_file_util_encode_string (ostream, cert->hostname) == -1)
325 if (camel_file_util_encode_string (ostream, cert->fingerprint) == -1)
327 if (camel_file_util_encode_uint32 (ostream, cert->trust) == -1)
334 camel_certdb_save (CamelCertDB *certdb)
341 g_return_val_if_fail (CAMEL_IS_CERTDB (certdb), -1);
342 g_return_val_if_fail (certdb->filename, -1);
344 filename = alloca (strlen (certdb->filename) + 4);
345 sprintf (filename, "%s~", certdb->filename);
347 fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
351 out = fdopen (fd, "w");
360 CAMEL_CERTDB_LOCK (certdb, io_lock);
362 certdb->saved_certs = certdb->certs->len;
363 if (CAMEL_CERTDB_GET_CLASS (certdb)->header_save (certdb, out) == -1)
366 for (i = 0; i < certdb->saved_certs; i++) {
367 cert = (CamelCert *) certdb->certs->pdata[i];
369 if (CAMEL_CERTDB_GET_CLASS (certdb)->cert_save (certdb, cert, out) == -1)
373 CAMEL_CERTDB_UNLOCK (certdb, io_lock);
375 if (fflush (out) != 0 || fsync (fileno (out)) == -1) {
383 if (fclose (out) != 0) {
390 if (rename (filename, certdb->filename) == -1) {
397 certdb->flags &= ~CAMEL_CERTDB_DIRTY;
403 g_warning ("Cannot save certificate database: %s", strerror (ferror (out)));
405 CAMEL_CERTDB_UNLOCK (certdb, io_lock);
416 camel_certdb_touch (CamelCertDB *certdb)
418 g_return_if_fail (CAMEL_IS_CERTDB (certdb));
420 certdb->flags |= CAMEL_CERTDB_DIRTY;
424 camel_certdb_get_cert (CamelCertDB *certdb, const char *fingerprint)
428 g_return_val_if_fail (CAMEL_IS_CERTDB (certdb), NULL);
430 CAMEL_CERTDB_LOCK (certdb, db_lock);
432 cert = g_hash_table_lookup (certdb->cert_hash, fingerprint);
434 camel_certdb_cert_ref (certdb, cert);
436 CAMEL_CERTDB_UNLOCK (certdb, db_lock);
442 camel_certdb_add (CamelCertDB *certdb, CamelCert *cert)
444 g_return_if_fail (CAMEL_IS_CERTDB (certdb));
446 CAMEL_CERTDB_LOCK (certdb, db_lock);
448 if (g_hash_table_lookup (certdb->cert_hash, cert->fingerprint)) {
449 CAMEL_CERTDB_UNLOCK (certdb, db_lock);
453 camel_certdb_cert_ref (certdb, cert);
454 g_ptr_array_add (certdb->certs, cert);
455 g_hash_table_insert (certdb->cert_hash, cert->fingerprint, cert);
457 certdb->flags |= CAMEL_CERTDB_DIRTY;
459 CAMEL_CERTDB_UNLOCK (certdb, db_lock);
463 camel_certdb_remove (CamelCertDB *certdb, CamelCert *cert)
465 g_return_if_fail (CAMEL_IS_CERTDB (certdb));
467 CAMEL_CERTDB_LOCK (certdb, db_lock);
469 if (g_hash_table_lookup (certdb->cert_hash, cert->fingerprint)) {
470 g_hash_table_remove (certdb->cert_hash, cert->fingerprint);
471 g_ptr_array_remove (certdb->certs, cert);
472 camel_certdb_cert_unref (certdb, cert);
474 certdb->flags |= CAMEL_CERTDB_DIRTY;
477 CAMEL_CERTDB_UNLOCK (certdb, db_lock);
481 certdb_cert_new (CamelCertDB *certdb)
485 if (certdb->cert_chunks)
486 cert = e_memchunk_alloc0 (certdb->cert_chunks);
488 cert = g_malloc0 (certdb->cert_size);
496 camel_certdb_cert_new (CamelCertDB *certdb)
500 g_return_val_if_fail (CAMEL_IS_CERTDB (certdb), NULL);
502 CAMEL_CERTDB_LOCK (certdb, alloc_lock);
504 cert = CAMEL_CERTDB_GET_CLASS (certdb)->cert_new (certdb);
506 CAMEL_CERTDB_UNLOCK (certdb, alloc_lock);
512 camel_certdb_cert_ref (CamelCertDB *certdb, CamelCert *cert)
514 g_return_if_fail (CAMEL_IS_CERTDB (certdb));
515 g_return_if_fail (cert != NULL);
517 CAMEL_CERTDB_LOCK (certdb, ref_lock);
519 CAMEL_CERTDB_UNLOCK (certdb, ref_lock);
523 certdb_cert_free (CamelCertDB *certdb, CamelCert *cert)
525 g_free (cert->issuer);
526 g_free (cert->subject);
527 g_free (cert->hostname);
528 g_free (cert->fingerprint);
532 camel_certdb_cert_unref (CamelCertDB *certdb, CamelCert *cert)
534 g_return_if_fail (CAMEL_IS_CERTDB (certdb));
535 g_return_if_fail (cert != NULL);
537 CAMEL_CERTDB_LOCK (certdb, ref_lock);
539 if (cert->refcount <= 1) {
540 CAMEL_CERTDB_GET_CLASS (certdb)->cert_free (certdb, cert);
541 if (certdb->cert_chunks)
542 e_memchunk_free (certdb->cert_chunks, cert);
549 CAMEL_CERTDB_UNLOCK (certdb, ref_lock);
554 cert_remove (gpointer key, gpointer value, gpointer user_data)
560 camel_certdb_clear (CamelCertDB *certdb)
565 g_return_if_fail (CAMEL_IS_CERTDB (certdb));
567 CAMEL_CERTDB_LOCK (certdb, db_lock);
569 g_hash_table_foreach_remove (certdb->cert_hash, cert_remove, NULL);
570 for (i = 0; i < certdb->certs->len; i++) {
571 cert = (CamelCert *) certdb->certs->pdata[i];
572 camel_certdb_cert_unref (certdb, cert);
575 certdb->saved_certs = 0;
576 g_ptr_array_set_size (certdb->certs, 0);
577 certdb->flags |= CAMEL_CERTDB_DIRTY;
579 CAMEL_CERTDB_UNLOCK (certdb, db_lock);
584 cert_get_string (CamelCertDB *certdb, CamelCert *cert, int string)
587 case CAMEL_CERT_STRING_ISSUER:
589 case CAMEL_CERT_STRING_SUBJECT:
590 return cert->subject;
591 case CAMEL_CERT_STRING_HOSTNAME:
592 return cert->hostname;
593 case CAMEL_CERT_STRING_FINGERPRINT:
594 return cert->fingerprint;
602 camel_cert_get_string (CamelCertDB *certdb, CamelCert *cert, int string)
604 g_return_val_if_fail (CAMEL_IS_CERTDB (certdb), NULL);
605 g_return_val_if_fail (cert != NULL, NULL);
607 /* FIXME: do locking? */
609 return CAMEL_CERTDB_GET_CLASS (certdb)->cert_get_string (certdb, cert, string);
613 cert_set_string (CamelCertDB *certdb, CamelCert *cert, int string, const char *value)
616 case CAMEL_CERT_STRING_ISSUER:
617 g_free (cert->issuer);
618 cert->issuer = g_strdup (value);
620 case CAMEL_CERT_STRING_SUBJECT:
621 g_free (cert->subject);
622 cert->subject = g_strdup (value);
624 case CAMEL_CERT_STRING_HOSTNAME:
625 g_free (cert->hostname);
626 cert->hostname = g_strdup (value);
628 case CAMEL_CERT_STRING_FINGERPRINT:
629 g_free (cert->fingerprint);
630 cert->fingerprint = g_strdup (value);
639 camel_cert_set_string (CamelCertDB *certdb, CamelCert *cert, int string, const char *value)
641 g_return_if_fail (CAMEL_IS_CERTDB (certdb));
642 g_return_if_fail (cert != NULL);
644 /* FIXME: do locking? */
646 CAMEL_CERTDB_GET_CLASS (certdb)->cert_set_string (certdb, cert, string, value);
651 camel_cert_get_trust (CamelCertDB *certdb, CamelCert *cert)
653 g_return_val_if_fail (CAMEL_IS_CERTDB (certdb), CAMEL_CERT_TRUST_UNKNOWN);
654 g_return_val_if_fail (cert != NULL, CAMEL_CERT_TRUST_UNKNOWN);
661 camel_cert_set_trust (CamelCertDB *certdb, CamelCert *cert, CamelCertTrust trust)
663 g_return_if_fail (CAMEL_IS_CERTDB (certdb));
664 g_return_if_fail (cert != NULL);