Diff

Differences From Artifact [60fa6fcd12]:

To Artifact [a802283a94]:


81
82
83
84
85
86
87

88
89
90
91
92
93
94
....
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
....
3153
3154
3155
3156
3157
3158
3159

































































































3160
3161
3162
3163
3164
3165
3166
....
4186
4187
4188
4189
4190
4191
4192





















































4193
4194
4195
4196
4197
4198
4199
....
4999
5000
5001
5002
5003
5004
5005
5006
5007





5008
5009
5010
5011
5012
5013
5014
5015
5016



5017


















































































































5018















5019
5020
5021
5022
5023
5024
5025
....
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
....
5367
5368
5369
5370
5371
5372
5373
5374
5375
5376
5377
5378
5379
5380
5381
5382
5383

5384

5385
5386
5387
5388
5389
5390
5391
5392
5393
5394
5395
5396
5397
5398
5399
5400
5401
5402
5403
5404
5405
5406
5407
5408
5409
5410
5411
5412
5413
5414
5415
5416
5417
5418
5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
5430
5431
5432
5433
5434
5435
5436
5437
5438
5439
5440
5441
#define GSCIS_INSTR_READ_BINARY       0xB0
#define GSCIS_INSTR_UPDATE_BINARY     0xD6
#define GSCIS_INSTR_SELECT            0xA4
#define GSCIS_INSTR_EXTERNAL_AUTH     0x82
#define GSCIS_INSTR_GET_CHALLENGE     0x84
#define GSCIS_INSTR_INTERNAL_AUTH     0x88
#define GSCIS_INSTR_VERIFY            0x20

#define GSCIS_INSTR_SIGN              0x2A
#define GSCIS_INSTR_GET_PROP          0x56
#define GSCIS_INSTR_GET_ACR           0x4C
#define GSCIS_INSTR_READ_BUFFER       0x52
#define GSCIS_INSTR_SIGNDECRYPT       0x42

#define GSCIS_PARAM_SELECT_APPLET     0x04
................................................................................
			xmit_buf[xmit_len++] = le;
		}
	}

	/* Begin Smartcard Transaction */
	cackey_begin_transaction(slot);

	if (class == GSCIS_CLASS_ISO7816 && instruction == GSCIS_INSTR_VERIFY && p1 == 0x00) {
		CACKEY_DEBUG_PRINTF("Sending APDU: <<censored>>");
	} else {
		CACKEY_DEBUG_PRINTBUF("Sending APDU:", xmit_buf, xmit_len);
	}

	recv_len = sizeof(recv_buf);
	scard_xmit_ret = SCardTransmit(slot->pcsc_card, pioSendPci, xmit_buf, xmit_len, NULL, recv_buf, &recv_len);
................................................................................
 *
 * RETURN VALUE
 *     ...
 *
 * NOTES
 *     ...
 *

































































































 */
static cackey_ret cackey_login(struct cackey_slot *slot, unsigned char *pin, unsigned long pin_len, int *tries_remaining_p) {
	struct cackey_pcsc_identity *pcsc_identities;
	unsigned char cac_pin[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
	unsigned long num_certs;
	uint16_t response_code;
	int tries_remaining;
................................................................................
		return(identities);
	}


	*ids_found = 0;
	return(NULL);
}






















































CK_DEFINE_FUNCTION(CK_RV, C_Initialize)(CK_VOID_PTR pInitArgs) {
	CK_C_INITIALIZE_ARGS CK_PTR args;
	uint32_t idx, highest_slot;
	int mutex_init_ret;
	int include_dod_certs;

................................................................................
	}

	CACKEY_DEBUG_PRINTF("Returning CKR_TOKEN_WRITE_PROTECTED (%i)", CKR_TOKEN_WRITE_PROTECTED);

	return(CKR_TOKEN_WRITE_PROTECTED);
}

