Differences From
Artifact [5d076538a2]:
883 883 #define CACKEY_PIN_COMMAND_DEFAULT_XSTR(str) CACKEY_PIN_COMMAND_DEFAULT_STR(str)
884 884 #define CACKEY_PIN_COMMAND_DEFAULT_STR(str) #str
885 885 static char *cackey_pin_command = NULL;
886 886 static char *cackey_pin_command_xonly = NULL;
887 887
888 888 /* PCSC Global Handles */
889 889 static LPSCARDCONTEXT cackey_pcsc_handle = NULL;
890 +static LPSCARDCONTEXT cackey_waiting_pcsc_handle = NULL;
890 891
891 892 static unsigned long cackey_getversion(void) {
892 893 static unsigned long retval = 255;
893 894 unsigned long major = 0;
894 895 unsigned long minor = 0;
895 896 char *major_str = NULL;
896 897 char *minor_str = NULL;
................................................................................
1020 1021 cackey_pcsc_handle = NULL;
1021 1022
1022 1023 cackey_slots_disconnect_all();
1023 1024
1024 1025 return(CACKEY_PCSC_E_GENERIC);
1025 1026 }
1026 1027 }
1028 +
1029 + if (cackey_waiting_pcsc_handle == NULL) {
1030 + cackey_waiting_pcsc_handle = malloc(sizeof(*cackey_waiting_pcsc_handle));
1031 + if (cackey_waiting_pcsc_handle == NULL) {
1032 + CACKEY_DEBUG_PRINTF("Call to malloc() failed, returning in failure");
1033 +
1034 + cackey_slots_disconnect_all();
1035 +
1036 + free(cackey_pcsc_handle);
1037 + cackey_pcsc_handle = NULL;
1038 +
1039 + return(CACKEY_PCSC_E_GENERIC);
1040 + }
1041 +
1042 + CACKEY_DEBUG_PRINTF("SCardEstablishContext() called");
1043 + scard_est_context_ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, cackey_waiting_pcsc_handle);
1044 + if (scard_est_context_ret != SCARD_S_SUCCESS) {
1045 + CACKEY_DEBUG_PRINTF("Call to SCardEstablishContext failed (returned %s/%li), returning in failure", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_est_context_ret), (long) scard_est_context_ret);
1046 +
1047 + free(cackey_pcsc_handle);
1048 + cackey_pcsc_handle = NULL;
1049 + free(cackey_waiting_pcsc_handle);
1050 + cackey_waiting_pcsc_handle = NULL;
1051 +
1052 + cackey_slots_disconnect_all();
1053 +
1054 + return(CACKEY_PCSC_E_GENERIC);
1055 + }
1056 + }
1027 1057
1028 1058 #ifdef HAVE_SCARDISVALIDCONTEXT
1029 1059 CACKEY_DEBUG_PRINTF("SCardIsValidContext() called");
1030 1060 scard_isvalid_ret = SCardIsValidContext(*cackey_pcsc_handle);
1031 1061 if (scard_isvalid_ret != SCARD_S_SUCCESS) {
1032 1062 CACKEY_DEBUG_PRINTF("Handle has become invalid (SCardIsValidContext = %s/%li), trying to re-establish...", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_isvalid_ret), (long) scard_isvalid_ret);
1033 1063
................................................................................
1042 1072 cackey_slots_disconnect_all();
1043 1073
1044 1074 return(CACKEY_PCSC_E_GENERIC);
1045 1075 }
1046 1076
1047 1077 CACKEY_DEBUG_PRINTF("Handle has been re-established");
1048 1078 }
1079 +
1080 + CACKEY_DEBUG_PRINTF("SCardIsValidContext() called");
1081 + scard_isvalid_ret = SCardIsValidContext(*cackey_waiting_pcsc_handle);
1082 + if (scard_isvalid_ret != SCARD_S_SUCCESS) {
1083 + CACKEY_DEBUG_PRINTF("Handle has become invalid (SCardIsValidContext = %s/%li), trying to re-establish...", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_isvalid_ret), (long) scard_isvalid_ret);
1084 +
1085 + CACKEY_DEBUG_PRINTF("SCardEstablishContext() called");
1086 + scard_est_context_ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, cackey_waiting_pcsc_handle);
1087 + if (scard_est_context_ret != SCARD_S_SUCCESS) {
1088 + CACKEY_DEBUG_PRINTF("Call to SCardEstablishContext failed (returned %s/%li), returning in failure", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_est_context_ret), (long) scard_est_context_ret);
1089 +
1090 + free(cackey_waiting_pcsc_handle);
1091 + cackey_waiting_pcsc_handle = NULL;
1092 +
1093 + cackey_slots_disconnect_all();
1094 +
1095 + return(CACKEY_PCSC_E_GENERIC);
1096 + }
1097 +
1098 + CACKEY_DEBUG_PRINTF("Waiting handle has been re-established");
1099 + }
1049 1100 #endif
1050 1101
1051 1102 CACKEY_DEBUG_PRINTF("Sucessfully connected to PC/SC, returning in success");
1052 1103
1053 1104 return(CACKEY_PCSC_S_OK);
1054 1105 }
1055 1106
................................................................................
1067 1118 * NOTES
1068 1119 * This function disconnects from the PC/SC Connection manager and updates
1069 1120 * the global handle.
1070 1121 *
1071 1122 */
1072 1123 static cackey_ret cackey_pcsc_disconnect(void) {
1073 1124 LONG scard_rel_context_ret;
1125 + cackey_ret retval = CACKEY_PCSC_S_OK;
1074 1126
1075 1127 CACKEY_DEBUG_PRINTF("Called.");
1076 1128
1077 - if (cackey_pcsc_handle == NULL) {
1078 - return(CACKEY_PCSC_S_OK);
1079 - }
1129 + if (cackey_pcsc_handle != NULL) {
1130 + scard_rel_context_ret = SCardReleaseContext(*cackey_pcsc_handle);
1131 + if (scard_rel_context_ret != SCARD_S_SUCCESS) {
1132 + retval = CACKEY_PCSC_E_GENERIC;
1133 + }
1080 1134
1081 - scard_rel_context_ret = SCardReleaseContext(*cackey_pcsc_handle);
1082 -
1083 - if (cackey_pcsc_handle) {
1084 1135 free(cackey_pcsc_handle);
1085 1136
1086 1137 cackey_pcsc_handle = NULL;
1087 1138 }
1088 1139
1089 - if (scard_rel_context_ret != SCARD_S_SUCCESS) {
1090 - return(CACKEY_PCSC_E_GENERIC);
1140 + if (cackey_waiting_pcsc_handle != NULL) {
1141 + scard_rel_context_ret = SCardReleaseContext(*cackey_waiting_pcsc_handle);
1142 + if (scard_rel_context_ret != SCARD_S_SUCCESS) {
1143 + retval = CACKEY_PCSC_E_GENERIC;
1144 + }
1145 +
1146 + free(cackey_waiting_pcsc_handle);
1147 +
1148 + cackey_waiting_pcsc_handle = NULL;
1091 1149 }
1092 1150
1093 - return(CACKEY_PCSC_S_OK);
1151 + return(retval);
1094 1152 }
1095 1153
1096 1154 /*
1097 1155 * SYNPOSIS
1098 1156 * void cackey_mark_slot_reset(struct cackey_slot *slot);
1099 1157 *
1100 1158 * ARGUMENTS
................................................................................
4201 4259
4202 4260 for (idx = 0; idx < (sizeof(cackey_sessions) / sizeof(cackey_sessions[0])); idx++) {
4203 4261 if (cackey_sessions[idx].active) {
4204 4262 C_CloseSession(idx);
4205 4263 }
4206 4264 }
4207 4265
4266 + cackey_mutex_lock(cackey_biglock);
4267 +
4208 4268 cackey_slots_disconnect_all();
4209 4269
4210 4270 for (idx = 0; idx < (sizeof(cackey_slots) / sizeof(cackey_slots[0])); idx++) {
4211 4271 if (cackey_slots[idx].internal) {
4212 4272 continue;
4213 4273 }
4214 4274
................................................................................
4222 4282 cackey_slots[idx].cached_certs = NULL;
4223 4283 }
4224 4284 }
4225 4285
4226 4286 cackey_pcsc_disconnect();
4227 4287
4228 4288 cackey_initialized = 0;
4289 +
4290 + cackey_mutex_unlock(cackey_biglock);
4229 4291
4230 4292 CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK);
4231 4293
4232 4294 return(CKR_OK);
4233 4295 }
4234 4296
4235 4297 CK_DEFINE_FUNCTION(CK_RV, C_GetInfo)(CK_INFO_PTR pInfo) {
................................................................................
4727 4789 CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK);
4728 4790
4729 4791 return(CKR_OK);
4730 4792 }
4731 4793
4732 4794 CK_DEFINE_FUNCTION(CK_RV, C_WaitForSlotEvent)(CK_FLAGS flags, CK_SLOT_ID_PTR pSlotID, CK_VOID_PTR pReserved) {
4733 4795 SCARD_READERSTATE reader_states[(sizeof(cackey_slots) / sizeof(cackey_slots[0])) + 1];
4734 - SCARDCONTEXT pcsc_handle;
4796 + LPSCARDCONTEXT handle;
4735 4797 LONG scard_getstatchng_ret;
4736 - LONG scard_est_context_ret;
4798 + cackey_ret pcsc_connect_ret;
4737 4799 struct cackey_slot *cackey_slot;
4738 - unsigned int currslot, reader_state_slot;
4739 - int pcsc_connect_ret;
4800 + unsigned int currslot, reader_state_slot, reader_state_slot_cnt;
4801 + int mutex_retval;
4740 4802 int slot_changed;
4741 4803
4742 4804 CACKEY_DEBUG_PRINTF("Called.");
4743 4805
4744 4806 if (pReserved != NULL) {
4745 4807 CACKEY_DEBUG_PRINTF("Error. pReserved is not NULL.");
4746 4808
................................................................................
4754 4816 }
4755 4817
4756 4818 if (!cackey_initialized) {
4757 4819 CACKEY_DEBUG_PRINTF("Error. Not initialized.");
4758 4820
4759 4821 return(CKR_CRYPTOKI_NOT_INITIALIZED);
4760 4822 }
4823 +
4824 + mutex_retval = cackey_mutex_lock(cackey_biglock);
4825 + if (mutex_retval != 0) {
4826 + CACKEY_DEBUG_PRINTF("Error. Locking failed.");
4827 +
4828 + return(CKR_GENERAL_ERROR);
4829 + }
4761 4830
4762 4831 pcsc_connect_ret = cackey_pcsc_connect();
4763 4832 if (pcsc_connect_ret != CACKEY_PCSC_S_OK) {
4833 + cackey_mutex_unlock(cackey_biglock);
4834 +
4764 4835 CACKEY_DEBUG_PRINTF("Connection to PC/SC failed, returning in failure");
4765 4836
4766 4837 return(CKR_GENERAL_ERROR);
4767 4838 }
4768 4839
4769 4840 for (reader_state_slot = currslot = 0; currslot < (sizeof(cackey_slots) / sizeof(cackey_slots[0])); currslot++) {
4770 4841 if (cackey_slots[currslot].internal) {
................................................................................
4782 4853 reader_states[reader_state_slot].dwCurrentState = SCARD_STATE_UNAWARE;
4783 4854 } else {
4784 4855 reader_states[reader_state_slot].dwCurrentState = cackey_slots[currslot].pcsc_state;
4785 4856 }
4786 4857
4787 4858 reader_state_slot++;
4788 4859 }
4860 +
4861 + mutex_retval = cackey_mutex_unlock(cackey_biglock);
4862 + if (mutex_retval != 0) {
4863 + CACKEY_DEBUG_PRINTF("Error. Unlocking failed.");
4864 +
4865 + return(CKR_GENERAL_ERROR);
4866 + }
4789 4867
4790 4868 reader_states[reader_state_slot].szReader = "\\\\?PnP?\\Notification";
4791 4869 reader_states[reader_state_slot].pvUserData = NULL;
4792 4870 reader_states[reader_state_slot].dwCurrentState = SCARD_STATE_UNAWARE;
4793 4871 reader_state_slot++;
4794 4872
4795 - scard_est_context_ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &pcsc_handle);
4796 - if (scard_est_context_ret != SCARD_S_SUCCESS) {
4797 - CACKEY_DEBUG_PRINTF("Returning CKR_GENERAL_ERROR (%i) because SCardEstablishContext failed: %lx", CKR_GENERAL_ERROR, scard_est_context_ret);
4873 + reader_state_slot_cnt = reader_state_slot;
4798 4874
4799 - return(CKR_GENERAL_ERROR);
4875 + while (1) {
4876 + cackey_mutex_lock(cackey_biglock);
4877 +
4878 + handle = cackey_waiting_pcsc_handle;
4879 +
4880 + cackey_mutex_unlock(cackey_biglock);
4881 +
4882 + if (handle == NULL) {
4883 + CACKEY_DEBUG_PRINTF("Waiting handle disappeared, not attempting to wait.");
4884 +
4885 + break;
4886 + }
4887 +
4888 + CACKEY_DEBUG_PRINTF("Calling SCardGetStatusChange(), which will block for 1 second");
4889 + scard_getstatchng_ret = SCardGetStatusChange(*handle, 1000, reader_states, reader_state_slot_cnt);
4890 +
4891 + if (scard_getstatchng_ret == SCARD_E_TIMEOUT) {
4892 + continue;
4893 + }
4894 +
4895 + break;
4800 4896 }
4801 4897
4802 - scard_getstatchng_ret = SCardGetStatusChange(pcsc_handle, INFINITE, reader_states, reader_state_slot);
4803 -
4804 - SCardReleaseContext(pcsc_handle);
4805 -
4806 4898 if (scard_getstatchng_ret != SCARD_S_SUCCESS) {
4807 4899 CACKEY_DEBUG_PRINTF("Returning CKR_GENERAL_ERROR (%i) because SCardGetStatusChange failed: %lx", CKR_GENERAL_ERROR, scard_getstatchng_ret);
4808 4900
4809 4901 return(CKR_GENERAL_ERROR);
4810 4902 }
4811 4903
4812 - for (currslot = 0; currslot < reader_state_slot; currslot++) {
4813 - CACKEY_DEBUG_PRINTF("[slot = %u] CurrentState = %lx, EventState = %lx",
4814 - currslot,
4815 - reader_states[currslot].dwCurrentState & 0xffff,
4816 - reader_states[currslot].dwEventState & 0xffff
4904 + mutex_retval = cackey_mutex_lock(cackey_biglock);
4905 + if (mutex_retval != 0) {
4906 + CACKEY_DEBUG_PRINTF("Error. Locking failed.");
4907 +
4908 + return(CKR_GENERAL_ERROR);
4909 + }
4910 +
4911 + for (reader_state_slot = 0; reader_state_slot < reader_state_slot_cnt; reader_state_slot++) {
4912 + CACKEY_DEBUG_PRINTF("[pcsc/slot = %u] CurrentState = %lx, EventState = %lx",
4913 + reader_state_slot,
4914 + reader_states[reader_state_slot].dwCurrentState & 0xffff,
4915 + reader_states[reader_state_slot].dwEventState & 0xffff
4817 4916 );
4818 4917
4819 - cackey_slot = (struct cackey_slot *) reader_states[currslot].pvUserData;
4918 + cackey_slot = NULL;
4919 + for (currslot = 0; currslot < (sizeof(cackey_slots) / sizeof(cackey_slots[0])); currslot++) {
4920 + if (cackey_slots[currslot].internal) {
4921 + continue;
4922 + }
4923 +
4924 + if (reader_states[reader_state_slot].szReader == NULL) {
4925 + continue;
4926 + }
4927 +
4928 + if (cackey_slots[currslot].pcsc_reader == NULL) {
4929 + continue;
4930 + }
4931 +
4932 + CACKEY_DEBUG_PRINTF("Checking to see if pcsc/slot:%u (%s) is cackey/slot:%u (%s)...",
4933 + reader_state_slot,
4934 + reader_states[reader_state_slot].szReader,
4935 + currslot,
4936 + cackey_slots[currslot].pcsc_reader
4937 + );
4938 +
4939 + if (strcmp(reader_states[reader_state_slot].szReader, cackey_slots[currslot].pcsc_reader) != 0) {
4940 + CACKEY_DEBUG_PRINTF(" no match");
4941 +
4942 + continue;
4943 + }
4944 +
4945 + cackey_slot = &cackey_slots[currslot];
4946 +
4947 + CACKEY_DEBUG_PRINTF(" match, slot = %p", cackey_slot);
4948 +
4949 + break;
4950 + }
4820 4951
4821 4952 if (cackey_slot == NULL) {
4822 - /* XXX: TODO: Someone plugged in a new slot */
4953 + /* XXX: TODO: Someone plugged in a new slot or removed a slot */
4954 + CACKEY_DEBUG_PRINTF("WARNING: Unhandled code. Slot inserted or removed.");
4955 +
4823 4956 continue;
4824 4957 }
4825 4958
4826 4959 slot_changed = 0;
4827 4960
4828 4961 if ((flags & CKF_DONT_BLOCK) == CKF_DONT_BLOCK) {
4829 - if (cackey_slot->pcsc_state != reader_states[currslot].dwEventState) {
4962 + if (cackey_slot->pcsc_state != reader_states[reader_state_slot].dwEventState) {
4830 4963 slot_changed = 1;
4831 4964 }
4832 4965 } else {
4833 - if (reader_states[currslot].dwCurrentState != reader_states[currslot].dwEventState) {
4966 + if (reader_states[reader_state_slot].dwCurrentState != reader_states[reader_state_slot].dwEventState) {
4834 4967 slot_changed = 1;
4835 4968 }
4836 4969 }
4837 4970
4838 4971 if (slot_changed == 0) {
4972 + CACKEY_DEBUG_PRINTF("[pcsc/slot = %u] Slot did not change", (unsigned int) reader_state_slot);
4973 +
4839 4974 continue;
4840 4975 }
4841 4976
4842 4977 CACKEY_DEBUG_PRINTF("Returning slot changed: %u", (unsigned int) cackey_slot->id);
4843 4978
4844 - cackey_slot->pcsc_state = reader_states[currslot].dwEventState;
4979 + cackey_slot->pcsc_state = reader_states[reader_state_slot].dwEventState;
4845 4980 *pSlotID = (CK_SLOT_ID) cackey_slot->id;
4846 4981
4847 4982 CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK);
4983 +
4984 + mutex_retval = cackey_mutex_unlock(cackey_biglock);
4985 + if (mutex_retval != 0) {
4986 + CACKEY_DEBUG_PRINTF("Error. Unlocking failed.");
4987 +
4988 + return(CKR_GENERAL_ERROR);
4989 + }
4848 4990
4849 4991 return(CKR_OK);
4850 4992 }
4993 +
4994 + mutex_retval = cackey_mutex_unlock(cackey_biglock);
4995 + if (mutex_retval != 0) {
4996 + CACKEY_DEBUG_PRINTF("Error. Unlocking failed.");
4997 +
4998 + return(CKR_GENERAL_ERROR);
4999 + }
4851 5000
4852 5001 if ((flags & CKF_DONT_BLOCK) != CKF_DONT_BLOCK) {
4853 5002 CACKEY_DEBUG_PRINTF("Returning CKR_NO_EVENT (%i), but asked to block !? BUG ENCOUNTERED.", CKR_NO_EVENT);
4854 5003 } else {
4855 5004 CACKEY_DEBUG_PRINTF("Returning CKR_NO_EVENT (%i)", CKR_NO_EVENT);
4856 5005 }
4857 5006