Check-in [b5ecb7c2d6]
Overview
Comment:Added support for updating the PIN
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:b5ecb7c2d6bcf1626969f443a67d31f5b7b6ed4e
User & Date: rkeene on 2015-07-15 20:05:35
Other Links: manifest | tags
Context
2015-07-16
16:18
Updated to retry login if it fails with a 6D 00 (wrong instruction) check-in: 4e30511f94 user: rkeene tags: trunk
16:06
Reset the card and rescan for certificates if we get the ISO 7816 error 6D 00 (Wrong instruction) error from the card when trying to verify. Closed-Leaf check-in: 52569c3e74 user: rkeene tags: piv-reset-on-wronginstruction
2015-07-15
20:10
Merged in trunk Leaf check-in: 38771da1e8 user: rkeene tags: require-login-if-needed
20:08
Merged in trunk Closed-Leaf check-in: bab332232a user: rkeene tags: protected-auth-path
20:05
Added support for updating the PIN check-in: b5ecb7c2d6 user: rkeene tags: trunk
18:47
Updated KPS CA Certs check-in: efe7692225 user: rkeene tags: trunk
Changes

Modified cackey.c from [65139610e9] to [3a0d4abad4].

    81     81   #define GSCIS_INSTR_READ_BINARY       0xB0
    82     82   #define GSCIS_INSTR_UPDATE_BINARY     0xD6
    83     83   #define GSCIS_INSTR_SELECT            0xA4
    84     84   #define GSCIS_INSTR_EXTERNAL_AUTH     0x82
    85     85   #define GSCIS_INSTR_GET_CHALLENGE     0x84
    86     86   #define GSCIS_INSTR_INTERNAL_AUTH     0x88
    87     87   #define GSCIS_INSTR_VERIFY            0x20
           88  +#define GSCIS_INSTR_CHANGE_REFERENCE  0x24
    88     89   #define GSCIS_INSTR_SIGN              0x2A
    89     90   #define GSCIS_INSTR_GET_PROP          0x56
    90     91   #define GSCIS_INSTR_GET_ACR           0x4C
    91     92   #define GSCIS_INSTR_READ_BUFFER       0x52
    92     93   #define GSCIS_INSTR_SIGNDECRYPT       0x42
    93     94   
    94     95   #define GSCIS_PARAM_SELECT_APPLET     0x04