/* We don't support this method. */
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) {





	CACKEY_DEBUG_PRINTF("Called.");

	if (!cackey_initialized) {
		CACKEY_DEBUG_PRINTF("Error.  Not initialized.");

		return(CKR_CRYPTOKI_NOT_INITIALIZED);
	}

	CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED);






















































































































	return(CKR_FUNCTION_NOT_SUPPORTED);















}

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) {
	unsigned long idx;
	int mutex_retval;
	int found_session = 0;

................................................................................
	CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED);

	return(CKR_FUNCTION_NOT_SUPPORTED);
}

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) {
	CK_SLOT_ID slotID;
	FILE *pinfd;
	char *pincmd, pinbuf[64], *fgets_ret;
	int mutex_retval;
	int tries_remaining;
	int login_ret;
	int pclose_ret;

	CACKEY_DEBUG_PRINTF("Called.");

	if (!cackey_initialized) {
		CACKEY_DEBUG_PRINTF("Error.  Not initialized.");

		return(CKR_CRYPTOKI_NOT_INITIALIZED);
................................................................................
		if (lock_mutex) {
			cackey_mutex_unlock(cackey_biglock);
		}

		return(CKR_GENERAL_ERROR);
	}

	pincmd = cackey_pin_command;
	if (pincmd != NULL) {
		CACKEY_DEBUG_PRINTF("CACKEY_PIN_COMMAND = %s", pincmd);

		if (pPin != NULL) {
			CACKEY_DEBUG_PRINTF("Protected authentication path in effect and PIN provided !?");
		}

		pinfd = popen(pincmd, "r");
		if (pinfd == NULL) {

			CACKEY_DEBUG_PRINTF("Error.  %s: Unable to run", pincmd);


			if (lock_mutex) {
				cackey_mutex_unlock(cackey_biglock);
			}

			CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT);

			return(CKR_PIN_INCORRECT);
		}

		fgets_ret = fgets(pinbuf, sizeof(pinbuf), pinfd);
		if (fgets_ret == NULL) {
			pinbuf[0] = '\0';
		}

		pclose_ret = pclose(pinfd);
		if (pclose_ret == -1 && errno == ECHILD) {
			CACKEY_DEBUG_PRINTF("Notice.  pclose() indicated it could not get the status of the child, assuming it succeeeded !");

			pclose_ret = 0;
		}

		if (pclose_ret != 0) {
			CACKEY_DEBUG_PRINTF("Error.  %s: exited with non-zero status of %i", pincmd, pclose_ret);

			if (lock_mutex) {
				cackey_mutex_unlock(cackey_biglock);
			}

			CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT);

			return(CKR_PIN_INCORRECT);
		}

		if (strlen(pinbuf) < 1) {
			CACKEY_DEBUG_PRINTF("Error.  %s: returned no data", pincmd);

			if (lock_mutex) {
				cackey_mutex_unlock(cackey_biglock);
			}

			CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT);

			return(CKR_PIN_INCORRECT);
		}

		if (pinbuf[strlen(pinbuf) - 1] == '\n') {
			pinbuf[strlen(pinbuf) - 1] = '\0';
		}

		pPin = (CK_UTF8CHAR_PTR) pinbuf;
		ulPinLen = strlen(pinbuf);
	}

	login_ret = cackey_login(&cackey_slots[slotID], pPin, ulPinLen, &tries_remaining);
	if (login_ret != CACKEY_PCSC_S_OK) {
		if (lock_mutex) {







>







 







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







<

>
>
>
>
>








<
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|
|



<







 







|
<
<
<




|
<
>
|
>





<
<



<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
....
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
....
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
....
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
....
5150
5151
5152
5153
5154
5155
5156

5157
5158
5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170

5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287
5288
5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
....
5585
5586
5587
5588
5589
5590
5591
5592
5593
5594
5595
5596

5597
5598
5599
5600
5601
5602
5603
....
5652
5653
5654
5655
5656
5657
5658
5659



5660
5661
5662
5663
5664

5665
5666
5667
5668
5669
5670
5671
5672


5673
5674
5675








































5676
5677
5678
5679
5680
5681
5682
#define GSCIS_INSTR_READ_BINARY       0xB0
#define GSCIS_INSTR_UPDATE_BINARY     0xD6
#define GSCIS_INSTR_SELECT            0xA4
#define GSCIS_INSTR_EXTERNAL_AUTH     0x82
#define GSCIS_INSTR_GET_CHALLENGE     0x84
#define GSCIS_INSTR_INTERNAL_AUTH     0x88
#define GSCIS_INSTR_VERIFY            0x20
#define GSCIS_INSTR_CHANGE_REFERENCE  0x24
#define GSCIS_INSTR_SIGN              0x2A
#define GSCIS_INSTR_GET_PROP          0x56
#define GSCIS_INSTR_GET_ACR           0x4C
#define GSCIS_INSTR_READ_BUFFER       0x52
#define GSCIS_INSTR_SIGNDECRYPT       0x42

#define GSCIS_PARAM_SELECT_APPLET     0x04
................................................................................
			xmit_buf[xmit_len++] = le;
		}
	}

	/* Begin Smartcard Transaction */
	cackey_begin_transaction(slot);

	if (class == GSCIS_CLASS_ISO7816 && (instruction == GSCIS_INSTR_VERIFY || instruction == GSCIS_INSTR_CHANGE_REFERENCE) && p1 == 0x00) {
		CACKEY_DEBUG_PRINTF("Sending APDU: <<censored>>");
	} else {
		CACKEY_DEBUG_PRINTBUF("Sending APDU:", xmit_buf, xmit_len);
	}

	recv_len = sizeof(recv_buf);
	scard_xmit_ret = SCardTransmit(slot->pcsc_card, pioSendPci, xmit_buf, xmit_len, NULL, recv_buf, &recv_len);
