Check-in [8ba93699b4]
Overview
Comment:Merged in changes from PIV
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:8ba93699b446465b1b1ce456b037b964eccedcc0
User & Date: rkeene on 2014-03-14 14:30:03
Other Links: manifest | tags
Context
2014-03-18
04:33
Updated to work with pclose() failures check-in: 42891ae8ca user: rkeene tags: trunk
2014-03-14
14:30
Merged in changes from PIV check-in: 8ba93699b4 user: rkeene tags: trunk
14:25
Updated to reset the card if a retry is required check-in: ad6536ceb0 user: rkeene tags: protected-auth-path
2014-01-17
13:35
Work towards fixing listing of slots to not list redundant slots check-in: afd6df445d user: rkeene tags: trunk
Changes

Modified cackey.c from [6eb21adaf8] to [3de1a30e4b].

  1113   1113   
  1114   1114   	if (slot->pcsc_card_connected) {
  1115   1115   		SCardDisconnect(slot->pcsc_card, SCARD_LEAVE_CARD);
  1116   1116   	}
  1117   1117   
  1118   1118   	slot->slot_reset = 1;
  1119   1119   	slot->pcsc_card_connected = 0;
  1120         -	slot->token_flags = CKF_LOGIN_REQUIRED;
         1120  +	if (cackey_pin_command == NULL) {
         1121  +		slot->token_flags = CKF_LOGIN_REQUIRED;
         1122  +	} else {
         1123  +		slot->token_flags = 0;
         1124  +	}
  1121   1125   
  1122   1126   	CACKEY_DEBUG_PRINTF("Returning.");
  1123   1127   
  1124   1128   	return;
  1125   1129   }
  1126   1130   
  1127   1131   /*
  1128   1132    * SYNPOSIS
  1129         - *     LONG cackey_reconnect_card(struct cackey_slot *slot, DWORD default_protocol, LPDWORD selected_protocol);
         1133  + *     LONG cackey_reconnect_card(struct cackey_slot *slot, DWORD default_protocol);
  1130   1134    *
  1131   1135    * ARGUMENTS
  1132   1136    *     cackey_slot *slot
  1133   1137    *         Slot to send commands to
  1134   1138    *
  1135   1139    *     DWORD default_protocol
  1136   1140    *         Protocol to attempt first
  1137   1141    *
  1138         - *     LPDWORD selected_protocol
  1139         - *         [OUT] Protocol selected
  1140         - *
  1141   1142    * RETURN VALUE
  1142   1143    *     The return value from SCardReconnect()
  1143   1144    *
  1144   1145    * NOTES
  1145   1146    *     This function is a wrapper around SCardReconnect()
  1146   1147    *
  1147   1148    *     The SCardReconnect() function call will be called first with the
  1148   1149    *     dwPreferredProtocols of "default_protocol".  If that call returns
  1149   1150    *     SCARD_E_PROTO_MISMATCH try again with a protocol of T=0, and failing
  1150   1151    *     that T=1.
  1151   1152    *
  1152   1153    */
  1153         -static LONG cackey_reconnect_card(struct cackey_slot *slot, DWORD default_protocol, LPDWORD selected_protocol) {
         1154  +static LONG cackey_reconnect_card(struct cackey_slot *slot, DWORD default_protocol) {
         1155  +	DWORD selected_protocol;
  1154   1156   	LONG scard_conn_ret;
  1155   1157   
  1156         -	scard_conn_ret = SCardReconnect(slot->pcsc_card, SCARD_SHARE_SHARED, default_protocol, SCARD_RESET_CARD, selected_protocol);
         1158  +	selected_protocol = 0;
         1159  +
         1160  +	scard_conn_ret = SCardReconnect(slot->pcsc_card, SCARD_SHARE_SHARED, default_protocol, SCARD_RESET_CARD, &selected_protocol);
  1157   1161   
  1158   1162   	if (scard_conn_ret == SCARD_E_PROTO_MISMATCH) {
  1159   1163   		CACKEY_DEBUG_PRINTF("SCardReconnect() returned SCARD_E_PROTO_MISMATCH, trying with just T=0")
  1160         -		scard_conn_ret = SCardReconnect(slot->pcsc_card, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, SCARD_RESET_CARD, selected_protocol);
         1164  +		scard_conn_ret = SCardReconnect(slot->pcsc_card, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, SCARD_RESET_CARD, &selected_protocol);
  1161   1165   
  1162   1166   		if (scard_conn_ret == SCARD_E_PROTO_MISMATCH) {
  1163   1167   			CACKEY_DEBUG_PRINTF("SCardReconnect() returned SCARD_E_PROTO_MISMATCH, trying with just T=1")
  1164         -			scard_conn_ret = SCardReconnect(slot->pcsc_card, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1, SCARD_RESET_CARD, selected_protocol);
         1168  +			scard_conn_ret = SCardReconnect(slot->pcsc_card, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1, SCARD_RESET_CARD, &selected_protocol);
  1165   1169   		}
  1166   1170   	}
         1171  +
         1172  +	if (scard_conn_ret == SCARD_S_SUCCESS) {
         1173  +		slot->protocol = selected_protocol;
         1174  +	}
  1167   1175   
  1168   1176   	return(scard_conn_ret);
  1169   1177   }
  1170   1178   
  1171   1179   /*
  1172   1180    * SYNPOSIS
  1173   1181    *     cackey_ret cackey_connect_card(struct cackey_slot *slot);
................................................................................
  1230   1238   
  1231   1239   				if (scard_conn_ret == SCARD_E_PROTO_MISMATCH) {
  1232   1240   					CACKEY_DEBUG_PRINTF("SCardConnect() returned SCARD_E_PROTO_MISMATCH, trying with just T=1")
  1233   1241   					scard_conn_ret = SCardConnect(*cackey_pcsc_handle, slot->pcsc_reader, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1, &slot->pcsc_card, &protocol);
  1234   1242   				}
  1235   1243   			}
  1236   1244   
  1237         -			scard_conn_ret = cackey_reconnect_card(slot, protocol, &protocol);
         1245  +			scard_conn_ret = cackey_reconnect_card(slot, protocol);
  1238   1246   		}
  1239   1247   
  1240   1248   		if (scard_conn_ret != SCARD_S_SUCCESS) {
  1241   1249   			CACKEY_DEBUG_PRINTF("Connection to card failed, returning in failure (SCardConnect() = %s/%li)", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_conn_ret), (long) scard_conn_ret);
  1242   1250   
  1243   1251   			return(CACKEY_PCSC_E_GENERIC);
  1244   1252   		}
................................................................................
  1437   1445    *     goes away.
  1438   1446    *
  1439   1447    */
  1440   1448   static cackey_ret cackey_send_apdu(struct cackey_slot *slot, unsigned char class, unsigned char instruction, unsigned char p1, unsigned char p2, unsigned int lc, unsigned char *data, unsigned int le, uint16_t *respcode, unsigned char *respdata, size_t *respdata_len) {
  1441   1449   	uint8_t major_rc, minor_rc;
  1442   1450   	size_t bytes_to_copy, tmp_respdata_len;
  1443   1451   	LPCSCARD_IO_REQUEST pioSendPci;
  1444         -	DWORD protocol;
  1445   1452   	DWORD xmit_len, recv_len;
  1446   1453   	LONG scard_xmit_ret, scard_reconn_ret;
  1447   1454   	BYTE xmit_buf[1024], recv_buf[1024];
  1448   1455   	int pcsc_connect_ret, pcsc_getresp_ret;
  1449   1456   	int idx;
  1450   1457   
  1451   1458   	CACKEY_DEBUG_PRINTF("Called.");
................................................................................
  1532   1539   
  1533   1540   	if (scard_xmit_ret == SCARD_E_NOT_TRANSACTED) {
  1534   1541   		CACKEY_DEBUG_PRINTF("Failed to send APDU to card (SCardTransmit() = %s/%lx), will ask calling function to retry (not resetting card)...", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_xmit_ret), (unsigned long) scard_xmit_ret);
  1535   1542   
  1536   1543   		/* Begin Smartcard Transaction */
  1537   1544   		cackey_end_transaction(slot);
  1538   1545   
         1546  +		cackey_reconnect_card(slot, slot->protocol);
         1547  +
  1539   1548   		return(CACKEY_PCSC_E_RETRY);
  1540   1549   	}
  1541   1550   
  1542   1551   	if (scard_xmit_ret != SCARD_S_SUCCESS) {
  1543   1552   		CACKEY_DEBUG_PRINTF("Failed to send APDU to card (SCardTransmit() = %s/%lx)", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_xmit_ret), (unsigned long) scard_xmit_ret);
  1544   1553   
  1545   1554   		CACKEY_DEBUG_PRINTF("Marking slot as having been reset");
  1546   1555   		cackey_mark_slot_reset(slot);
  1547   1556   
  1548   1557   		if (scard_xmit_ret == SCARD_W_RESET_CARD) {
  1549   1558   			CACKEY_DEBUG_PRINTF("Reset required, please hold...");
  1550   1559   
  1551         -			scard_reconn_ret = cackey_reconnect_card(slot, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &protocol);
         1560  +			scard_reconn_ret = cackey_reconnect_card(slot, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1);
  1552   1561   
  1553   1562   			if (scard_reconn_ret == SCARD_S_SUCCESS) {
  1554         -				/* Update protocol */
  1555         -				slot->protocol = protocol;
  1556   1563   				switch (slot->protocol) {
  1557   1564   					case SCARD_PROTOCOL_T0:
  1558   1565   						pioSendPci = SCARD_PCI_T0;
  1559   1566   
  1560   1567   						break;
  1561   1568   					case SCARD_PROTOCOL_T1:
  1562   1569   						pioSendPci = SCARD_PCI_T1;
................................................................................
  2853   2860   				send_ret = cackey_send_apdu(slot, class, NISTSP800_73_3_INSTR_GENAUTH, NISTSP800_78_3_ALGO_RSA2048, identity->pcsc_identity->card.piv.key_id, bytes_to_send, tmpbuf, le, &respcode, outbuf, &tmpoutbuflen);
  2854   2861   				break;
  2855   2862   			case CACKEY_ID_TYPE_CERT_ONLY:
  2856   2863   				break;
  2857   2864   		}
  2858   2865   
  2859   2866   		if (send_ret != CACKEY_PCSC_S_OK) {
  2860         -			CACKEY_DEBUG_PRINTF("ADPU Sending Failed -- returning in error.");
  2861         -
  2862   2867   			if (free_tmpbuf) {
  2863   2868   				if (tmpbuf_s) {
  2864   2869   					free(tmpbuf_s);
  2865   2870   				}
  2866   2871   			}
  2867   2872   
  2868   2873   			/* End transaction */
  2869   2874   			cackey_end_transaction(slot);
  2870   2875   
         2876  +			if (send_ret == CACKEY_PCSC_E_RETRY) {
         2877  +				CACKEY_DEBUG_PRINTF("ADPU Sending Failed -- retrying.");
         2878  +
         2879  +				return(cackey_signdecrypt(slot, identity, buf, buflen, outbuf, outbuflen, padInput, unpadOutput));
         2880  +			}
         2881  +
         2882  +			CACKEY_DEBUG_PRINTF("ADPU Sending Failed -- returning in error.");
         2883  +
  2871   2884   			if (respcode == 0x6982 || respcode == 0x6e00) {
  2872         -				CACKEY_DEBUG_PRINTF("Security status not satisified (respcode = 0x%04x).  Returning NEEDLOGIN", (int) respcode);
         2885  +				if (respcode == 0x6E00) {
         2886  +					CACKEY_DEBUG_PRINTF("Got \"WRONG CLASS\", this means we are talking to the wrong object (likely because the card went away) -- resetting");
         2887  +				} else {
         2888  +					CACKEY_DEBUG_PRINTF("Security status not satisified (respcode = 0x%04x).  Returning NEEDLOGIN", (int) respcode);
         2889  +				}
  2873   2890   
  2874   2891   				cackey_mark_slot_reset(slot);
         2892  +
         2893  +				slot->token_flags = CKF_LOGIN_REQUIRED;
  2875   2894   
  2876   2895   				return(CACKEY_PCSC_E_NEEDLOGIN);
  2877   2896   			}
  2878   2897   
  2879   2898   			if (respcode == 0x6E00) {
  2880   2899   				CACKEY_DEBUG_PRINTF("Got \"WRONG CLASS\", this means we are talking to the wrong object (likely because the card went away) -- resetting");
  2881   2900   
................................................................................
  3180   3199   
  3181   3200   	if (status_ret != SCARD_S_SUCCESS) {
  3182   3201   		cackey_mark_slot_reset(slot);
  3183   3202   
  3184   3203   		if (status_ret == SCARD_W_RESET_CARD) {
  3185   3204   			CACKEY_DEBUG_PRINTF("Reset required, please hold...");
  3186   3205   
  3187         -			scard_reconn_ret = cackey_reconnect_card(slot, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &protocol);
         3206  +			scard_reconn_ret = cackey_reconnect_card(slot, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1);
  3188   3207   			if (scard_reconn_ret == SCARD_S_SUCCESS) {
  3189         -				/* Update protocol */
  3190         -				slot->protocol = protocol;
  3191         -
  3192   3208   				/* Re-establish transaction, if it was present */
  3193   3209   				if (slot->transaction_depth > 0) {
  3194   3210   					slot->transaction_depth--;
  3195   3211   					slot->transaction_need_hw_lock = 1;
  3196   3212   					cackey_begin_transaction(slot);
  3197   3213   				}
  3198   3214   
................................................................................
  4439   4455   						if (slot_reset) {
  4440   4456   							cackey_slots[currslot].active = 1;
  4441   4457   							cackey_slots[currslot].internal = 0;
  4442   4458   							cackey_slots[currslot].pcsc_reader = strdup(pcsc_readers);
  4443   4459   							cackey_slots[currslot].pcsc_card_connected = 0;
  4444   4460   							cackey_slots[currslot].transaction_depth = 0;
  4445   4461   							cackey_slots[currslot].transaction_need_hw_lock = 0;
  4446         -							cackey_slots[currslot].token_flags = CKF_LOGIN_REQUIRED;
         4462  +							if (cackey_pin_command == NULL) {
         4463  +								cackey_slots[currslot].token_flags = CKF_LOGIN_REQUIRED;
         4464  +							} else {
         4465  +								cackey_slots[currslot].token_flags = 0;
         4466  +							}
  4447   4467   							cackey_slots[currslot].label = NULL;
  4448   4468   
  4449   4469   							cackey_mark_slot_reset(&cackey_slots[currslot]);
  4450   4470   						}
  4451   4471   					} else {
  4452   4472   						if (!cackey_slots[currslot].active) {
  4453   4473   							/* Artificially increase the number of active slots by what will become active */
................................................................................
  5188   5208   	}
  5189   5209   
  5190   5210   	CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED);
  5191   5211   
  5192   5212   	return(CKR_FUNCTION_NOT_SUPPORTED);
  5193   5213   }
  5194   5214   
  5195         -CK_DEFINE_FUNCTION(CK_RV, C_Login)(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) {
         5215  +CK_DEFINE_FUNCTION(CK_RV, _C_LoginMutexArg)(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen, int lock_mutex) {
  5196   5216   	CK_SLOT_ID slotID;
  5197   5217   	FILE *pinfd;
  5198   5218   	char *pincmd, pinbuf[64], *fgets_ret;
  5199   5219   	int mutex_retval;
  5200   5220   	int tries_remaining;
  5201   5221   	int login_ret;
  5202   5222   	int pclose_ret;
................................................................................
  5217   5237   
  5218   5238   	if (userType != CKU_USER) {
  5219   5239   		CACKEY_DEBUG_PRINTF("Error.  We only support USER mode, asked for %lu mode.", (unsigned long) userType)
  5220   5240   
  5221   5241   		return(CKR_USER_TYPE_INVALID);
  5222   5242   	}
  5223   5243   
  5224         -	mutex_retval = cackey_mutex_lock(cackey_biglock);
  5225         -	if (mutex_retval != 0) {
  5226         -		CACKEY_DEBUG_PRINTF("Error.  Locking failed.");
         5244  +	if (lock_mutex) {
         5245  +		mutex_retval = cackey_mutex_lock(cackey_biglock);
         5246  +		if (mutex_retval != 0) {
         5247  +			CACKEY_DEBUG_PRINTF("Error.  Locking failed.");
  5227   5248   
  5228         -		return(CKR_GENERAL_ERROR);
         5249  +			return(CKR_GENERAL_ERROR);
         5250  +		}
  5229   5251   	}
  5230   5252   
  5231   5253   	if (!cackey_sessions[hSession].active) {
  5232         -		cackey_mutex_unlock(cackey_biglock);
         5254  +		if (lock_mutex) {
         5255  +			cackey_mutex_unlock(cackey_biglock);
         5256  +		}
  5233   5257   
  5234   5258   		CACKEY_DEBUG_PRINTF("Error.  Session not active.");
  5235   5259   		
  5236   5260   		return(CKR_SESSION_HANDLE_INVALID);
  5237   5261   	}
  5238   5262   
  5239   5263   	slotID = cackey_sessions[hSession].slotID;
  5240   5264   
  5241   5265   	if (slotID < 0 || slotID >= (sizeof(cackey_slots) / sizeof(cackey_slots[0]))) {
  5242   5266   		CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), outside of valid range", slotID);
         5267  +
         5268  +		if (lock_mutex) {
         5269  +			cackey_mutex_unlock(cackey_biglock);
         5270  +		}
  5243   5271   
  5244   5272   		return(CKR_GENERAL_ERROR);
  5245   5273   	}
  5246   5274   
  5247   5275   	if (cackey_slots[slotID].active == 0) {
  5248   5276   		CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), slot not currently active", slotID);
  5249   5277   
  5250         -		cackey_mutex_unlock(cackey_biglock);
         5278  +		if (lock_mutex) {
         5279  +			cackey_mutex_unlock(cackey_biglock);
         5280  +		}
  5251   5281   
  5252   5282   		return(CKR_GENERAL_ERROR);
  5253   5283   	}
  5254   5284   
  5255   5285   	pincmd = cackey_pin_command;
  5256   5286   	if (pincmd != NULL) {
  5257   5287   		CACKEY_DEBUG_PRINTF("CACKEY_PIN_COMMAND = %s", pincmd);
................................................................................
  5260   5290   			CACKEY_DEBUG_PRINTF("Protected authentication path in effect and PIN provided !?");
  5261   5291   		}
  5262   5292   
  5263   5293   		pinfd = popen(pincmd, "r");
  5264   5294   		if (pinfd == NULL) {
  5265   5295   			CACKEY_DEBUG_PRINTF("Error.  %s: Unable to run", pincmd);
  5266   5296   
  5267         -			cackey_mutex_unlock(cackey_biglock);
         5297  +			if (lock_mutex) {
         5298  +				cackey_mutex_unlock(cackey_biglock);
         5299  +			}
  5268   5300   
  5269   5301   			CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT);
  5270   5302   
  5271   5303   			return(CKR_PIN_INCORRECT);
  5272   5304   		}
  5273   5305   
  5274   5306   		fgets_ret = fgets(pinbuf, sizeof(pinbuf), pinfd);
................................................................................
  5276   5308   			pinbuf[0] = '\0';
  5277   5309   		}
  5278   5310   
  5279   5311   		pclose_ret = pclose(pinfd);
  5280   5312   		if (pclose_ret != 0) {
  5281   5313   			CACKEY_DEBUG_PRINTF("Error.  %s: exited with non-zero status of %i", pincmd, pclose_ret);
  5282   5314   
  5283         -			cackey_mutex_unlock(cackey_biglock);
         5315  +			if (lock_mutex) {
         5316  +				cackey_mutex_unlock(cackey_biglock);
         5317  +			}
  5284   5318   
  5285   5319   			CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT);
  5286   5320   
  5287   5321   			return(CKR_PIN_INCORRECT);
  5288   5322   		}
  5289   5323   
  5290   5324   		if (strlen(pinbuf) < 1) {
  5291   5325   			CACKEY_DEBUG_PRINTF("Error.  %s: returned no data", pincmd);
  5292   5326   
  5293         -			cackey_mutex_unlock(cackey_biglock);
         5327  +			if (lock_mutex) {
         5328  +				cackey_mutex_unlock(cackey_biglock);
         5329  +			}
  5294   5330   
  5295   5331   			CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT);
  5296   5332   
  5297   5333   			return(CKR_PIN_INCORRECT);
  5298   5334   		}
  5299   5335   
  5300   5336   		if (pinbuf[strlen(pinbuf) - 1] == '\n') {
................................................................................
  5303   5339   
  5304   5340   		pPin = (CK_UTF8CHAR_PTR) pinbuf;
  5305   5341   		ulPinLen = strlen(pinbuf);
  5306   5342   	}
  5307   5343   
  5308   5344   	login_ret = cackey_login(&cackey_slots[slotID], pPin, ulPinLen, &tries_remaining);
  5309   5345   	if (login_ret != CACKEY_PCSC_S_OK) {
  5310         -		cackey_mutex_unlock(cackey_biglock);
         5346  +		if (lock_mutex) {
         5347  +			cackey_mutex_unlock(cackey_biglock);
         5348  +		}
  5311   5349   
  5312   5350   		if (login_ret == CACKEY_PCSC_E_LOCKED) {
  5313   5351   			CACKEY_DEBUG_PRINTF("Error.  Token is locked.");
  5314   5352   
  5315   5353   			cackey_slots[slotID].token_flags |= CKF_USER_PIN_LOCKED;
  5316   5354   
  5317   5355   			CACKEY_DEBUG_PRINTF("Returning CKR_PIN_LOCKED (%i)", (int) CKR_PIN_LOCKED);
................................................................................
  5336   5374   		return(CKR_GENERAL_ERROR);
  5337   5375   	}
  5338   5376   
  5339   5377   	cackey_slots[slotID].token_flags &= ~(CKF_USER_PIN_LOCKED | CKF_USER_PIN_COUNT_LOW | CKF_LOGIN_REQUIRED | CKF_USER_PIN_FINAL_TRY);
  5340   5378   
  5341   5379   	cackey_sessions[hSession].state = CKS_RO_USER_FUNCTIONS;
  5342   5380   
  5343         -	mutex_retval = cackey_mutex_unlock(cackey_biglock);
  5344         -	if (mutex_retval != 0) {
  5345         -		CACKEY_DEBUG_PRINTF("Error.  Unlocking failed.");
         5381  +	if (lock_mutex) {
         5382  +		mutex_retval = cackey_mutex_unlock(cackey_biglock);
         5383  +		if (mutex_retval != 0) {
         5384  +			CACKEY_DEBUG_PRINTF("Error.  Unlocking failed.");
  5346   5385   
  5347         -		return(CKR_GENERAL_ERROR);
         5386  +			return(CKR_GENERAL_ERROR);
         5387  +		}
  5348   5388   	}
  5349   5389   
  5350   5390   	CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK);
  5351   5391   
  5352   5392   	return(CKR_OK);
  5353   5393   }
         5394  +
         5395  +CK_DEFINE_FUNCTION(CK_RV, C_Login)(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) {
         5396  +	return(_C_LoginMutexArg(hSession, userType, pPin, ulPinLen, 1));
         5397  +}
  5354   5398   
  5355   5399   CK_DEFINE_FUNCTION(CK_RV, C_Logout)(CK_SESSION_HANDLE hSession) {
  5356   5400   	CK_SLOT_ID slotID;
  5357   5401   	int mutex_retval;
  5358   5402   
  5359   5403   	CACKEY_DEBUG_PRINTF("Called.");
  5360   5404   
................................................................................
  5398   5442   
  5399   5443   		cackey_mutex_unlock(cackey_biglock);
  5400   5444   
  5401   5445   		return(CKR_GENERAL_ERROR);
  5402   5446   	}
  5403   5447   
  5404   5448   	cackey_sessions[hSession].state = CKS_RO_PUBLIC_SESSION;
  5405         -	cackey_slots[slotID].token_flags = CKF_LOGIN_REQUIRED;
         5449  +
         5450  +	if (cackey_pin_command == NULL) {
         5451  +		cackey_slots[slotID].token_flags = CKF_LOGIN_REQUIRED;
         5452  +	} else {
         5453  +		cackey_slots[slotID].token_flags = 0;
         5454  +	}
  5406   5455   
  5407   5456   	mutex_retval = cackey_mutex_unlock(cackey_biglock);
  5408   5457   	if (mutex_retval != 0) {
  5409   5458   		CACKEY_DEBUG_PRINTF("Error.  Unlocking failed.");
  5410   5459   
  5411   5460   		return(CKR_GENERAL_ERROR);
  5412   5461   	}
................................................................................
  6322   6371   		return(CKR_GENERAL_ERROR);
  6323   6372   	}
  6324   6373   
  6325   6374   	switch (cackey_sessions[hSession].decrypt_mechanism) {
  6326   6375   		case CKM_RSA_PKCS:
  6327   6376   			/* Ask card to decrypt */
  6328   6377   			buflen = cackey_signdecrypt(&cackey_slots[slotID], cackey_sessions[hSession].decrypt_identity, pEncryptedPart, ulEncryptedPartLen, buf, sizeof(buf), 0, 1);
         6378  +
         6379  +			if (buflen == CACKEY_PCSC_E_NEEDLOGIN && cackey_pin_command != NULL) {
         6380  +				if (_C_LoginMutexArg(hSession, CKU_USER, NULL, 0, 0) == CKR_OK) {
         6381  +					buflen = cackey_signdecrypt(&cackey_slots[slotID], cackey_sessions[hSession].decrypt_identity, pEncryptedPart, ulEncryptedPartLen, buf, sizeof(buf), 0, 1);
         6382  +				}
         6383  +			}
  6329   6384   
  6330   6385   			if (buflen < 0) {
  6331   6386   				/* Decryption failed. */
  6332   6387   				if (buflen == CACKEY_PCSC_E_NEEDLOGIN) {
  6333   6388   					retval = CKR_USER_NOT_LOGGED_IN;
  6334   6389   				} else if (buflen == CACKEY_PCSC_E_TOKENABSENT) {
  6335   6390   					retval = CKR_DEVICE_REMOVED;
  6336   6391   				} else {
         6392  +					CACKEY_DEBUG_PRINTF("Failed to send APDU, error = %li", (long int) buflen);
         6393  +
  6337   6394   					retval = CKR_GENERAL_ERROR;
  6338   6395   				}
  6339   6396   			} else if (((unsigned long) buflen) > *pulPartLen && pPart) {
  6340   6397   				/* Decrypted data too large */
  6341   6398   				retval = CKR_BUFFER_TOO_SMALL;
  6342   6399   			} else {
  6343   6400   				if (pPart) {
................................................................................
  6833   6890   	}
  6834   6891   
  6835   6892   	switch (cackey_sessions[hSession].sign_mechanism) {
  6836   6893   		case CKM_RSA_PKCS:
  6837   6894   			/* Ask card to sign */
  6838   6895   			CACKEY_DEBUG_PRINTF("Asking to sign from identity %p in session %lu", (void *) cackey_sessions[hSession].sign_identity, (unsigned long) hSession);
  6839   6896   			sigbuflen = cackey_signdecrypt(&cackey_slots[slotID], cackey_sessions[hSession].sign_identity, cackey_sessions[hSession].sign_buf, cackey_sessions[hSession].sign_bufused, sigbuf, sizeof(sigbuf), 1, 0);
         6897  +
         6898  +			if (sigbuflen == CACKEY_PCSC_E_NEEDLOGIN && cackey_pin_command != NULL) {
         6899  +				if (_C_LoginMutexArg(hSession, CKU_USER, NULL, 0, 0) == CKR_OK) {
         6900  +					sigbuflen = cackey_signdecrypt(&cackey_slots[slotID], cackey_sessions[hSession].sign_identity, cackey_sessions[hSession].sign_buf, cackey_sessions[hSession].sign_bufused, sigbuf, sizeof(sigbuf), 1, 0);
         6901  +				}
         6902  +			}
  6840   6903   
  6841   6904   			if (sigbuflen < 0) {
  6842   6905   				/* Signing failed. */
  6843   6906   				if (sigbuflen == CACKEY_PCSC_E_NEEDLOGIN) {
  6844   6907   					retval = CKR_USER_NOT_LOGGED_IN;
  6845   6908   				} else if (sigbuflen == CACKEY_PCSC_E_TOKENABSENT) {
  6846   6909   					retval = CKR_DEVICE_REMOVED;