................................................................................
  1529   1530   			xmit_buf[xmit_len++] = le;
  1530   1531   		}
  1531   1532   	}
  1532   1533   
  1533   1534   	/* Begin Smartcard Transaction */
  1534   1535   	cackey_begin_transaction(slot);
  1535   1536   
  1536         -	if (class == GSCIS_CLASS_ISO7816 && instruction == GSCIS_INSTR_VERIFY && p1 == 0x00) {
         1537  +	if (class == GSCIS_CLASS_ISO7816 && (instruction == GSCIS_INSTR_VERIFY || instruction == GSCIS_INSTR_CHANGE_REFERENCE) && p1 == 0x00) {
  1537   1538   		CACKEY_DEBUG_PRINTF("Sending APDU: <<censored>>");
  1538   1539   	} else {
  1539   1540   		CACKEY_DEBUG_PRINTBUF("Sending APDU:", xmit_buf, xmit_len);
  1540   1541   	}
  1541   1542   
  1542   1543   	recv_len = sizeof(recv_buf);
  1543   1544   	scard_xmit_ret = SCardTransmit(slot->pcsc_card, pioSendPci, xmit_buf, xmit_len, NULL, recv_buf, &recv_len);
................................................................................
  3137   3138    *
  3138   3139    * RETURN VALUE
  3139   3140    *     ...
  3140   3141    *
  3141   3142    * NOTES
  3142   3143    *     ...
  3143   3144    *
         3145  + */
         3146  +static cackey_ret cackey_set_pin(struct cackey_slot *slot, unsigned char *old_pin, unsigned long old_pin_len, unsigned char *pin, unsigned long pin_len) {
         3147  +	struct cackey_pcsc_identity *pcsc_identities;
         3148  +	unsigned char cac_pin[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
         3149  +	unsigned char old_cac_pin[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
         3150  +	unsigned char pin_update[sizeof(cac_pin) + sizeof(old_cac_pin)];
         3151  +	unsigned long num_certs;
         3152  +	uint16_t response_code;
         3153  +	int tries_remaining;
         3154  +	int send_ret;
         3155  +	int key_reference = 0x00;
         3156  +
         3157  +	/* Apparently, CAC PINs are *EXACTLY* 8 bytes long -- pad with 0xFF if too short */
         3158  +	if (pin_len >= 8) {
         3159  +		memcpy(cac_pin, pin, 8);
         3160  +	} else {
         3161  +		memcpy(cac_pin, pin, pin_len);
         3162  +	}
         3163  +
         3164  +	if (old_pin_len >= 8) {
         3165  +		memcpy(old_cac_pin, old_pin, 8);
         3166  +	} else {
         3167  +		memcpy(old_cac_pin, old_pin, old_pin_len);
         3168  +	}
         3169  +
         3170  +	/* Concatenate both PINs together to send as a single instruction */
         3171  +	memcpy(pin_update, old_cac_pin, sizeof(old_cac_pin));
         3172  +	memcpy(pin_update + sizeof(old_cac_pin), cac_pin, sizeof(cac_pin));
         3173  +
         3174  +	/* Reject PINs which are too short */
         3175  +	if (pin_len < 5) {
         3176  +		CACKEY_DEBUG_PRINTF("Rejecting New PIN which is too short (length = %lu, must be atleast 5)", pin_len);
         3177  +
         3178  +		return(CACKEY_PCSC_E_BADPIN);
         3179  +	}
         3180  +
         3181  +	if (old_pin_len < 5) {
         3182  +		CACKEY_DEBUG_PRINTF("Rejecting Old PIN which is too short (length = %lu, must be atleast 5)", old_pin_len);
         3183  +
         3184  +		return(CACKEY_PCSC_E_BADPIN);
         3185  +	}
         3186  +
         3187  +	/* PIV authentication uses a "key_reference" of 0x80 */
         3188  +	pcsc_identities = cackey_read_certs(slot, NULL, &num_certs);
         3189  +	if (num_certs > 0 && pcsc_identities != NULL) {
         3190  +		switch (pcsc_identities[0].id_type) {
         3191  +			case CACKEY_ID_TYPE_PIV:
         3192  +				CACKEY_DEBUG_PRINTF("We have PIV card, so we will attempt to authenticate using the PIV Application key reference");
         3193  +
         3194  +				key_reference = 0x80;
         3195  +				break;
         3196  +			default:
         3197  +				break;
         3198  +		}
         3199  +
         3200  +		cackey_free_certs(pcsc_identities, num_certs, 1);
         3201  +	}
         3202  +
         3203  +	/* Issue a Set PIN (CHANGE REFERENCE) */
         3204  +	send_ret = cackey_send_apdu(slot, GSCIS_CLASS_ISO7816, GSCIS_INSTR_CHANGE_REFERENCE, 0x00, key_reference, sizeof(pin_update), pin_update, 0x00, &response_code, NULL, NULL);
         3205  +
         3206  +	if (send_ret != CACKEY_PCSC_S_OK) {
         3207  +		if ((response_code & 0x63C0) == 0x63C0) {
         3208  +			tries_remaining = (response_code & 0xF);
         3209  +
         3210  +			CACKEY_DEBUG_PRINTF("PIN Verification failed, %i tries remaining", tries_remaining);
         3211  +
         3212  +			return(CACKEY_PCSC_E_BADPIN);
         3213  +		}
         3214  +
         3215  +		if (response_code == 0x6983) {
         3216  +			CACKEY_DEBUG_PRINTF("Unable to set PIN, device is locked or changing the PIN is disabled");
         3217  +
         3218  +			return(CACKEY_PCSC_E_LOCKED);
         3219  +		}
         3220  +
         3221  +		return(CACKEY_PCSC_E_GENERIC);
         3222  +	}
         3223  +
         3224  +	CACKEY_DEBUG_PRINTF("PIN Change succeeded");
         3225  +
         3226  +	return(CACKEY_PCSC_S_OK);
         3227  +}
         3228  +
         3229  +/*
         3230  + * SYNPOSIS
         3231  + *     ...
         3232  + *
         3233  + * ARGUMENTS
         3234  + *     ...
         3235  + *
         3236  + * RETURN VALUE
         3237  + *     ...
         3238  + *
         3239  + * NOTES
         3240  + *     ...
         3241  + *
  3144   3242    */
  3145   3243   static cackey_ret cackey_login(struct cackey_slot *slot, unsigned char *pin, unsigned long pin_len, int *tries_remaining_p) {
  3146   3244   	struct cackey_pcsc_identity *pcsc_identities;
  3147   3245   	unsigned char cac_pin[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
  3148   3246   	unsigned long num_certs;
  3149   3247   	uint16_t response_code;
  3150   3248   	int tries_remaining;
................................................................................
  4170   4268   		return(identities);
  4171   4269   	}
  4172   4270   
  4173   4271   
  4174   4272   	*ids_found = 0;
  4175   4273   	return(NULL);
  4176   4274   }
         4275  +
         4276  +static cackey_ret cackey_get_pin(char *pinbuf) {
         4277  +	FILE *pinfd;
         4278  +	char *fgets_ret;
         4279  +	int pclose_ret;
         4280  +
         4281  +	if (cackey_pin_command == NULL) {
         4282  +		return(CACKEY_PCSC_E_GENERIC);
         4283  +	}
         4284  +
         4285  +	if (pinbuf == NULL) {
         4286  +		return(CACKEY_PCSC_E_GENERIC);
         4287  +	}
         4288  +
         4289  +	CACKEY_DEBUG_PRINTF("CACKEY_PIN_COMMAND = %s", cackey_pin_command);
         4290  +
         4291  +	pinfd = popen(cackey_pin_command, "r");
         4292  +	if (pinfd == NULL) {
         4293  +		CACKEY_DEBUG_PRINTF("Error.  %s: Unable to run", cackey_pin_command);
         4294  +
         4295  +		return(CACKEY_PCSC_E_BADPIN);
         4296  +	}
         4297  +
         4298  +	fgets_ret = fgets(pinbuf, 32, pinfd);
         4299  +	if (fgets_ret == NULL) {
         4300  +		pinbuf[0] = '\0';
         4301  +	}
         4302  +
         4303  +	pclose_ret = pclose(pinfd);
         4304  +	if (pclose_ret == -1 && errno == ECHILD) {
         4305  +		CACKEY_DEBUG_PRINTF("Notice.  pclose() indicated it could not get the status of the child, assuming it succeeeded !");
         4306  +
         4307  +		pclose_ret = 0;
         4308  +	}
         4309  +
         4310  +	if (pclose_ret != 0) {
         4311  +		CACKEY_DEBUG_PRINTF("Error.  %s: exited with non-zero status of %i", cackey_pin_command, pclose_ret);
         4312  +
         4313  +		return(CACKEY_PCSC_E_BADPIN);
         4314  +	}
         4315  +
         4316  +	if (strlen(pinbuf) < 1) {
         4317  +		CACKEY_DEBUG_PRINTF("Error.  %s: returned no data", cackey_pin_command);
         4318  +
         4319  +		return(CACKEY_PCSC_E_BADPIN);
         4320  +	}
         4321  +
         4322  +	if (pinbuf[strlen(pinbuf) - 1] == '\n') {
         4323  +		pinbuf[strlen(pinbuf) - 1] = '\0';
         4324  +	}
         4325  +
         4326  +	return(CACKEY_PCSC_S_OK);
         4327  +}
  4177   4328   
  4178   4329   CK_DEFINE_FUNCTION(CK_RV, C_Initialize)(CK_VOID_PTR pInitArgs) {
  4179   4330   	CK_C_INITIALIZE_ARGS CK_PTR args;
  4180   4331   	uint32_t idx, highest_slot;
  4181   4332   	int mutex_init_ret;
  4182   4333   	int include_dod_certs;
  4183   4334   
................................................................................
  4987   5138   	}
  4988   5139   
  4989   5140   	CACKEY_DEBUG_PRINTF("Returning CKR_TOKEN_WRITE_PROTECTED (%i)", CKR_TOKEN_WRITE_PROTECTED);
  4990   5141   
  4991   5142   	return(CKR_TOKEN_WRITE_PROTECTED);
  4992   5143   }
  4993   5144   
  4994         -/* We don't support this method. */
  4995   5145   CK_DEFINE_FUNCTION(CK_RV, C_SetPIN)(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pOldPin, CK_ULONG ulOldPinLen, CK_UTF8CHAR_PTR pNewPin, CK_ULONG ulNewPinLen) {
  4996         -	CACKEY_DEBUG_PRINTF("Called.");
  4997         -
  4998         -	if (!cackey_initialized) {
  4999         -		CACKEY_DEBUG_PRINTF("Error.  Not initialized.");
  5000         -
  5001         -		return(CKR_CRYPTOKI_NOT_INITIALIZED);
  5002         -	}
  5003         -
  5004         -	CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED);
  5005         -
  5006         -	return(CKR_FUNCTION_NOT_SUPPORTED);
         5146  +	char oldpinbuf[64], newpinbuf[64];
         5147  +	cackey_ret set_pin_ret, get_pin_ret;
         5148  +	CK_SLOT_ID slotID;
         5149  +	int mutex_retval;
         5150  +
         5151  +	CACKEY_DEBUG_PRINTF("Called.");
         5152  +
         5153  +	if (!cackey_initialized) {
         5154  +		CACKEY_DEBUG_PRINTF("Error.  Not initialized.");
         5155  +
         5156  +		return(CKR_CRYPTOKI_NOT_INITIALIZED);
         5157  +	}
         5158  +
         5159  +	mutex_retval = cackey_mutex_lock(cackey_biglock);
         5160  +	if (mutex_retval != 0) {
         5161  +		CACKEY_DEBUG_PRINTF("Error.  Locking failed.");
         5162  +
         5163  +		return(CKR_GENERAL_ERROR);
         5164  +	}
         5165  +
         5166  +	if (!cackey_sessions[hSession].active) {
         5167  +		cackey_mutex_unlock(cackey_biglock);
         5168  +
         5169  +		CACKEY_DEBUG_PRINTF("Error.  Session not active.");
         5170  +		
         5171  +		return(CKR_SESSION_HANDLE_INVALID);
         5172  +	}
         5173  +
         5174  +	slotID = cackey_sessions[hSession].slotID;
         5175  +
         5176  +	if (slotID < 0 || slotID >= (sizeof(cackey_slots) / sizeof(cackey_slots[0]))) {
         5177  +		CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), outside of valid range", slotID);
         5178  +
         5179  +		cackey_mutex_unlock(cackey_biglock);
         5180  +
         5181  +		return(CKR_GENERAL_ERROR);
         5182  +	}
         5183  +
         5184  +	if (cackey_slots[slotID].active == 0) {
         5185  +		CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), slot not currently active", slotID);
         5186  +
         5187  +		cackey_mutex_unlock(cackey_biglock);
         5188  +
         5189  +		return(CKR_GENERAL_ERROR);
         5190  +	}
         5191  +
         5192  +	if (cackey_pin_command != NULL) {
         5193  +		/* Get old PIN */
         5194  +		get_pin_ret = cackey_get_pin(oldpinbuf);
         5195  +
         5196  +		if (get_pin_ret != CACKEY_PCSC_S_OK) {
         5197  +			CACKEY_DEBUG_PRINTF("Error while getting Old PIN, returning CKR_PIN_INCORRECT.");
         5198  +
         5199  +			cackey_mutex_unlock(cackey_biglock);
         5200  +			
         5201  +			return(CKR_PIN_INCORRECT);
         5202  +		}
         5203  +
         5204  +		pOldPin = (CK_UTF8CHAR_PTR) oldpinbuf;
         5205  +		ulOldPinLen = strlen(oldpinbuf);
         5206  +
         5207  +		/* Get new PIN */
         5208  +		get_pin_ret = cackey_get_pin(newpinbuf);
         5209  +
         5210  +		if (get_pin_ret != CACKEY_PCSC_S_OK) {
         5211  +			CACKEY_DEBUG_PRINTF("Error while getting New PIN, returning CKR_PIN_INVALID.");
         5212  +
         5213  +			cackey_mutex_unlock(cackey_biglock);
         5214  +			
         5215  +			return(CKR_PIN_INVALID);
         5216  +		}
         5217  +
         5218  +		pNewPin = (CK_UTF8CHAR_PTR) newpinbuf;
         5219  +		ulNewPinLen = strlen(newpinbuf);
         5220  +	}
         5221  +
         5222  +	if (pOldPin == NULL) {
         5223  +		CACKEY_DEBUG_PRINTF("Old PIN value is wrong (null).");
         5224  +
         5225  +		cackey_mutex_unlock(cackey_biglock);
         5226  +
         5227  +		return(CKR_PIN_INCORRECT);
         5228  +	}
         5229  +
         5230  +	if (ulOldPinLen == 0 || ulOldPinLen > 8) {
         5231  +		CACKEY_DEBUG_PRINTF("Old PIN length is wrong: %lu.", (unsigned long) ulOldPinLen);
         5232  +
         5233  +		cackey_mutex_unlock(cackey_biglock);
         5234  +
         5235  +		return(CKR_PIN_INCORRECT);
         5236  +	}
         5237  +
         5238  +	if (pNewPin == NULL) {
         5239  +		CACKEY_DEBUG_PRINTF("New PIN value is wrong (either NULL, or too long/short).");
         5240  +
         5241  +		cackey_mutex_unlock(cackey_biglock);
         5242  +
         5243  +		return(CKR_PIN_INVALID);
         5244  +	}
         5245  +
         5246  +	if (ulNewPinLen < 5 || ulNewPinLen > 8) {
         5247  +		CACKEY_DEBUG_PRINTF("New PIN length is wrong: %lu, must be atleast 5 and no more than 8.", (unsigned long) ulNewPinLen);
         5248  +
         5249  +		cackey_mutex_unlock(cackey_biglock);
         5250  +
         5251  +		return(CKR_PIN_LEN_RANGE);
         5252  +	}
         5253  +
         5254  +	set_pin_ret = cackey_set_pin(&cackey_slots[slotID], pOldPin, ulOldPinLen, pNewPin, ulNewPinLen);
         5255  +
         5256  +	if (set_pin_ret != CACKEY_PCSC_S_OK) {
         5257  +		if (cackey_pin_command == NULL) {
         5258  +			cackey_slots[slotID].token_flags |= CKF_LOGIN_REQUIRED;
         5259  +		}
         5260  +
         5261  +		if (set_pin_ret == CACKEY_PCSC_E_LOCKED) {
         5262  +			cackey_slots[slotID].token_flags |= CKF_USER_PIN_LOCKED;
         5263  +		}
         5264  +	}
         5265  +
         5266  +	mutex_retval = cackey_mutex_unlock(cackey_biglock);
         5267  +	if (mutex_retval != 0) {
         5268  +		CACKEY_DEBUG_PRINTF("Error.  Unlocking failed.");
         5269  +
         5270  +		return(CKR_GENERAL_ERROR);
         5271  +	}
         5272  +
         5273  +	switch (set_pin_ret) {
         5274  +		case CACKEY_PCSC_S_OK:
         5275  +			CACKEY_DEBUG_PRINTF("Successfully set PIN.");
         5276  +
         5277  +			return(CKR_OK);
         5278  +		case CACKEY_PCSC_E_BADPIN:
         5279  +			CACKEY_DEBUG_PRINTF("PIN was invalid.");
         5280  +
         5281  +			return(CKR_PIN_INVALID);
         5282  +		case CACKEY_PCSC_E_LOCKED:
         5283  +			CACKEY_DEBUG_PRINTF("Token is locked or this change is not permitted.");
         5284  +
         5285  +			return(CKR_PIN_LOCKED);
         5286  +		default:
         5287  +			CACKEY_DEBUG_PRINTF("Something else went wrong changing the PIN: %i", set_pin_ret);
         5288  +
         5289  +			return(CKR_GENERAL_ERROR);
         5290  +	}
         5291  +
         5292  +	return(CKR_GENERAL_ERROR);
  5007   5293   }
  5008   5294   
  5009   5295   CK_DEFINE_FUNCTION(CK_RV, C_OpenSession)(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY notify, CK_SESSION_HANDLE_PTR phSession) {
  5010   5296   	unsigned long idx;
  5011   5297   	int mutex_retval;
  5012   5298   	int found_session = 0;
  5013   5299   
................................................................................
  5287   5573   	CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED);
  5288   5574   
  5289   5575   	return(CKR_FUNCTION_NOT_SUPPORTED);
  5290   5576   }
  5291   5577   
  5292   5578   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) {
  5293   5579   	CK_SLOT_ID slotID;
  5294         -	FILE *pinfd;
  5295         -	char *pincmd, pinbuf[64], *fgets_ret;
         5580  +	cackey_ret get_pin_ret;
         5581  +	char pinbuf[64];
  5296   5582   	int mutex_retval;
  5297   5583   	int tries_remaining;
  5298   5584   	int login_ret;
  5299         -	int pclose_ret;
  5300   5585   
  5301   5586   	CACKEY_DEBUG_PRINTF("Called.");
  5302   5587   
  5303   5588   	if (!cackey_initialized) {
  5304   5589   		CACKEY_DEBUG_PRINTF("Error.  Not initialized.");
  5305   5590   
  5306   5591   		return(CKR_CRYPTOKI_NOT_INITIALIZED);
................................................................................
  5355   5640   		if (lock_mutex) {
  5356   5641   			cackey_mutex_unlock(cackey_biglock);
  5357   5642   		}
  5358   5643   
  5359   5644   		return(CKR_GENERAL_ERROR);
  5360   5645   	}
  5361   5646   
  5362         -	pincmd = cackey_pin_command;
  5363         -	if (pincmd != NULL) {
  5364         -		CACKEY_DEBUG_PRINTF("CACKEY_PIN_COMMAND = %s", pincmd);
  5365         -
         5647  +	if (cackey_pin_command != NULL) {
  5366   5648   		if (pPin != NULL) {
  5367   5649   			CACKEY_DEBUG_PRINTF("Protected authentication path in effect and PIN provided !?");
  5368   5650   		}
  5369   5651   
  5370         -		pinfd = popen(pincmd, "r");
  5371         -		if (pinfd == NULL) {
  5372         -			CACKEY_DEBUG_PRINTF("Error.  %s: Unable to run", pincmd);
         5652  +		get_pin_ret = cackey_get_pin(pinbuf);
         5653  +
         5654  +		if (get_pin_ret != CACKEY_PCSC_S_OK) {
         5655  +			CACKEY_DEBUG_PRINTF("cackey_get_pin() returned in failure, assuming the PIN was incorrect.");
  5373   5656   
  5374   5657   			if (lock_mutex) {
  5375   5658   				cackey_mutex_unlock(cackey_biglock);
  5376   5659   			}
  5377   5660   
  5378         -			CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT);
  5379         -
  5380   5661   			return(CKR_PIN_INCORRECT);
  5381   5662   		}
  5382   5663   
  5383         -		fgets_ret = fgets(pinbuf, sizeof(pinbuf), pinfd);
  5384         -		if (fgets_ret == NULL) {
  5385         -			pinbuf[0] = '\0';
  5386         -		}
  5387         -
  5388         -		pclose_ret = pclose(pinfd);
  5389         -		if (pclose_ret == -1 && errno == ECHILD) {
  5390         -			CACKEY_DEBUG_PRINTF("Notice.  pclose() indicated it could not get the status of the child, assuming it succeeeded !");
  5391         -
  5392         -			pclose_ret = 0;
  5393         -		}
  5394         -
  5395         -		if (pclose_ret != 0) {
  5396         -			CACKEY_DEBUG_PRINTF("Error.  %s: exited with non-zero status of %i", pincmd, pclose_ret);
  5397         -
  5398         -			if (lock_mutex) {
  5399         -				cackey_mutex_unlock(cackey_biglock);
  5400         -			}
  5401         -
  5402         -			CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT);
  5403         -
  5404         -			return(CKR_PIN_INCORRECT);
  5405         -		}
  5406         -
  5407         -		if (strlen(pinbuf) < 1) {
  5408         -			CACKEY_DEBUG_PRINTF("Error.  %s: returned no data", pincmd);
  5409         -
  5410         -			if (lock_mutex) {
  5411         -				cackey_mutex_unlock(cackey_biglock);
  5412         -			}
  5413         -
  5414         -			CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT);
  5415         -
  5416         -			return(CKR_PIN_INCORRECT);
  5417         -		}
  5418         -
  5419         -		if (pinbuf[strlen(pinbuf) - 1] == '\n') {
  5420         -			pinbuf[strlen(pinbuf) - 1] = '\0';
  5421         -		}
  5422         -
  5423   5664   		pPin = (CK_UTF8CHAR_PTR) pinbuf;
  5424   5665   		ulPinLen = strlen(pinbuf);
  5425   5666   	}
  5426   5667   
  5427   5668   	login_ret = cackey_login(&cackey_slots[slotID], pPin, ulPinLen, &tries_remaining);
  5428   5669   	if (login_ret != CACKEY_PCSC_S_OK) {
  5429   5670   		if (lock_mutex) {