................................................................................
 *
 * RETURN VALUE
 *     ...
 *
 * NOTES
 *     ...
 *
 */
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) {
	struct cackey_pcsc_identity *pcsc_identities;
	unsigned char cac_pin[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
	unsigned char old_cac_pin[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
	unsigned char pin_update[sizeof(cac_pin) + sizeof(old_cac_pin)];
	unsigned long num_certs;
	uint16_t response_code;
	int tries_remaining;
	int send_ret;
	int key_reference = 0x00;

	/* Apparently, CAC PINs are *EXACTLY* 8 bytes long -- pad with 0xFF if too short */
	if (pin_len >= 8) {
		memcpy(cac_pin, pin, 8);
	} else {
		memcpy(cac_pin, pin, pin_len);
	}

	if (old_pin_len >= 8) {
		memcpy(old_cac_pin, old_pin, 8);
	} else {
		memcpy(old_cac_pin, old_pin, old_pin_len);
	}

	/* Concatenate both PINs together to send as a single instruction */
	memcpy(pin_update, old_cac_pin, sizeof(old_cac_pin));
	memcpy(pin_update + sizeof(old_cac_pin), cac_pin, sizeof(cac_pin));

	/* Reject PINs which are too short */
	if (pin_len < 5) {
		CACKEY_DEBUG_PRINTF("Rejecting New PIN which is too short (length = %lu, must be atleast 5)", pin_len);

		return(CACKEY_PCSC_E_BADPIN);
	}

	if (old_pin_len < 5) {
		CACKEY_DEBUG_PRINTF("Rejecting Old PIN which is too short (length = %lu, must be atleast 5)", old_pin_len);

		return(CACKEY_PCSC_E_BADPIN);
	}

	/* PIV authentication uses a "key_reference" of 0x80 */
	pcsc_identities = cackey_read_certs(slot, NULL, &num_certs);
	if (num_certs > 0 && pcsc_identities != NULL) {
		switch (pcsc_identities[0].id_type) {
			case CACKEY_ID_TYPE_PIV:
				CACKEY_DEBUG_PRINTF("We have PIV card, so we will attempt to authenticate using the PIV Application key reference");

				key_reference = 0x80;
				break;
			default:
				break;
		}

		cackey_free_certs(pcsc_identities, num_certs, 1);
	}

	/* Issue a Set PIN (CHANGE REFERENCE) */
	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);

	if (send_ret != CACKEY_PCSC_S_OK) {
		if ((response_code & 0x63C0) == 0x63C0) {
			tries_remaining = (response_code & 0xF);

			CACKEY_DEBUG_PRINTF("PIN Verification failed, %i tries remaining", tries_remaining);

			return(CACKEY_PCSC_E_BADPIN);
		}

		if (response_code == 0x6983) {
			CACKEY_DEBUG_PRINTF("Unable to set PIN, device is locked or changing the PIN is disabled");

			return(CACKEY_PCSC_E_LOCKED);
		}

		return(CACKEY_PCSC_E_GENERIC);
	}

	CACKEY_DEBUG_PRINTF("PIN Change succeeded");

	return(CACKEY_PCSC_S_OK);
}

/*
 * SYNPOSIS
 *     ...
 *
 * ARGUMENTS
 *     ...
 *
 * RETURN VALUE
 *     ...
 *
 * NOTES
 *     ...
 *
 */
static cackey_ret cackey_login(struct cackey_slot *slot, unsigned char *pin, unsigned long pin_len, int *tries_remaining_p) {
	struct cackey_pcsc_identity *pcsc_identities;
	unsigned char cac_pin[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
	unsigned long num_certs;
	uint16_t response_code;
	int tries_remaining;
................................................................................
		return(identities);
	}


	*ids_found = 0;
	return(NULL);
}

static cackey_ret cackey_get_pin(char *pinbuf) {
	FILE *pinfd;
	char *fgets_ret;
	int pclose_ret;

	if (cackey_pin_command == NULL) {
		return(CACKEY_PCSC_E_GENERIC);
	}

	if (pinbuf == NULL) {
		return(CACKEY_PCSC_E_GENERIC);
	}

	CACKEY_DEBUG_PRINTF("CACKEY_PIN_COMMAND = %s", cackey_pin_command);

	pinfd = popen(cackey_pin_command, "r");
	if (pinfd == NULL) {
		CACKEY_DEBUG_PRINTF("Error.  %s: Unable to run", cackey_pin_command);

		return(CACKEY_PCSC_E_BADPIN);
	}

	fgets_ret = fgets(pinbuf, 32, pinfd);
	if (fgets_ret == NULL) {
		pinbuf[0] = '\0';
	}

	pclose_ret = pclose(pinfd);
	if (pclose_ret == -1 && errno == ECHILD) {
		CACKEY_DEBUG_PRINTF("Notice.  pclose() indicated it could not get the status of the child, assuming it succeeeded !");

		pclose_ret = 0;
	}

	if (pclose_ret != 0) {
		CACKEY_DEBUG_PRINTF("Error.  %s: exited with non-zero status of %i", cackey_pin_command, pclose_ret);

		return(CACKEY_PCSC_E_BADPIN);
	}

	if (strlen(pinbuf) < 1) {
		CACKEY_DEBUG_PRINTF("Error.  %s: returned no data", cackey_pin_command);

		return(CACKEY_PCSC_E_BADPIN);
	}

	if (pinbuf[strlen(pinbuf) - 1] == '\n') {
		pinbuf[strlen(pinbuf) - 1] = '\0';
	}

	return(CACKEY_PCSC_S_OK);
}

CK_DEFINE_FUNCTION(CK_RV, C_Initialize)(CK_VOID_PTR pInitArgs) {
	CK_C_INITIALIZE_ARGS CK_PTR args;
	uint32_t idx, highest_slot;
	int mutex_init_ret;
	int include_dod_certs;

................................................................................
	}

	CACKEY_DEBUG_PRINTF("Returning CKR_TOKEN_WRITE_PROTECTED (%i)", CKR_TOKEN_WRITE_PROTECTED);

	return(CKR_TOKEN_WRITE_PROTECTED);
}


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) {
	char oldpinbuf[64], newpinbuf[64];
	cackey_ret set_pin_ret, get_pin_ret;
	CK_SLOT_ID slotID;
	int mutex_retval;

	CACKEY_DEBUG_PRINTF("Called.");

	if (!cackey_initialized) {
		CACKEY_DEBUG_PRINTF("Error.  Not initialized.");

		return(CKR_CRYPTOKI_NOT_INITIALIZED);
	}


	mutex_retval = cackey_mutex_lock(cackey_biglock);
	if (mutex_retval != 0) {
		CACKEY_DEBUG_PRINTF("Error.  Locking failed.");

		return(CKR_GENERAL_ERROR);
	}

	if (!cackey_sessions[hSession].active) {
		cackey_mutex_unlock(cackey_biglock);

		CACKEY_DEBUG_PRINTF("Error.  Session not active.");
		
		return(CKR_SESSION_HANDLE_INVALID);
	}

	slotID = cackey_sessions[hSession].slotID;

	if (slotID < 0 || slotID >= (sizeof(cackey_slots) / sizeof(cackey_slots[0]))) {
		CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), outside of valid range", slotID);

		cackey_mutex_unlock(cackey_biglock);

		return(CKR_GENERAL_ERROR);
	}

	if (cackey_slots[slotID].active == 0) {
		CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), slot not currently active", slotID);

		cackey_mutex_unlock(cackey_biglock);

		return(CKR_GENERAL_ERROR);
	}

	if (cackey_pin_command != NULL) {
		/* Get old PIN */
		get_pin_ret = cackey_get_pin(oldpinbuf);

		if (get_pin_ret != CACKEY_PCSC_S_OK) {
			CACKEY_DEBUG_PRINTF("Error while getting Old PIN, returning CKR_PIN_INCORRECT.");

			cackey_mutex_unlock(cackey_biglock);
			
			return(CKR_PIN_INCORRECT);
		}

		pOldPin = (CK_UTF8CHAR_PTR) oldpinbuf;
		ulOldPinLen = strlen(oldpinbuf);

		/* Get new PIN */
		get_pin_ret = cackey_get_pin(newpinbuf);

		if (get_pin_ret != CACKEY_PCSC_S_OK) {
			CACKEY_DEBUG_PRINTF("Error while getting New PIN, returning CKR_PIN_INVALID.");

			cackey_mutex_unlock(cackey_biglock);
			
			return(CKR_PIN_INVALID);
		}

		pNewPin = (CK_UTF8CHAR_PTR) newpinbuf;
		ulNewPinLen = strlen(newpinbuf);
	}

	if (pOldPin == NULL) {
		CACKEY_DEBUG_PRINTF("Old PIN value is wrong (null).");

		cackey_mutex_unlock(cackey_biglock);

		return(CKR_PIN_INCORRECT);
	}

	if (ulOldPinLen == 0 || ulOldPinLen > 8) {
		CACKEY_DEBUG_PRINTF("Old PIN length is wrong: %lu.", (unsigned long) ulOldPinLen);

		cackey_mutex_unlock(cackey_biglock);

		return(CKR_PIN_INCORRECT);
	}

	if (pNewPin == NULL) {
		CACKEY_DEBUG_PRINTF("New PIN value is wrong (either NULL, or too long/short).");

		cackey_mutex_unlock(cackey_biglock);

		return(CKR_PIN_INVALID);
	}

	if (ulNewPinLen < 5 || ulNewPinLen > 8) {
		CACKEY_DEBUG_PRINTF("New PIN length is wrong: %lu, must be atleast 5 and no more than 8.", (unsigned long) ulNewPinLen);

		cackey_mutex_unlock(cackey_biglock);

		return(CKR_PIN_LEN_RANGE);
	}

	set_pin_ret = cackey_set_pin(&cackey_slots[slotID], pOldPin, ulOldPinLen, pNewPin, ulNewPinLen);

	if (set_pin_ret != CACKEY_PCSC_S_OK) {
		if (cackey_pin_command == NULL) {
			cackey_slots[slotID].token_flags |= CKF_LOGIN_REQUIRED;
		}

		if (set_pin_ret == CACKEY_PCSC_E_LOCKED) {
			cackey_slots[slotID].token_flags |= CKF_USER_PIN_LOCKED;
		}
	}

	mutex_retval = cackey_mutex_unlock(cackey_biglock);
	if (mutex_retval != 0) {
		CACKEY_DEBUG_PRINTF("Error.  Unlocking failed.");

		return(CKR_GENERAL_ERROR);
	}

	switch (set_pin_ret) {
		case CACKEY_PCSC_S_OK:
			CACKEY_DEBUG_PRINTF("Successfully set PIN.");

			return(CKR_OK);
		case CACKEY_PCSC_E_BADPIN:
			CACKEY_DEBUG_PRINTF("PIN was invalid.");

			return(CKR_PIN_INVALID);
		case CACKEY_PCSC_E_LOCKED:
			CACKEY_DEBUG_PRINTF("Token is locked or this change is not permitted.");

			return(CKR_PIN_LOCKED);
		default:
			CACKEY_DEBUG_PRINTF("Something else went wrong changing the PIN: %i", set_pin_ret);

			return(CKR_GENERAL_ERROR);
	}

	return(CKR_GENERAL_ERROR);
}

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) {
	unsigned long idx;
	int mutex_retval;
	int found_session = 0;

................................................................................
	CACKEY_DEBUG_PRINTF("Returning CKR_FUNCTION_NOT_SUPPORTED (%i)", CKR_FUNCTION_NOT_SUPPORTED);

	return(CKR_FUNCTION_NOT_SUPPORTED);
}

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) {
	CK_SLOT_ID slotID;
	cackey_ret get_pin_ret;
	char pinbuf[64];
	int mutex_retval;
	int tries_remaining;
	int login_ret;


	CACKEY_DEBUG_PRINTF("Called.");

	if (!cackey_initialized) {
		CACKEY_DEBUG_PRINTF("Error.  Not initialized.");

		return(CKR_CRYPTOKI_NOT_INITIALIZED);
................................................................................
		if (lock_mutex) {
			cackey_mutex_unlock(cackey_biglock);
		}

		return(CKR_GENERAL_ERROR);
	}

	if (cackey_pin_command != NULL) {



		if (pPin != NULL) {
			CACKEY_DEBUG_PRINTF("Protected authentication path in effect and PIN provided !?");
		}

		get_pin_ret = cackey_get_pin(pinbuf);


		if (get_pin_ret != CACKEY_PCSC_S_OK) {
			CACKEY_DEBUG_PRINTF("cackey_get_pin() returned in failure, assuming the PIN was incorrect.");

			if (lock_mutex) {
				cackey_mutex_unlock(cackey_biglock);
			}



			return(CKR_PIN_INCORRECT);
		}









































		pPin = (CK_UTF8CHAR_PTR) pinbuf;
		ulPinLen = strlen(pinbuf);
	}

	login_ret = cackey_login(&cackey_slots[slotID], pPin, ulPinLen, &tries_remaining);
	if (login_ret != CACKEY_PCSC_S_OK) {
		if (lock_mutex) {