LCOV - code coverage report
Current view: top level - pkcs11/gkm - gkm-module.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 76.0 % 600 456
Test Date: 2024-04-08 13:24:42 Functions: 81.8 % 66 54

            Line data    Source code
       1              : /*
       2              :  * gnome-keyring
       3              :  *
       4              :  * Copyright (C) 2008 Stefan Walter
       5              :  *
       6              :  * This program is free software; you can redistribute it and/or modify
       7              :  * it under the terms of the GNU Lesser General Public License as
       8              :  * published by the Free Software Foundation; either version 2.1 of
       9              :  * the License, or (at your option) any later version.
      10              :  *
      11              :  * This program is distributed in the hope that it will be useful, but
      12              :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      13              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14              :  * Lesser General Public License for more details.
      15              :  *
      16              :  * You should have received a copy of the GNU Lesser General Public
      17              :  * License along with this program; if not, see
      18              :  * <http://www.gnu.org/licenses/>.
      19              :  */
      20              : 
      21              : #include "config.h"
      22              : 
      23              : #include "pkcs11/pkcs11.h"
      24              : #include "pkcs11/pkcs11i.h"
      25              : 
      26              : #include "gkm-aes-key.h"
      27              : #include "gkm-aes-mechanism.h"
      28              : #include "gkm-attributes.h"
      29              : #include "gkm-certificate.h"
      30              : #include "gkm-credential.h"
      31              : #include "gkm-factory.h"
      32              : #include "gkm-generic-key.h"
      33              : #include "gkm-manager.h"
      34              : #include "gkm-memory-store.h"
      35              : #include "gkm-module.h"
      36              : #include "gkm-null-key.h"
      37              : #include "gkm-null-mechanism.h"
      38              : #include "gkm-dh-private-key.h"
      39              : #include "gkm-private-xsa-key.h"
      40              : #include "gkm-dh-public-key.h"
      41              : #include "gkm-public-xsa-key.h"
      42              : #include "gkm-session.h"
      43              : #include "gkm-store.h"
      44              : #include "gkm-timer.h"
      45              : #include "gkm-transaction.h"
      46              : #include "gkm-util.h"
      47              : 
      48              : enum {
      49              :         PROP_0,
      50              :         PROP_MANAGER,
      51              :         PROP_WRITE_PROTECTED,
      52              :         PROP_INITIALIZE_ARGS,
      53              :         PROP_MUTEX
      54              : };
      55              : 
      56              : #define APARTMENT_APP(apt) \
      57              :         ((apt) & ~CK_GNOME_MAX_SLOT)
      58              : #define APARTMENT_SLOT(apt) \
      59              :         ((apt) & CK_GNOME_MAX_SLOT)
      60              : #define APARTMENT_ID(slot, app) \
      61              :         (((slot) & CK_GNOME_MAX_SLOT) | ((app) & ~CK_GNOME_MAX_SLOT))
      62              : 
      63              : struct _GkmModulePrivate {
      64              :         GMutex *mutex;                          /* The mutex controlling entry to this module */
      65              : 
      66              :         GkmManager *token_manager;
      67              :         GHashTable *apartments_by_id;           /* Apartment (slot + application) by their id */
      68              :         GHashTable *sessions_by_handle;         /* Mapping of handle to all open sessions */
      69              :         gulong handle_counter;                  /* Constantly incrementing counter for handles and the like */
      70              :         GArray *factories;                      /* Various registered object factories */
      71              :         gboolean factories_sorted;              /* Whether we need to sort the object factories */
      72              : 
      73              :         GHashTable *transient_objects;          /* Token objects that are not stored permanently. */
      74              :         GkmStore *transient_store;              /* Store for trantsient objects. */
      75              : };
      76              : 
      77              : typedef struct _Apartment {
      78              :         CK_ULONG apt_id;
      79              :         CK_SLOT_ID slot_id;
      80              :         CK_G_APPLICATION_ID app_id;
      81              :         CK_G_APPLICATION_PTR app_ptr;
      82              :         GkmManager *session_manager;
      83              :         GList *sessions;
      84              :         CK_USER_TYPE logged_in;
      85              : } Apartment;
      86              : 
      87        24688 : G_DEFINE_TYPE_WITH_PRIVATE (GkmModule, gkm_module, G_TYPE_OBJECT);
      88              : 
      89              : /* These info blocks are used unless derived class overrides */
      90              : 
      91              : static const CK_INFO default_module_info = {
      92              :         { CRYPTOKI_VERSION_MAJOR, CRYPTOKI_VERSION_MINOR },
      93              :         "Gnome Keyring",
      94              :         CKF_G_APPLICATIONS,
      95              :         "Gnome Keyring Module",
      96              :         { 1, 1 },
      97              : };
      98              : 
      99              : static const CK_SLOT_INFO default_slot_info = {
     100              :         "Unnamed Slot",
     101              :         "Gnome Keyring",
     102              :         CKF_TOKEN_PRESENT,
     103              :         { 0, 0 },
     104              :         { 0, 0 }
     105              : };
     106              : 
     107              : static const CK_TOKEN_INFO default_token_info = {
     108              :         "Unnamed Token",
     109              :         "Gnome Keyring",
     110              :         "1.0",
     111              :         "1",
     112              :         CKF_TOKEN_INITIALIZED | CKF_WRITE_PROTECTED,
     113              :         CK_EFFECTIVELY_INFINITE,
     114              :         CK_EFFECTIVELY_INFINITE,
     115              :         CK_EFFECTIVELY_INFINITE,
     116              :         CK_EFFECTIVELY_INFINITE,
     117              :         1024,
     118              :         1,
     119              :         CK_UNAVAILABLE_INFORMATION,
     120              :         CK_UNAVAILABLE_INFORMATION,
     121              :         CK_UNAVAILABLE_INFORMATION,
     122              :         CK_UNAVAILABLE_INFORMATION,
     123              :         { 0, 0 },
     124              :         { 0, 0 },
     125              :         ""
     126              : };
     127              : 
     128              : typedef struct _MechanismAndInfo {
     129              :         CK_MECHANISM_TYPE mechanism;
     130              :         CK_MECHANISM_INFO info;
     131              : } MechanismAndInfo;
     132              : 
     133              : static const MechanismAndInfo mechanism_list[] = {
     134              :         /*
     135              :          * CKM_RSA_PKCS
     136              :          * For RSA, min and max are the minimum and maximum modulus in bits
     137              :          */
     138              :         { CKM_RSA_PKCS, { 256, 32768, CKF_ENCRYPT | CKF_DECRYPT | CKF_SIGN | CKF_VERIFY } },
     139              : 
     140              :         /*
     141              :          * CKM_RSA_X509
     142              :          * For RSA, min and max are the minimum and maximum modulus in bits
     143              :          */
     144              :         { CKM_RSA_X_509, { 256, 32768, CKF_ENCRYPT | CKF_DECRYPT | CKF_SIGN | CKF_VERIFY } },
     145              : 
     146              :         /*
     147              :          * CKM_DSA
     148              :          * For DSA, min and max are the minimum and maximum modulus in bits
     149              :          */
     150              :         { CKM_DSA, { 512, 1024, CKF_SIGN | CKF_VERIFY } },
     151              : 
     152              :         /*
     153              :          * CKM_DH_PKCS_KEY_PAIR_GEN
     154              :          * For DH derivation the min and max are sizes of prime in bits.
     155              :          */
     156              :         { CKM_DH_PKCS_KEY_PAIR_GEN, { 768, 8192, CKF_GENERATE_KEY_PAIR } },
     157              : 
     158              :         /*
     159              :          * CKM_DH_PKCS_DERIVE
     160              :          * For DH derivation the min and max are sizes of output key in bytes.
     161              :          */
     162              :         { CKM_DH_PKCS_DERIVE, { 1, 255, CKF_DERIVE } },
     163              : 
     164              :         /*
     165              :          * CKM_ECDSA
     166              :          * For ECDSA, min and max are the minimum and maximum modulus in bits
     167              :          */
     168              :         { CKM_ECDSA, { 256, 521, CKF_SIGN | CKF_VERIFY } },
     169              : 
     170              :         /*
     171              :          * CKM_G_HKDF_DERIVE
     172              :          * For HKDF derivation the min and max are sizes of prime in bits.
     173              :          */
     174              :         { CKM_G_HKDF_SHA256_DERIVE, { 768, 8192, CKF_DERIVE } },
     175              : 
     176              :         /*
     177              :          * CKM_AES_CBC_PAD
     178              :          * For AES the min and max are sizes of key in bytes.
     179              :          */
     180              :         { CKM_AES_CBC_PAD, { GKM_AES_MECHANISM_MIN_LENGTH, GKM_AES_MECHANISM_MAX_LENGTH, CKF_WRAP | CKF_UNWRAP } },
     181              : 
     182              :         /*
     183              :          * CKM_G_NULL
     184              :          * For NULL min and max are zero
     185              :          */
     186              :         { CKM_G_NULL, { GKM_NULL_MECHANISM_MIN_LENGTH, GKM_NULL_MECHANISM_MAX_LENGTH, CKF_WRAP | CKF_UNWRAP } },
     187              : };
     188              : 
     189              : /* Hidden function that you should not use */
     190              : GMutex* _gkm_module_get_scary_mutex_that_you_should_not_touch (GkmModule *self);
     191              : 
     192              : static void  remove_transient_object (GkmModule *self, GkmTransaction *transaction, GkmObject *object);
     193              : 
     194              : static void  add_transient_object    (GkmModule *self, GkmTransaction *transaction, GkmObject *object);
     195              : 
     196              : /* -----------------------------------------------------------------------------
     197              :  * INTERNAL
     198              :  */
     199              : 
     200              : static gint
     201         1215 : sort_factory_by_n_attrs (gconstpointer a, gconstpointer b)
     202              : {
     203         1215 :         const GkmFactory *fa = a;
     204         1215 :         const GkmFactory *fb = b;
     205              : 
     206         1215 :         g_assert (a);
     207         1215 :         g_assert (b);
     208              : 
     209              :         /* Note we're sorting in reverse order */
     210         1215 :         if (fa->n_attrs < fb->n_attrs)
     211          403 :                 return 1;
     212          812 :         return (fa->n_attrs == fb->n_attrs) ? 0 : -1;
     213              : }
     214              : 
     215              : static void
     216          966 : extend_space_string (CK_UTF8CHAR_PTR string, gsize length)
     217              : {
     218              :         CK_UTF8CHAR_PTR at;
     219              : 
     220              :         /* Find a null pointer in the string */
     221          966 :         at = memchr (string, 0, length);
     222          966 :         g_assert (at != NULL && at < string + length);
     223        25532 :         for (; at < string + length; ++at)
     224        24566 :                 *at = ' ';
     225          966 : }
     226              : 
     227              : static void
     228          208 : apartment_free (gpointer data)
     229              : {
     230              :         Apartment *apt;
     231              :         GList *l;
     232              : 
     233          208 :         g_assert (data != NULL);
     234          208 :         apt = (Apartment*)data;
     235              : 
     236          208 :         g_return_if_fail (GKM_IS_MANAGER (apt->session_manager));
     237              : 
     238              :         /* Unreference all the sessions */
     239          362 :         for (l = apt->sessions; l; l = g_list_next (l)) {
     240              : 
     241              :                 /* Some sanity checks to make sure things have remained as expected */
     242          154 :                 g_return_if_fail (GKM_IS_SESSION (l->data));
     243          154 :                 g_return_if_fail (gkm_session_get_apartment (l->data) == apt->apt_id);
     244          154 :                 g_return_if_fail (gkm_session_get_manager (l->data) == apt->session_manager);
     245          154 :                 g_return_if_fail (gkm_session_get_logged_in (l->data) == apt->logged_in);
     246              : 
     247          154 :                 g_object_unref (l->data);
     248              :         }
     249              : 
     250          208 :         g_list_free (apt->sessions);
     251          208 :         g_object_unref (apt->session_manager);
     252              : 
     253          208 :         g_slice_free (Apartment, apt);
     254              : }
     255              : 
     256              : static Apartment*
     257          208 : apartment_new (GkmModuleClass *klass, CK_SLOT_ID slot_id, CK_G_APPLICATION_PTR app)
     258              : {
     259              :         Apartment *apt;
     260              : 
     261          208 :         apt = g_slice_new0 (Apartment);
     262          208 :         apt->session_manager = g_object_new (GKM_TYPE_MANAGER, "for-token", FALSE, NULL);
     263          208 :         apt->logged_in = CKU_NONE;
     264          208 :         apt->sessions = NULL;
     265          208 :         apt->slot_id = slot_id;
     266              : 
     267          208 :         if (app) {
     268           17 :                 if (!app->applicationId)
     269           17 :                         app->applicationId = gkm_util_next_handle () << 8;
     270           17 :                 apt->app_id = app->applicationId;
     271           17 :                 apt->app_ptr = app;
     272              :         } else {
     273          191 :                 apt->app_id = 0;
     274          191 :                 apt->app_ptr = NULL;
     275              :         }
     276              : 
     277          208 :         apt->apt_id = APARTMENT_ID (apt->slot_id, apt->app_id);
     278              : 
     279          208 :         return apt;
     280              : }
     281              : 
     282              : static Apartment*
     283          686 : lookup_apartment (GkmModule *self, CK_ULONG apartment)
     284              : {
     285          686 :         g_assert (GKM_IS_MODULE (self));
     286          686 :         return g_hash_table_lookup (self->pv->apartments_by_id, &apartment);
     287              : }
     288              : 
     289              : static void
     290          208 : register_apartment (GkmModule *self, Apartment *apt)
     291              : {
     292          208 :         g_assert (apt);
     293          208 :         g_assert (GKM_IS_MODULE (self));
     294          208 :         g_assert (!g_hash_table_lookup (self->pv->apartments_by_id, &(apt->apt_id)));
     295              : 
     296          208 :         g_hash_table_insert (self->pv->apartments_by_id,
     297          208 :                              gkm_util_ulong_alloc (apt->apt_id), apt);
     298          208 : }
     299              : 
     300              : static void
     301           54 : unregister_apartment (GkmModule *self, Apartment *apt)
     302              : {
     303           54 :         g_assert (apt);
     304           54 :         g_assert (GKM_IS_MODULE (self));
     305              : 
     306           54 :         switch (apt->logged_in) {
     307            0 :         case CKU_NONE:
     308            0 :                 break;
     309           50 :         case CKU_USER:
     310           50 :                 gkm_module_logout_user (self, apt->apt_id);
     311           50 :                 break;
     312            4 :         case CKU_SO:
     313            4 :                 gkm_module_logout_so (self, apt->apt_id);
     314            4 :                 break;
     315            0 :         default:
     316            0 :                 g_return_if_reached ();
     317              :                 break;
     318              :         }
     319              : 
     320           54 :         if (!g_hash_table_remove (self->pv->apartments_by_id, &(apt->apt_id)))
     321            0 :                 g_assert_not_reached ();
     322              : }
     323              : 
     324              : static void
     325          237 : mark_login_apartment (GkmModule *self, Apartment *apt, CK_USER_TYPE user)
     326              : {
     327              :         GList *l;
     328              : 
     329          237 :         g_assert (apt);
     330          237 :         g_assert (GKM_IS_MODULE (self));
     331              : 
     332              :         /* Mark all sessions in the partition as logged in */
     333          420 :         for (l = apt->sessions; l; l = g_list_next (l))
     334          183 :                 gkm_session_set_logged_in (l->data, user);
     335          237 :         apt->logged_in = user;
     336          237 : }
     337              : 
     338              : static void
     339          223 : parse_argument (GkmModule *self, char *arg)
     340              : {
     341              :         gchar *value;
     342              : 
     343          223 :         g_assert (GKM_IS_MODULE (self));
     344              : 
     345          223 :         value = arg + strcspn (arg, ":=");
     346          223 :         if (!*value)
     347            0 :                 value = NULL;
     348              :         else
     349          223 :                 *(value++) = 0;
     350              : 
     351          223 :         g_strstrip (arg);
     352          223 :         if (value)
     353          223 :                 g_strstrip (value);
     354              : 
     355          223 :         g_return_if_fail (GKM_MODULE_GET_CLASS (self)->parse_argument);
     356          223 :         GKM_MODULE_GET_CLASS (self)->parse_argument (self, arg, value);
     357              : }
     358              : 
     359              : static void
     360          223 : parse_arguments (GkmModule *self, const gchar *string)
     361              : {
     362          223 :         gchar quote = '\0';
     363              :         gchar *src, *dup, *at, *arg;
     364              : 
     365          223 :         g_assert (GKM_IS_MODULE (self));
     366              : 
     367          223 :         if (!string)
     368            0 :                 return;
     369              : 
     370          223 :         src = dup = g_strdup (string);
     371              : 
     372          223 :         arg = at = src;
     373        10963 :         for (src = dup; *src; src++) {
     374              : 
     375              :                 /* Matching quote */
     376        10740 :                 if (quote == *src) {
     377          223 :                         quote = '\0';
     378              : 
     379              :                 /* Inside of quotes */
     380        10517 :                 } else if (quote != '\0') {
     381         8064 :                         if (*src == '\\') {
     382            0 :                                 *at++ = *src++;
     383            0 :                                 if (!*src) {
     384            0 :                                         g_warning ("couldn't parse module argument string");
     385            0 :                                         goto done;
     386              :                                 }
     387            0 :                                 if (*src != quote)
     388            0 :                                         *at++ = '\\';
     389              :                         }
     390         8064 :                         *at++ = *src;
     391              : 
     392              :                 /* Space, not inside of quotes */
     393         2453 :                 } else if (g_ascii_isspace(*src)) {
     394            0 :                         *at = 0;
     395            0 :                         parse_argument (self, arg);
     396            0 :                         arg = at;
     397              : 
     398              :                 /* Other character outside of quotes */
     399              :                 } else {
     400         2453 :                         switch (*src) {
     401          223 :                         case '\'':
     402              :                         case '"':
     403          223 :                                 quote = *src;
     404          223 :                                 break;
     405            0 :                         case '\\':
     406            0 :                                 *at++ = *src++;
     407            0 :                                 if (!*src) {
     408            0 :                                         g_warning ("couldn't parse module argument string");
     409            0 :                                         goto done;
     410              :                                 }
     411              :                                 /* fall through */
     412              :                         default:
     413         2230 :                                 *at++ = *src;
     414         2230 :                                 break;
     415              :                         }
     416              :                 }
     417              :         }
     418              : 
     419              : 
     420          223 :         if (at != arg) {
     421          223 :                 *at = 0;
     422          223 :                 parse_argument (self, arg);
     423              :         }
     424              : 
     425            0 : done:
     426          223 :         g_free (dup);
     427              : }
     428              : 
     429              : 
     430              : static gboolean
     431           22 : complete_transient_remove (GkmTransaction *transaction, GkmModule *self, GkmObject *object)
     432              : {
     433           22 :         if (gkm_transaction_get_failed (transaction))
     434            0 :                 add_transient_object (self, NULL, object);
     435           22 :         g_object_unref (object);
     436           22 :         return TRUE;
     437              : }
     438              : 
     439              : static void
     440           23 : remove_transient_object (GkmModule *self, GkmTransaction *transaction, GkmObject *object)
     441              : {
     442           23 :         g_assert (GKM_IS_MODULE (self));
     443           23 :         g_assert (GKM_IS_OBJECT (object));
     444              : 
     445           23 :         g_object_ref (object);
     446              : 
     447           23 :         gkm_object_expose (object, FALSE);
     448           23 :         if (!g_hash_table_remove (self->pv->transient_objects, object))
     449            0 :                 g_return_if_reached ();
     450           23 :         g_object_set (object, "store", NULL, NULL);
     451              : 
     452           23 :         if (transaction) {
     453           22 :                 gkm_transaction_add (transaction, self,
     454              :                                      (GkmTransactionFunc)complete_transient_remove,
     455              :                                      g_object_ref (object));
     456              :         }
     457              : 
     458           23 :         g_object_unref (object);
     459              : }
     460              : 
     461              : static gboolean
     462           23 : complete_transient_add (GkmTransaction *transaction, GkmModule *self, GkmObject *object)
     463              : {
     464           23 :         if (gkm_transaction_get_failed (transaction))
     465            1 :                 remove_transient_object (self, NULL, object);
     466           23 :         g_object_unref (object);
     467           23 :         return TRUE;
     468              : }
     469              : 
     470              : static void
     471          132 : add_transient_object (GkmModule *self, GkmTransaction *transaction, GkmObject *object)
     472              : {
     473          132 :         g_assert (GKM_IS_MODULE (self));
     474          132 :         g_assert (GKM_IS_OBJECT (object));
     475              : 
     476              :         /* Must not already be associated with a session or manager */
     477          132 :         g_return_if_fail (gkm_object_get_manager (object) == self->pv->token_manager);
     478          132 :         g_return_if_fail (g_hash_table_lookup (self->pv->transient_objects, object) == NULL);
     479              : 
     480          132 :         g_hash_table_insert (self->pv->transient_objects, object, g_object_ref (object));
     481          132 :         g_object_set (object, "store", self->pv->transient_store, NULL);
     482          132 :         gkm_object_expose (object, TRUE);
     483              : 
     484          132 :         if (transaction) {
     485           23 :                 gkm_transaction_add (transaction, self,
     486              :                                      (GkmTransactionFunc)complete_transient_add,
     487              :                                      g_object_ref (object));
     488              :         }
     489              : }
     490              : 
     491              : /* -----------------------------------------------------------------------------
     492              :  * OBJECT
     493              :  */
     494              : 
     495              : static const CK_SLOT_INFO*
     496            0 : gkm_module_real_get_slot_info (GkmModule *self)
     497              : {
     498            0 :         return &default_slot_info;
     499              : }
     500              : 
     501              : static const CK_TOKEN_INFO*
     502            0 : gkm_module_real_get_token_info (GkmModule *self)
     503              : {
     504            0 :         return &default_token_info;
     505              : }
     506              : 
     507              : static void
     508            0 : gkm_module_real_parse_argument (GkmModule *self, const gchar *name, const gchar *value)
     509              : {
     510              :         /* Derived classes should do something interesting */
     511            0 : }
     512              : 
     513              : static CK_RV
     514            2 : gkm_module_real_refresh_token (GkmModule *self)
     515              : {
     516              :         /* Derived classes should do something interesting */
     517            2 :         return CKR_OK;
     518              : }
     519              : 
     520              : static void
     521            0 : gkm_module_real_add_token_object (GkmModule *self, GkmTransaction *transaction, GkmObject *object)
     522              : {
     523              :         /* Derived class should override, default does nothing */
     524            0 : }
     525              : 
     526              : static void
     527            0 : gkm_module_real_store_token_object (GkmModule *self, GkmTransaction *transaction, GkmObject *object)
     528              : {
     529              :         /* Derived classes should do something interesting */
     530            0 :         gkm_transaction_fail (transaction, CKR_FUNCTION_NOT_SUPPORTED);
     531            0 : }
     532              : 
     533              : static void
     534            0 : gkm_module_real_remove_token_object (GkmModule *self, GkmTransaction *transaction, GkmObject *object)
     535              : {
     536              :         /* Derived classes should do something interesting */
     537            0 :         gkm_transaction_fail (transaction, CKR_FUNCTION_NOT_SUPPORTED);
     538            0 : }
     539              : 
     540              : static CK_RV
     541            2 : gkm_module_real_login_change (GkmModule *self, CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR old_pin,
     542              :                               CK_ULONG n_old_pin, CK_UTF8CHAR_PTR new_pin, CK_ULONG n_new_pin)
     543              : {
     544            2 :         return CKR_FUNCTION_NOT_SUPPORTED;
     545              : }
     546              : 
     547              : static CK_RV
     548          179 : gkm_module_real_login_user (GkmModule *self, CK_ULONG apartment, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
     549              : {
     550              :         Apartment *apt;
     551              : 
     552          179 :         apt = lookup_apartment (self, apartment);
     553          179 :         g_return_val_if_fail (apt, CKR_GENERAL_ERROR);
     554              : 
     555          179 :         mark_login_apartment (self, apt, CKU_USER);
     556          179 :         return CKR_OK;
     557              : }
     558              : 
     559              : static CK_RV
     560            4 : gkm_module_real_login_so (GkmModule *self, CK_ULONG apartment, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
     561              : {
     562              :         Apartment *apt;
     563              : 
     564            4 :         apt = lookup_apartment (self, apartment);
     565            4 :         g_return_val_if_fail (apt, CKR_GENERAL_ERROR);
     566              : 
     567            4 :         mark_login_apartment (self, apt, CKU_SO);
     568            4 :         return CKR_OK;
     569              : }
     570              : 
     571              : static CK_RV
     572           54 : gkm_module_real_logout_any (GkmModule *self, CK_ULONG apartment)
     573              : {
     574              :         Apartment *apt;
     575              : 
     576              :         /* Calculate the partition identifier */
     577           54 :         apt = lookup_apartment (self, apartment);
     578           54 :         g_return_val_if_fail (apt, CKR_GENERAL_ERROR);
     579              : 
     580           54 :         mark_login_apartment (self, apt, CKU_NONE);
     581           54 :         return CKR_OK;
     582              : }
     583              : 
     584              : static GObject*
     585          287 : gkm_module_constructor (GType type, guint n_props, GObjectConstructParam *props)
     586              : {
     587          287 :         GkmModule *self = GKM_MODULE (G_OBJECT_CLASS (gkm_module_parent_class)->constructor(type, n_props, props));
     588              :         CK_ATTRIBUTE attr;
     589              : 
     590          287 :         g_return_val_if_fail (self, NULL);
     591              : 
     592              :         /* Register store attributes */
     593          287 :         attr.type = CKA_LABEL;
     594          287 :         attr.pValue = "";
     595          287 :         attr.ulValueLen = 0;
     596          287 :         gkm_store_register_schema (self->pv->transient_store, &attr, NULL, 0);
     597              : 
     598          287 :         return G_OBJECT (self);
     599              : }
     600              : 
     601              : static void
     602          287 : gkm_module_init (GkmModule *self)
     603              : {
     604          287 :         gkm_timer_initialize ();
     605              : 
     606          287 :         self->pv = gkm_module_get_instance_private (self);
     607          287 :         self->pv->token_manager = g_object_new (GKM_TYPE_MANAGER, "for-token", TRUE, NULL);
     608          287 :         self->pv->sessions_by_handle = g_hash_table_new_full (gkm_util_ulong_hash, gkm_util_ulong_equal,
     609              :                                                               gkm_util_ulong_free, g_object_unref);
     610          287 :         self->pv->apartments_by_id = g_hash_table_new_full (gkm_util_ulong_hash, gkm_util_ulong_equal,
     611              :                                                             gkm_util_ulong_free, apartment_free);
     612          287 :         self->pv->factories = g_array_new (FALSE, TRUE, sizeof (GkmFactory));
     613              : 
     614          287 :         self->pv->handle_counter = 1;
     615              : 
     616              :         /* Create the store for transient objects */
     617          287 :         self->pv->transient_store = GKM_STORE (gkm_memory_store_new ());
     618          287 :         self->pv->transient_objects = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, gkm_util_dispose_unref);
     619              : 
     620              :         /* Register session object factories */
     621          287 :         gkm_module_register_factory (self, GKM_FACTORY_AES_KEY);
     622          287 :         gkm_module_register_factory (self, GKM_FACTORY_CERTIFICATE);
     623          287 :         gkm_module_register_factory (self, GKM_FACTORY_CREDENTIAL);
     624          287 :         gkm_module_register_factory (self, GKM_FACTORY_GENERIC_KEY);
     625          287 :         gkm_module_register_factory (self, GKM_FACTORY_NULL_KEY);
     626          287 :         gkm_module_register_factory (self, GKM_FACTORY_DH_PRIVATE_KEY);
     627          287 :         gkm_module_register_factory (self, GKM_FACTORY_PRIVATE_XSA_KEY);
     628          287 :         gkm_module_register_factory (self, GKM_FACTORY_DH_PUBLIC_KEY);
     629          287 :         gkm_module_register_factory (self, GKM_FACTORY_PUBLIC_XSA_KEY);
     630          287 : }
     631              : 
     632              : static void
     633          574 : gkm_module_dispose (GObject *obj)
     634              : {
     635          574 :         GkmModule *self = GKM_MODULE (obj);
     636              : 
     637          574 :         g_hash_table_remove_all (self->pv->transient_objects);
     638          574 :         g_hash_table_remove_all (self->pv->sessions_by_handle);
     639          574 :         g_hash_table_remove_all (self->pv->apartments_by_id);
     640              : 
     641          574 :         if (self->pv->token_manager)
     642          287 :                 g_object_unref (self->pv->token_manager);
     643          574 :         self->pv->token_manager = NULL;
     644              : 
     645          574 :         g_array_set_size (self->pv->factories, 0);
     646              : 
     647          574 :         G_OBJECT_CLASS (gkm_module_parent_class)->dispose (obj);
     648          574 : }
     649              : 
     650              : static void
     651          287 : gkm_module_finalize (GObject *obj)
     652              : {
     653          287 :         GkmModule *self = GKM_MODULE (obj);
     654              : 
     655          287 :         g_hash_table_destroy (self->pv->transient_objects);
     656          287 :         self->pv->transient_objects = NULL;
     657              : 
     658          287 :         g_object_unref (self->pv->transient_store);
     659          287 :         self->pv->transient_store = NULL;
     660              : 
     661          287 :         g_assert (self->pv->token_manager == NULL);
     662              : 
     663          287 :         g_assert (g_hash_table_size (self->pv->apartments_by_id) == 0);
     664          287 :         g_hash_table_destroy (self->pv->apartments_by_id);
     665          287 :         self->pv->apartments_by_id = NULL;
     666              : 
     667          287 :         g_assert (g_hash_table_size (self->pv->sessions_by_handle) == 0);
     668          287 :         g_hash_table_destroy (self->pv->sessions_by_handle);
     669          287 :         self->pv->sessions_by_handle = NULL;
     670              : 
     671          287 :         g_array_free (self->pv->factories, TRUE);
     672          287 :         self->pv->factories = NULL;
     673              : 
     674          287 :         gkm_timer_shutdown ();
     675              : 
     676          287 :         G_OBJECT_CLASS (gkm_module_parent_class)->finalize (obj);
     677          287 : }
     678              : 
     679              : static void
     680          574 : gkm_module_set_property (GObject *obj, guint prop_id, const GValue *value,
     681              :                          GParamSpec *pspec)
     682              : {
     683          574 :         GkmModule *self = GKM_MODULE (obj);
     684              :         CK_C_INITIALIZE_ARGS_PTR args;
     685              : 
     686          574 :         switch (prop_id) {
     687          287 :         case PROP_INITIALIZE_ARGS:
     688          287 :                 args = g_value_get_pointer (value);
     689          287 :                 if (args != NULL && args->pReserved != NULL)
     690          223 :                         parse_arguments (self, args->pReserved);
     691          287 :                 break;
     692          287 :         case PROP_MUTEX:
     693          287 :                 self->pv->mutex = g_value_get_pointer (value);
     694          287 :                 g_return_if_fail (self->pv->mutex);
     695          287 :                 break;
     696            0 :         default:
     697            0 :                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
     698            0 :                 break;
     699              :         }
     700              : }
     701              : 
     702              : static void
     703            0 : gkm_module_get_property (GObject *obj, guint prop_id, GValue *value,
     704              :                          GParamSpec *pspec)
     705              : {
     706            0 :         GkmModule *self = GKM_MODULE (obj);
     707              : 
     708            0 :         switch (prop_id) {
     709            0 :         case PROP_MANAGER:
     710            0 :                 g_value_set_object (value, gkm_module_get_manager (self));
     711            0 :                 break;
     712            0 :         case PROP_WRITE_PROTECTED:
     713            0 :                 g_value_set_boolean (value, gkm_module_get_write_protected (self));
     714            0 :                 break;
     715            0 :         default:
     716            0 :                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
     717            0 :                 break;
     718              :         }
     719            0 : }
     720              : 
     721              : static void
     722           47 : gkm_module_class_init (GkmModuleClass *klass)
     723              : {
     724           47 :         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
     725              : 
     726           47 :         gobject_class->constructor = gkm_module_constructor;
     727           47 :         gobject_class->dispose = gkm_module_dispose;
     728           47 :         gobject_class->finalize = gkm_module_finalize;
     729           47 :         gobject_class->set_property = gkm_module_set_property;
     730           47 :         gobject_class->get_property = gkm_module_get_property;
     731              : 
     732           47 :         klass->get_slot_info = gkm_module_real_get_slot_info;
     733           47 :         klass->get_token_info = gkm_module_real_get_token_info;
     734           47 :         klass->parse_argument = gkm_module_real_parse_argument;
     735           47 :         klass->refresh_token = gkm_module_real_refresh_token;
     736           47 :         klass->add_token_object = gkm_module_real_add_token_object;
     737           47 :         klass->store_token_object = gkm_module_real_store_token_object;
     738           47 :         klass->remove_token_object = gkm_module_real_remove_token_object;
     739           47 :         klass->login_change = gkm_module_real_login_change;
     740           47 :         klass->login_user = gkm_module_real_login_user;
     741           47 :         klass->logout_user = gkm_module_real_logout_any;
     742           47 :         klass->login_so = gkm_module_real_login_so;
     743           47 :         klass->logout_so = gkm_module_real_logout_any;
     744              : 
     745           47 :         g_object_class_install_property (gobject_class, PROP_MANAGER,
     746              :                    g_param_spec_object ("manager", "Manager", "Token object manager",
     747              :                                         GKM_TYPE_MANAGER, G_PARAM_READABLE));
     748              : 
     749           47 :         g_object_class_install_property (gobject_class, PROP_WRITE_PROTECTED,
     750              :                    g_param_spec_boolean ("write-protected", "Write Protected", "Token is write protected",
     751              :                                          TRUE, G_PARAM_READABLE));
     752              : 
     753           47 :         g_object_class_install_property (gobject_class, PROP_INITIALIZE_ARGS,
     754              :                    g_param_spec_pointer ("initialize-args", "Initialize Args", "Arguments passed to C_Initialize",
     755              :                                          G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
     756              : 
     757           47 :         g_object_class_install_property (gobject_class, PROP_MUTEX,
     758              :                    g_param_spec_pointer ("mutex", "Mutex", "Module mutex",
     759              :                                          G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
     760           47 : }
     761              : 
     762              : /* -----------------------------------------------------------------------------
     763              :  * PUBLIC
     764              :  */
     765              : 
     766              : GkmManager*
     767         3390 : gkm_module_get_manager (GkmModule *self)
     768              : {
     769         3390 :         g_return_val_if_fail (GKM_IS_MODULE (self), NULL);
     770         3390 :         g_return_val_if_fail (GKM_IS_MANAGER (self->pv->token_manager), NULL);
     771         3390 :         return self->pv->token_manager;
     772              : }
     773              : 
     774              : gboolean
     775           31 : gkm_module_get_write_protected (GkmModule *self)
     776              : {
     777              :         const CK_TOKEN_INFO* info;
     778              : 
     779           31 :         g_return_val_if_fail (GKM_IS_MODULE (self), TRUE);
     780           31 :         g_return_val_if_fail (GKM_MODULE_GET_CLASS (self)->get_token_info, TRUE);
     781              : 
     782           31 :         info = (GKM_MODULE_GET_CLASS (self)->get_token_info) (self);
     783           31 :         g_return_val_if_fail (info, TRUE);
     784              : 
     785           31 :         return info->flags & CKF_WRITE_PROTECTED;
     786              : }
     787              : 
     788              : GkmSession*
     789         1690 : gkm_module_lookup_session (GkmModule *self, CK_SESSION_HANDLE handle)
     790              : {
     791              :         GkmSession *session;
     792              : 
     793         1690 :         g_return_val_if_fail (GKM_IS_MODULE (self), NULL);
     794              : 
     795         1690 :         session = g_hash_table_lookup (self->pv->sessions_by_handle, &handle);
     796         1690 :         if (!session)
     797            0 :                 return NULL;
     798              : 
     799         1690 :         g_return_val_if_fail (GKM_IS_SESSION (session), NULL);
     800         1690 :         return session;
     801              : }
     802              : 
     803              : CK_RV
     804            5 : gkm_module_login_change (GkmModule *self, CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR old_pin,
     805              :                          CK_ULONG n_old_pin, CK_UTF8CHAR_PTR new_pin, CK_ULONG n_new_pin)
     806              : {
     807            5 :         g_return_val_if_fail (GKM_IS_MODULE (self), CKR_GENERAL_ERROR);
     808            5 :         g_assert (GKM_MODULE_GET_CLASS (self)->login_change);
     809            5 :         return GKM_MODULE_GET_CLASS (self)->login_change (self, slot_id, old_pin, n_old_pin, new_pin, n_new_pin);
     810              : }
     811              : 
     812              : CK_RV
     813          179 : gkm_module_login_user (GkmModule *self, CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
     814              : {
     815          179 :         g_return_val_if_fail (GKM_IS_MODULE (self), CKR_GENERAL_ERROR);
     816          179 :         g_assert (GKM_MODULE_GET_CLASS (self)->login_user);
     817          179 :         return GKM_MODULE_GET_CLASS (self)->login_user (self, slot_id, pin, n_pin);
     818              : }
     819              : 
     820              : CK_RV
     821           50 : gkm_module_logout_user (GkmModule *self, CK_SLOT_ID slot_id)
     822              : {
     823           50 :         g_return_val_if_fail (GKM_IS_MODULE (self), CKR_GENERAL_ERROR);
     824           50 :         g_assert (GKM_MODULE_GET_CLASS (self)->logout_user);
     825           50 :         return GKM_MODULE_GET_CLASS (self)->logout_user (self, slot_id);
     826              : }
     827              : 
     828              : CK_RV
     829            4 : gkm_module_login_so (GkmModule *self, CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
     830              : {
     831            4 :         g_return_val_if_fail (GKM_IS_MODULE (self), CKR_GENERAL_ERROR);
     832            4 :         g_assert (GKM_MODULE_GET_CLASS (self)->login_so);
     833            4 :         return GKM_MODULE_GET_CLASS (self)->login_so (self, slot_id, pin, n_pin);
     834              : }
     835              : 
     836              : CK_RV
     837            4 : gkm_module_logout_so (GkmModule *self, CK_SLOT_ID slot_id)
     838              : {
     839            4 :         g_return_val_if_fail (GKM_IS_MODULE (self), CKR_GENERAL_ERROR);
     840            4 :         g_assert (GKM_MODULE_GET_CLASS (self)->logout_so);
     841            4 :         return GKM_MODULE_GET_CLASS (self)->logout_so (self, slot_id);
     842              : }
     843              : 
     844              : CK_ULONG
     845          215 : gkm_module_next_handle (GkmModule *self)
     846              : {
     847          215 :         g_return_val_if_fail (GKM_IS_MODULE (self), 0);
     848          215 :         if (self->pv->handle_counter == CK_GNOME_MAX_HANDLE) {
     849            0 :                 g_warning ("handle counter wrapped");
     850            0 :                 self->pv->handle_counter = 0;
     851              :         }
     852          215 :         return (self->pv->handle_counter)++;
     853              : }
     854              : 
     855              : CK_RV
     856          244 : gkm_module_refresh_token (GkmModule *self)
     857              : {
     858          244 :         g_return_val_if_fail (GKM_IS_MODULE (self), CKR_GENERAL_ERROR);
     859          244 :         g_assert (GKM_MODULE_GET_CLASS (self)->refresh_token);
     860          244 :         return GKM_MODULE_GET_CLASS (self)->refresh_token (self);
     861              : }
     862              : 
     863              : void
     864          153 : gkm_module_add_token_object (GkmModule *self, GkmTransaction *transaction, GkmObject *object)
     865              : {
     866          153 :         g_return_if_fail (GKM_IS_MODULE (self));
     867          153 :         g_return_if_fail (GKM_IS_OBJECT (object));
     868          153 :         g_assert (GKM_MODULE_GET_CLASS (self)->add_token_object);
     869              : 
     870          153 :         if (gkm_object_is_transient (object)) {
     871          132 :                 if (g_hash_table_lookup (self->pv->transient_objects, object) == NULL)
     872          132 :                         add_transient_object (self, transaction, object);
     873              :         } else {
     874           21 :                 GKM_MODULE_GET_CLASS (self)->add_token_object (self, transaction, object);
     875              :         }
     876              : }
     877              : 
     878              : void
     879           58 : gkm_module_store_token_object (GkmModule *self, GkmTransaction *transaction, GkmObject *object)
     880              : {
     881           58 :         g_return_if_fail (GKM_IS_MODULE (self));
     882           58 :         g_return_if_fail (GKM_IS_OBJECT (object));
     883           58 :         g_assert (GKM_MODULE_GET_CLASS (self)->store_token_object);
     884              : 
     885           58 :         if (!gkm_object_is_transient (object))
     886           36 :                 GKM_MODULE_GET_CLASS (self)->store_token_object (self, transaction, object);
     887              : }
     888              : 
     889              : void
     890           28 : gkm_module_remove_token_object (GkmModule *self, GkmTransaction *transaction, GkmObject *object)
     891              : {
     892           28 :         g_return_if_fail (GKM_IS_MODULE (self));
     893           28 :         g_return_if_fail (GKM_IS_OBJECT (object));
     894           28 :         g_assert (GKM_MODULE_GET_CLASS (self)->remove_token_object);
     895              : 
     896           28 :         if (gkm_object_is_transient (object))
     897           22 :                 remove_transient_object (self, transaction, object);
     898              :         else
     899            6 :                 GKM_MODULE_GET_CLASS (self)->remove_token_object (self, transaction, object);
     900              : }
     901              : 
     902              : void
     903         3096 : gkm_module_register_factory (GkmModule *self, GkmFactory *factory)
     904              : {
     905         3096 :         g_return_if_fail (GKM_IS_MODULE (self));
     906         3096 :         g_return_if_fail (factory);
     907         3096 :         g_return_if_fail (factory->attrs || !factory->n_attrs);
     908         3096 :         g_return_if_fail (factory->func);
     909              : 
     910         3096 :         g_array_append_val (self->pv->factories, *factory);
     911         3096 :         self->pv->factories_sorted = FALSE;
     912              : }
     913              : 
     914              : GkmFactory*
     915          115 : gkm_module_find_factory (GkmModule *self, CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
     916              : {
     917              :         GkmFactory *factory;
     918              :         gboolean matched;
     919              :         gulong j;
     920              :         gsize i;
     921              : 
     922          115 :         g_return_val_if_fail (GKM_IS_MODULE (self), NULL);
     923          115 :         g_return_val_if_fail (attrs || !n_attrs, NULL);
     924              : 
     925          115 :         if (!self->pv->factories_sorted) {
     926           53 :                 g_array_sort (self->pv->factories, sort_factory_by_n_attrs);
     927           53 :                 self->pv->factories_sorted = TRUE;
     928              :         }
     929              : 
     930          936 :         for (i = 0; i < self->pv->factories->len; ++i) {
     931          936 :                 factory = &(g_array_index (self->pv->factories, GkmFactory, i));
     932              : 
     933          936 :                 matched = TRUE;
     934         1138 :                 for (j = 0; j < factory->n_attrs; ++j) {
     935         1023 :                         if (!gkm_attributes_contains (attrs, n_attrs, &factory->attrs[j])) {
     936          821 :                                 matched = FALSE;
     937          821 :                                 break;
     938              :                         }
     939              :                 }
     940              : 
     941          936 :                 if (matched)
     942          115 :                         return factory;
     943              :         }
     944              : 
     945            0 :         return NULL;
     946              : }
     947              : 
     948              : /*
     949              :  * Hidden method to get the mutex for a module. This is for timers to be
     950              :  * able to reenter the module. Don't use this method.
     951              :  */
     952              : 
     953              : GMutex*
     954          136 : _gkm_module_get_scary_mutex_that_you_should_not_touch (GkmModule *self)
     955              : {
     956          136 :         g_return_val_if_fail (GKM_IS_MODULE (self), NULL);
     957          136 :         return self->pv->mutex;
     958              : }
     959              : 
     960              : /* -----------------------------------------------------------------------------
     961              :  * PKCS#11
     962              :  */
     963              : 
     964              : CK_RV
     965            2 : gkm_module_C_GetInfo (GkmModule *self, CK_INFO_PTR info)
     966              : {
     967              :         GkmModuleClass *klass;
     968              : 
     969            2 :         g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
     970              : 
     971            2 :         if (!info)
     972            0 :                 return CKR_ARGUMENTS_BAD;
     973              : 
     974            2 :         klass = GKM_MODULE_GET_CLASS (self);
     975            2 :         g_return_val_if_fail (klass, CKR_GENERAL_ERROR);
     976              : 
     977            2 :         memcpy (info, &default_module_info, sizeof (CK_INFO));
     978              : 
     979              :         /* Extend all the strings appropriately */
     980            2 :         extend_space_string (info->libraryDescription, sizeof (info->libraryDescription));
     981            2 :         extend_space_string (info->manufacturerID, sizeof (info->manufacturerID));
     982              : 
     983            2 :         return CKR_OK;
     984              : }
     985              : 
     986              : CK_RV
     987          218 : gkm_module_C_GetSlotList (GkmModule *self, CK_BBOOL token_present, CK_SLOT_ID_PTR slot_list, CK_ULONG_PTR count)
     988              : {
     989          218 :         g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
     990              : 
     991          218 :         if (!count)
     992            0 :                 return CKR_ARGUMENTS_BAD;
     993              : 
     994              :         /* Just want to get the count */
     995          218 :         if (slot_list == NULL) {
     996          109 :                 *count = 1;
     997          109 :                 return CKR_OK;
     998              :         }
     999              : 
    1000              :         /* Buffer too small? */
    1001          109 :         if (*count == 0) {
    1002            0 :                 *count = 1;
    1003            0 :                 return CKR_BUFFER_TOO_SMALL;
    1004              :         }
    1005              : 
    1006          109 :         g_return_val_if_fail (slot_list, CKR_ARGUMENTS_BAD);
    1007              : 
    1008              :         /* Answer C_GetSlotList with 0 for app */
    1009          109 :         slot_list[0] = GKM_SLOT_ID;
    1010          109 :         *count = 1;
    1011          109 :         return CKR_OK;
    1012              : }
    1013              : 
    1014              : CK_RV
    1015          265 : gkm_module_C_GetSlotInfo (GkmModule *self, CK_SLOT_ID id, CK_SLOT_INFO_PTR info)
    1016              : {
    1017              :         const CK_SLOT_INFO *original;
    1018              :         GkmModuleClass *klass;
    1019              : 
    1020          265 :         g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
    1021              : 
    1022          265 :         if (id != GKM_SLOT_ID)
    1023            0 :                 return CKR_SLOT_ID_INVALID;
    1024          265 :         if (info == NULL)
    1025            0 :                 return CKR_ARGUMENTS_BAD;
    1026              : 
    1027              :         /* Any slot ID is valid for partitioned module */
    1028              : 
    1029          265 :         klass = GKM_MODULE_GET_CLASS (self);
    1030          265 :         g_return_val_if_fail (klass, CKR_GENERAL_ERROR);
    1031          265 :         g_return_val_if_fail (klass->get_slot_info, CKR_GENERAL_ERROR);
    1032              : 
    1033          265 :         original = (klass->get_slot_info) (self);
    1034          265 :         g_return_val_if_fail (original, CKR_GENERAL_ERROR);
    1035              : 
    1036          265 :         memcpy (info, original, sizeof (CK_SLOT_INFO));
    1037              : 
    1038              :         /* Extend all the strings appropriately */
    1039          265 :         extend_space_string (info->manufacturerID, sizeof (info->manufacturerID));
    1040          265 :         extend_space_string (info->slotDescription, sizeof (info->slotDescription));
    1041              : 
    1042          265 :         return CKR_OK;
    1043              : }
    1044              : 
    1045              : CK_RV
    1046          108 : gkm_module_C_GetTokenInfo (GkmModule *self, CK_SLOT_ID id, CK_TOKEN_INFO_PTR info)
    1047              : {
    1048              :         const CK_TOKEN_INFO *original;
    1049              :         GkmModuleClass *klass;
    1050              : 
    1051          108 :         g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
    1052              : 
    1053          108 :         if (id != GKM_SLOT_ID)
    1054            0 :                 return CKR_SLOT_ID_INVALID;
    1055          108 :         if (info == NULL)
    1056            0 :                 return CKR_ARGUMENTS_BAD;
    1057              : 
    1058              :         /* Any slot ID is valid for partitioned module */
    1059              : 
    1060          108 :         klass = GKM_MODULE_GET_CLASS (self);
    1061          108 :         g_return_val_if_fail (klass, CKR_GENERAL_ERROR);
    1062          108 :         g_return_val_if_fail (klass->get_token_info, CKR_GENERAL_ERROR);
    1063              : 
    1064          108 :         original = (klass->get_token_info) (self);
    1065          108 :         g_return_val_if_fail (original, CKR_GENERAL_ERROR);
    1066              : 
    1067          108 :         memcpy (info, original, sizeof (CK_TOKEN_INFO));
    1068              : 
    1069              :         /* Extend all the strings appropriately */
    1070          108 :         extend_space_string (info->label, sizeof (info->label));
    1071          108 :         extend_space_string (info->manufacturerID, sizeof (info->manufacturerID));
    1072          108 :         extend_space_string (info->model, sizeof (info->model));
    1073          108 :         extend_space_string (info->serialNumber, sizeof (info->serialNumber));
    1074              : 
    1075          108 :         return CKR_OK;
    1076              : }
    1077              : 
    1078              : CK_RV
    1079            0 : gkm_module_C_GetMechanismList (GkmModule *self, CK_SLOT_ID id,
    1080              :                                CK_MECHANISM_TYPE_PTR mech_list, CK_ULONG_PTR count)
    1081              : {
    1082            0 :         const guint n_mechanisms = G_N_ELEMENTS (mechanism_list);
    1083              :         guint i;
    1084              : 
    1085            0 :         g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
    1086              : 
    1087            0 :         if (id != GKM_SLOT_ID)
    1088            0 :                 return CKR_SLOT_ID_INVALID;
    1089            0 :         if (count == NULL)
    1090            0 :                 return CKR_ARGUMENTS_BAD;
    1091              : 
    1092              :         /* Just want to get the count */
    1093            0 :         if (mech_list == NULL) {
    1094            0 :                 *count = n_mechanisms;
    1095            0 :                 return CKR_OK;
    1096              :         }
    1097              : 
    1098              :         /* Buffer too small? */
    1099            0 :         if (*count < n_mechanisms) {
    1100            0 :                 *count = n_mechanisms;
    1101            0 :                 return CKR_BUFFER_TOO_SMALL;
    1102              :         }
    1103              : 
    1104            0 :         *count = n_mechanisms;
    1105            0 :         for (i = 0; i < n_mechanisms; ++i)
    1106            0 :                 mech_list[i] = mechanism_list[i].mechanism;
    1107              : 
    1108            0 :         return CKR_OK;
    1109              : }
    1110              : 
    1111              : CK_RV
    1112            0 : gkm_module_C_GetMechanismInfo (GkmModule *self, CK_SLOT_ID id,
    1113              :                                CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR info)
    1114              : {
    1115            0 :         const guint n_mechanisms = G_N_ELEMENTS (mechanism_list);
    1116              :         guint index;
    1117              : 
    1118            0 :         g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
    1119              : 
    1120            0 :         if (id != GKM_SLOT_ID)
    1121            0 :                 return CKR_SLOT_ID_INVALID;
    1122            0 :         if (info == NULL)
    1123            0 :                 return CKR_ARGUMENTS_BAD;
    1124              : 
    1125            0 :         for (index = 0; index < n_mechanisms; ++index) {
    1126            0 :                 if (mechanism_list[index].mechanism == type)
    1127            0 :                         break;
    1128              :         }
    1129              : 
    1130            0 :         if (index == n_mechanisms)
    1131            0 :                 return CKR_MECHANISM_INVALID;
    1132              : 
    1133            0 :         memcpy (info, &mechanism_list[index].info, sizeof (CK_MECHANISM_INFO));
    1134            0 :         return CKR_OK;
    1135              : }
    1136              : 
    1137              : CK_RV
    1138            0 : gkm_module_C_InitToken (GkmModule *self, CK_SLOT_ID id, CK_UTF8CHAR_PTR pin,
    1139              :                         CK_ULONG pin_len, CK_UTF8CHAR_PTR label)
    1140              : {
    1141            0 :         return CKR_FUNCTION_NOT_SUPPORTED;
    1142              : }
    1143              : 
    1144              : CK_RV
    1145          215 : gkm_module_C_OpenSession (GkmModule *self, CK_SLOT_ID id, CK_FLAGS flags, CK_VOID_PTR user_data,
    1146              :                           CK_NOTIFY callback, CK_SESSION_HANDLE_PTR result)
    1147              : {
    1148              :         CK_G_APPLICATION_PTR app;
    1149              :         CK_SESSION_HANDLE handle;
    1150              :         GkmSession *session;
    1151          215 :         Apartment *apt = NULL;
    1152              : 
    1153          215 :         g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
    1154              : 
    1155          215 :         if (APARTMENT_SLOT (id) != GKM_SLOT_ID)
    1156            0 :                 return CKR_SLOT_ID_INVALID;
    1157          215 :         if (!result)
    1158            0 :                 return CKR_ARGUMENTS_BAD;
    1159              : 
    1160          215 :         if (!(flags & CKF_SERIAL_SESSION))
    1161            0 :                 return CKR_SESSION_PARALLEL_NOT_SUPPORTED;
    1162              : 
    1163              :         /*
    1164              :          * If they're calling us with the 'application' extension, then
    1165              :          * allocate or use our application identifier.
    1166              :          */
    1167          215 :         if (flags & CKF_G_APPLICATION_SESSION) {
    1168           17 :                 app = user_data;
    1169           17 :                 if (app == NULL)
    1170            0 :                         return CKR_ARGUMENTS_BAD;
    1171           17 :                 if (app->applicationId)
    1172            0 :                         apt = lookup_apartment (self, APARTMENT_ID (id, app->applicationId));
    1173              :         } else {
    1174          198 :                 app = NULL;
    1175          198 :                 apt = lookup_apartment (self, APARTMENT_ID (id, 0));
    1176              :         }
    1177              : 
    1178              :         /* The first time this application is accessing, or closed all sessions, allocate new */
    1179          215 :         if (apt == NULL) {
    1180          208 :                 apt = apartment_new (GKM_MODULE_GET_CLASS (self), id, app);
    1181          208 :                 register_apartment (self, apt);
    1182              :         }
    1183              : 
    1184              :         /* Can't open read only session if SO login */
    1185          215 :         if (apt->logged_in == CKU_SO && !(flags & CKF_RW_SESSION))
    1186            0 :                 return CKR_SESSION_READ_WRITE_SO_EXISTS;
    1187              : 
    1188              :         /* Make and register a new session */
    1189          215 :         handle = gkm_module_next_handle (self);
    1190          215 :         session = g_object_new (GKM_TYPE_SESSION, "slot-id", apt->slot_id, "apartment", apt->apt_id,
    1191              :                                 "flags", flags, "handle", handle, "module", self,
    1192              :                                 "manager", apt->session_manager, "logged-in", apt->logged_in, NULL);
    1193          215 :         apt->sessions = g_list_prepend (apt->sessions, session);
    1194              : 
    1195              :         /* Track the session by handle */
    1196          430 :         g_hash_table_insert (self->pv->sessions_by_handle,
    1197          215 :                              gkm_util_ulong_alloc (handle),
    1198              :                              g_object_ref (session));
    1199              : 
    1200          215 :         *result = handle;
    1201          215 :         return CKR_OK;
    1202              : }
    1203              : 
    1204              : CK_RV
    1205           61 : gkm_module_C_CloseSession (GkmModule *self, CK_SESSION_HANDLE handle)
    1206              : {
    1207              :         GkmSession *session;
    1208              :         CK_ULONG apt_id;
    1209              :         Apartment *apt;
    1210              :         GList *link;
    1211              : 
    1212           61 :         g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
    1213              : 
    1214           61 :         session = gkm_module_lookup_session (self, handle);
    1215           61 :         if (session == NULL)
    1216            0 :                 return CKR_SESSION_HANDLE_INVALID;
    1217              : 
    1218              :         /* Calculate the virtual slot */
    1219           61 :         apt_id = gkm_session_get_apartment (session);
    1220           61 :         apt = lookup_apartment (self, apt_id);
    1221           61 :         g_return_val_if_fail (apt, CKR_GENERAL_ERROR);
    1222              : 
    1223           61 :         link = g_list_find (apt->sessions, session);
    1224           61 :         g_return_val_if_fail (link, CKR_GENERAL_ERROR);
    1225           61 :         apt->sessions = g_list_delete_link (apt->sessions, link);
    1226           61 :         g_object_unref (session);
    1227           61 :         if (!apt->sessions)
    1228           54 :                 unregister_apartment (self, apt);
    1229              : 
    1230           61 :         if (!g_hash_table_remove (self->pv->sessions_by_handle, &handle))
    1231            0 :                 g_assert_not_reached ();
    1232              : 
    1233           61 :         return CKR_OK;
    1234              : }
    1235              : 
    1236              : CK_RV
    1237            0 : gkm_module_C_CloseAllSessions (GkmModule *self, CK_SLOT_ID id)
    1238              : {
    1239              :         Apartment *apt;
    1240              :         CK_SESSION_HANDLE handle;
    1241              :         GList *l;
    1242              : 
    1243            0 :         g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
    1244              : 
    1245            0 :         if (APARTMENT_SLOT (id) != GKM_SLOT_ID)
    1246            0 :                 return CKR_SLOT_ID_INVALID;
    1247              : 
    1248            0 :         apt = lookup_apartment (self, id);
    1249            0 :         if (apt == NULL)
    1250            0 :                 return CKR_OK;
    1251              : 
    1252              :         /* Unregister all its sessions */
    1253            0 :         for (l = apt->sessions; l; l = g_list_next (l)) {
    1254            0 :                 handle = gkm_session_get_handle (l->data);
    1255            0 :                 if (!g_hash_table_remove (self->pv->sessions_by_handle, &handle))
    1256            0 :                         g_assert_not_reached ();
    1257              :         }
    1258              : 
    1259            0 :         unregister_apartment (self, apt);
    1260            0 :         return CKR_OK;
    1261              : }
    1262              : 
    1263              : CK_RV
    1264            4 : gkm_module_C_InitPIN (GkmModule* self, CK_SESSION_HANDLE handle,
    1265              :                       CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
    1266              : {
    1267              :         GkmSession *session;
    1268              :         Apartment *apt;
    1269              :         CK_ULONG apt_id;
    1270              : 
    1271            4 :         g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
    1272              : 
    1273            4 :         session = gkm_module_lookup_session (self, handle);
    1274            4 :         if (session == NULL)
    1275            0 :                 return CKR_SESSION_HANDLE_INVALID;
    1276              : 
    1277              :         /* Calculate the virtual slot */
    1278            4 :         apt_id = gkm_session_get_apartment (session);
    1279            4 :         apt = lookup_apartment (self, apt_id);
    1280            4 :         g_return_val_if_fail (apt, CKR_GENERAL_ERROR);
    1281              : 
    1282            4 :         if (apt->logged_in != CKU_SO)
    1283            0 :                 return CKR_USER_NOT_LOGGED_IN;
    1284              : 
    1285              :         /* Our InitPIN assumes an uninitialized PIN */
    1286            4 :         return gkm_module_login_change (self, apt_id, NULL, 0, pin, n_pin);
    1287              : }
    1288              : 
    1289              : CK_RV
    1290            1 : gkm_module_C_SetPIN (GkmModule* self, CK_SESSION_HANDLE handle, CK_UTF8CHAR_PTR old_pin,
    1291              :                      CK_ULONG old_pin_len, CK_UTF8CHAR_PTR new_pin, CK_ULONG new_pin_len)
    1292              : {
    1293              :         GkmSession *session;
    1294              :         Apartment *apt;
    1295              :         CK_ULONG apt_id;
    1296              : 
    1297            1 :         g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
    1298              : 
    1299            1 :         session = gkm_module_lookup_session (self, handle);
    1300            1 :         if (session == NULL)
    1301            0 :                 return CKR_SESSION_HANDLE_INVALID;
    1302              : 
    1303              :         /* Calculate the virtual slot */
    1304            1 :         apt_id = gkm_session_get_apartment (session);
    1305            1 :         apt = lookup_apartment (self, apt_id);
    1306            1 :         g_return_val_if_fail (apt, CKR_GENERAL_ERROR);
    1307              : 
    1308            1 :         return gkm_module_login_change (self, apt_id, old_pin, old_pin_len, new_pin, new_pin_len);
    1309              : }
    1310              : 
    1311              : CK_RV
    1312          185 : gkm_module_C_Login (GkmModule *self, CK_SESSION_HANDLE handle, CK_USER_TYPE user_type,
    1313              :                     CK_UTF8CHAR_PTR pin, CK_ULONG pin_len)
    1314              : {
    1315              :         CK_ULONG apt_id;
    1316              :         GkmSession *session;
    1317              :         Apartment *apt;
    1318              :         GList *l;
    1319              : 
    1320          185 :         g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
    1321              : 
    1322          185 :         session = gkm_module_lookup_session (self, handle);
    1323          185 :         if (session == NULL)
    1324            0 :                 return CKR_SESSION_HANDLE_INVALID;
    1325              : 
    1326              :         /* Pass off context specifc logins to appropriate place */
    1327          185 :         if (user_type == CKU_CONTEXT_SPECIFIC)
    1328            0 :                 return gkm_session_login_context_specific (session, pin, pin_len);
    1329              : 
    1330              :         /* Some random crap... */
    1331          185 :         if (user_type != CKU_USER && user_type != CKU_SO)
    1332            0 :                 return CKR_USER_TYPE_INVALID;
    1333              : 
    1334              :         /* Calculate the virtual slot */
    1335          185 :         apt_id = gkm_session_get_apartment (session);
    1336          185 :         apt = lookup_apartment (self, apt_id);
    1337          185 :         g_return_val_if_fail (apt, CKR_GENERAL_ERROR);
    1338              : 
    1339          185 :         if (apt->logged_in == user_type)
    1340            2 :                 return CKR_USER_ALREADY_LOGGED_IN;
    1341          183 :         if (apt->logged_in != CKU_NONE)
    1342            0 :                 return CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
    1343              : 
    1344          183 :         if (user_type == CKU_SO) {
    1345              : 
    1346              :                 /* Can't login as SO if read-only sessions exist */
    1347            8 :                 for (l = apt->sessions; l; l = g_list_next (l)) {
    1348            4 :                         if (gkm_session_is_read_only (l->data))
    1349            0 :                                 return CKR_SESSION_READ_ONLY_EXISTS;
    1350              :                 }
    1351              : 
    1352            4 :                 return gkm_module_login_so (self, apt_id, pin, pin_len);
    1353              : 
    1354          179 :         } else if (user_type == CKU_USER) {
    1355          179 :                 return gkm_module_login_user (self, apt_id, pin, pin_len);
    1356              : 
    1357              :         } else {
    1358            0 :                 return CKR_USER_TYPE_INVALID;
    1359              :         }
    1360              : }
    1361              : 
    1362              : CK_RV
    1363            0 : gkm_module_C_Logout (GkmModule *self, CK_SESSION_HANDLE handle)
    1364              : {
    1365              :         CK_ULONG apt_id;
    1366              :         Apartment *apt;
    1367              :         GkmSession *session;
    1368              : 
    1369            0 :         g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
    1370              : 
    1371            0 :         session = gkm_module_lookup_session (self, handle);
    1372            0 :         if (session == NULL)
    1373            0 :                 return CKR_SESSION_HANDLE_INVALID;
    1374              : 
    1375            0 :         apt_id = gkm_session_get_apartment (session);
    1376            0 :         apt = lookup_apartment (self, apt_id);
    1377            0 :         g_return_val_if_fail (apt, CKR_GENERAL_ERROR);
    1378              : 
    1379            0 :         if (apt->logged_in == CKU_NONE)
    1380            0 :                 return CKR_USER_NOT_LOGGED_IN;
    1381              : 
    1382            0 :         else if (apt->logged_in == CKU_USER)
    1383            0 :                 return gkm_module_logout_user (self, apt_id);
    1384              : 
    1385            0 :         else if (apt->logged_in == CKU_SO)
    1386            0 :                 return gkm_module_logout_so (self, apt_id);
    1387              : 
    1388              :         else
    1389            0 :                 g_return_val_if_reached (CKR_GENERAL_ERROR);
    1390              : }
        

Generated by: LCOV version 2.0-1