Exemplo n.º 1
0
/*
 * Process commands from remote clients (i.e. those offering a device).
 */
static int ria_svc_dev_handler(ct_socket_t * sock, header_t * hdr,
                               ct_buf_t * args, ct_buf_t * resp)
{
    unsigned char cmd;
    ria_peer_t *clnt, *peer;
    ria_device_t devinfo;
    int rc;

    clnt = (ria_peer_t *) sock->user_data;
    ria_print_packet(sock, 2, "dev <<", hdr, args);

    /* bounce response to peer right away */
    if (hdr->dest)
        goto bounce_to_peer;

    if (ct_buf_get(args, &cmd, 1) < 0)
        return IFD_ERROR_INVALID_MSG;

    switch (cmd) {
    case RIA_MGR_REGISTER:
        if (clnt->device.name[0])
            return IFD_ERROR_INVALID_ARG;
        if ((rc = ct_buf_get(args, &devinfo, sizeof(devinfo))) < 0)
            return IFD_ERROR_INVALID_ARG;
        if (devinfo.type[0] == '\0')
            return IFD_ERROR_INVALID_ARG;
        /* For security reasons, don't allow the handle counter
         * to wrap around. */
        if (dev_handle == 0)
            return IFD_ERROR_GENERIC;

        memcpy(&devinfo.address, clnt->device.address, RIA_NAME_MAX);
        clnt->device = devinfo;
        snprintf(clnt->device.handle, RIA_NAME_MAX,
                 "%s%u", clnt->device.type, dev_handle++);
        ifd_debug(1,
                  "%s registered new %s device , handle '%s', name `%s'",
                  clnt->device.address, clnt->device.type,
                  clnt->device.handle, clnt->device.name);
        return 0;
    }

    if (cmd < __RIA_PEER_CMD_BASE)
        return IFD_ERROR_INVALID_CMD;

    /* Push back the command byte */
    ct_buf_push(args, &cmd, 1);

bounce_to_peer:
    if ((peer = clnt->peer) == NULL)
        return IFD_ERROR_NOT_CONNECTED;

    rc = ct_socket_put_packet(peer->sock, hdr, args);

    /* Tell the caller not to send a response */
    hdr->xid = 0;
    return rc;
}
Exemplo n.º 2
0
Arquivo: conf.c Projeto: OpenSC/openct
/*
 * Eat initial white space from buffer
 */
static int skipws(void)
{
	unsigned int m, n, in_comment = 0;
	char *s;

      again:
	s = (char *)ct_buf_head(&config_buf);
	n = ct_buf_avail(&config_buf);

	for (m = 0; m < n; m++, s++) {
		if (*s == '#') {
			in_comment = 1;
		} else if (!in_comment && !isspace((int)*s)) {
			break;
		} else if (*s == '\n') {
			config_line++;
			in_comment = 0;
		}
	}

	ct_buf_get(&config_buf, NULL, m);
	if (in_comment) {
		if (ct_buf_read(&config_buf, config_fd) < 0) {
			ct_error("%s: error while reading file: %m",
				 config_filename);
			return -1;
		}
		goto again;
	}

	return 0;
}
Exemplo n.º 3
0
static int t0_send(ifd_protocol_t * prot, ct_buf_t * bp, int count)
{
	int n, avail;

	avail = ct_buf_avail(bp);
	if (count < 0)
		count = avail;
	if (count > avail || !avail)
		return -1;
	n = ifd_send_command(prot, ct_buf_head(bp), count);
	if (n >= 0)
		ct_buf_get(bp, NULL, count);
	return n;
}
Exemplo n.º 4
0
Arquivo: conf.c Projeto: OpenSC/openct
/*
 * Tokenizer
 */
static int get_token(char **tok)
{
	static char buffer[512];
	unsigned int m, n, copy, retry = 1;
	char *s;

	/* consume initial white space */
	if (skipws() < 0)
		return -1;

      again:
	s = (char *)ct_buf_head(&config_buf);
	n = ct_buf_avail(&config_buf);

	if (n && issepa(*s)) {
		m = 1;
	} else {
		for (m = 0; !isspace((int)s[m]) && !issepa(s[m]) && m < n;
		     m++) ;
	}

	/* If we hit the end of the buffer while scanning
	 * for white space, read more data and try 
	 * again */
	if (m >= n && retry) {
		if (ct_buf_read(&config_buf, config_fd) < 0) {
			ct_error("%s: error while reading file: %m",
				 config_filename);
			return -1;
		}
		retry = 0;
		goto again;
	}

	if (m == 0)
		return -1;

	if ((copy = m) >= sizeof(buffer))
		copy = sizeof(buffer) - 1;
	memcpy(buffer, s, copy);
	buffer[copy] = '\0';
	ct_buf_get(&config_buf, NULL, m);

	ifd_debug(5, "ifd_config_parse: token=\"%s\"", buffer);

	*tok = buffer;
	return 0;
}
Exemplo n.º 5
0
Arquivo: tlv.c Projeto: OpenSC/openct
/*
 * Parse TLV data
 */
int ct_tlv_parse(ct_tlv_parser_t * parser, ct_buf_t * bp)
{
	unsigned int avail, len;
	unsigned char *p, tag;

	/* Code below relies on it */
	assert(((ifd_tag_t) - 1) == 255);

	while ((avail = ct_buf_avail(bp)) != 0) {
		unsigned int header = 2;

		if (avail < 2)
			return -1;

		p = (unsigned char *)ct_buf_head(bp);
		tag = p[0];
		len = p[1];

		if (tag & __CT_TAG_LARGE) {
			parser->use_large_tags = 1;
			tag &= ~__CT_TAG_LARGE;
			if (avail < 3)
				return -1;
			len = (len << 8) | p[header++];
		}

		if (len == 0 || header + len > avail)
			return -1;

		parser->val[tag] = p + header;
		parser->len[tag] = len;

		ct_buf_get(bp, NULL, header + len);
	}

	return 0;
}
Exemplo n.º 6
0
int ifdhandler_process(ct_socket_t * sock, ifd_reader_t * reader,
		       ct_buf_t * argbuf, ct_buf_t * resbuf)
{
	unsigned char cmd, unit;
	ct_tlv_parser_t args;
	ct_tlv_builder_t resp;
	int rc;

	/* Get command and target unit */
	if (ct_buf_get(argbuf, &cmd, 1) < 0 || ct_buf_get(argbuf, &unit, 1) < 0)
		return IFD_ERROR_INVALID_MSG;

	ifd_debug(1, "ifdhandler_process(cmd=%s, unit=%u)",
		  get_cmd_name(cmd), unit);

	/* First, handle commands that don't do TLV encoded
	 * arguments - currently this is only CT_CMD_TRANSACT. */
	if (cmd == CT_CMD_TRANSACT_OLD) {
		/* Security - deny any APDUs if there's an
		 * exclusive lock held by some other client. */
		if ((rc =
		     ifdhandler_check_lock(sock, unit, IFD_LOCK_EXCLUSIVE)) < 0)
			return rc;
		return do_transact_old(reader, unit, argbuf, resbuf);
	}

	if ((rc = do_before_command(reader)) < 0) {
		return rc;
	}

	memset(&args, 0, sizeof(args));
	if (ct_tlv_parse(&args, argbuf) < 0)
		return IFD_ERROR_INVALID_MSG;
	if (args.use_large_tags)
		sock->use_large_tags = 1;

	ct_tlv_builder_init(&resp, resbuf, sock->use_large_tags);

	switch (cmd) {
	case CT_CMD_STATUS:
		rc = do_status(reader, unit, &args, &resp);
		break;

	case CT_CMD_OUTPUT:
		rc = do_output(reader, unit, &args, &resp);
		break;

	case CT_CMD_RESET:
	case CT_CMD_REQUEST_ICC:
		rc = do_reset(reader, unit, &args, &resp);
		break;

	case CT_CMD_EJECT_ICC:
		rc = do_eject(reader, unit, &args, &resp);
		break;

	case CT_CMD_PERFORM_VERIFY:
		rc = do_verify(reader, unit, &args, &resp);
		break;

	case CT_CMD_LOCK:
		rc = do_lock(sock, reader, unit, &args, &resp);
		break;

	case CT_CMD_UNLOCK:
		rc = do_unlock(sock, reader, unit, &args, &resp);
		break;

	case CT_CMD_MEMORY_READ:
		rc = do_memory_read(reader, unit, &args, &resp);
		break;

	case CT_CMD_MEMORY_WRITE:
		rc = do_memory_write(reader, unit, &args, &resp);
		break;

	case CT_CMD_TRANSACT:
		rc = do_transact(reader, unit, &args, &resp);
		break;
	case CT_CMD_SET_PROTOCOL:
		rc = do_set_protocol(reader, unit, &args, &resp);
		break;
	default:
		return IFD_ERROR_INVALID_CMD;
	}

	if (rc >= 0)
		rc = resp.error;

	/*
	 * TODO consider checking error
	 */
	do_after_command(reader);

	return rc;
}
Exemplo n.º 7
0
/*
 * Send an APDU through T=1
 */
static int t1_transceive(ifd_protocol_t * prot, int dad, const void *snd_buf,
			 size_t snd_len, void *rcv_buf, size_t rcv_len)
{
	t1_state_t *t1 = (t1_state_t *) prot;
	ct_buf_t sbuf, rbuf, tbuf;
	unsigned char sdata[T1_BUFFER_SIZE], sblk[5];
	unsigned int slen, retries, resyncs, sent_length = 0;
	size_t last_send = 0;

	if (snd_len == 0)
		return -1;

	/* we can't talk to a dead card / reader. Reset it! */
	if (t1->state == DEAD)
		return -1;

	t1->state = SENDING;
	retries = t1->retries;
	resyncs = 3;

	/* Initialize send/recv buffer */
	ct_buf_set(&sbuf, (void *)snd_buf, snd_len);
	ct_buf_init(&rbuf, rcv_buf, rcv_len);

	/* Send the first block */
	slen = t1_build(t1, sdata, dad, T1_I_BLOCK, &sbuf, &last_send);

	while (1) {
		unsigned char pcb;
		int n;

		retries--;

		if ((n = t1_xcv(t1, sdata, slen, sizeof(sdata))) < 0) {
			ifd_debug(1, "fatal: transmit/receive failed");
			t1->state = DEAD;
			goto error;
		}

		if (!t1_verify_checksum(t1, sdata, n)) {
			ifd_debug(1, "checksum failed");
			if (retries == 0 || sent_length)
				goto resync;
			slen = t1_build(t1, sdata,
					dad, T1_R_BLOCK | T1_EDC_ERROR,
					NULL, NULL);
			continue;
		}

		pcb = sdata[PCB];
		switch (t1_block_type(pcb)) {
		case T1_R_BLOCK:
			if (T1_IS_ERROR(pcb)) {
				ifd_debug(1, "received error block, err=%d",
					  T1_IS_ERROR(pcb));
				goto resync;
			}

			if (t1->state == RECEIVING) {
				slen = t1_build(t1, sdata,
						dad, T1_R_BLOCK, NULL, NULL);
				break;
			}

			/* If the card terminal requests the next
			 * sequence number, it received the previous
			 * block successfully */
			if (t1_seq(pcb) != t1->ns) {
				ct_buf_get(&sbuf, NULL, last_send);
				sent_length += last_send;
				last_send = 0;
				t1->ns ^= 1;
			}

			/* If there's no data available, the ICC
			 * shouldn't be asking for more */
			if (ct_buf_avail(&sbuf) == 0)
				goto resync;

			slen = t1_build(t1, sdata, dad, T1_I_BLOCK,
					&sbuf, &last_send);
			break;

		case T1_I_BLOCK:
			/* The first I-block sent by the ICC indicates
			 * the last block we sent was received successfully. */
			if (t1->state == SENDING) {
				ct_buf_get(&sbuf, NULL, last_send);
				last_send = 0;
				t1->ns ^= 1;
			}

			t1->state = RECEIVING;

			/* If the block sent by the card doesn't match
			 * what we expected it to send, reply with
			 * an R block */
			if (t1_seq(pcb) != t1->nr) {
				slen = t1_build(t1, sdata, dad,
						T1_R_BLOCK | T1_OTHER_ERROR,
						NULL, NULL);
				continue;
			}

			t1->nr ^= 1;

			if (ct_buf_put(&rbuf, sdata + 3, sdata[LEN]) < 0)
				goto error;

			if ((pcb & T1_MORE_BLOCKS) == 0)
				goto done;

			slen = t1_build(t1, sdata, dad, T1_R_BLOCK, NULL, NULL);
			break;

		case T1_S_BLOCK:
			if (T1_S_IS_RESPONSE(pcb) && t1->state == RESYNCH) {
				t1->state = SENDING;
				sent_length = 0;
				last_send = 0;
				resyncs = 3;
				retries = t1->retries;
				ct_buf_init(&rbuf, rcv_buf, rcv_len);
				slen = t1_build(t1, sdata, dad, T1_I_BLOCK,
						&sbuf, &last_send);
				continue;
			}

			if (T1_S_IS_RESPONSE(pcb))
				goto resync;

			ct_buf_init(&tbuf, sblk, sizeof(sblk));

			switch (T1_S_TYPE(pcb)) {
			case T1_S_RESYNC:
				/* the card is not allowed to send a resync. */
				goto resync;
			case T1_S_ABORT:
				ifd_debug(1, "abort requested");
				break;
			case T1_S_IFS:
				ifd_debug(1, "CT sent S-block with ifs=%u",
					  sdata[DATA]);
				if (sdata[DATA] == 0)
					goto resync;
				t1->ifsc = sdata[DATA];
				ct_buf_putc(&tbuf, sdata[DATA]);
				break;
			case T1_S_WTX:
				/* We don't handle the wait time extension
				 * yet */
				ifd_debug(1, "CT sent S-block with wtx=%u",
					  sdata[DATA]);
				t1->wtx = sdata[DATA];
				ct_buf_putc(&tbuf, sdata[DATA]);
				break;
			default:
				ct_error("T=1: Unknown S block type 0x%02x",
					 T1_S_TYPE(pcb));
				goto resync;
			}

			slen = t1_build(t1, sdata, dad,
					T1_S_BLOCK | T1_S_RESPONSE |
					T1_S_TYPE(pcb), &tbuf, NULL);
		}

		/* Everything went just splendid */
		retries = t1->retries;
		continue;

	      resync:
		/* the number or resyncs is limited, too */
		if (resyncs == 0)
			goto error;
		resyncs--;
		t1->ns = 0;
		t1->nr = 0;
		slen = t1_build(t1, sdata, dad, T1_S_BLOCK | T1_S_RESYNC, NULL,
				NULL);
		t1->state = RESYNCH;
		continue;
	}

      done:
	return ct_buf_avail(&rbuf);

      error:
	t1->state = DEAD;
	return -1;
}
Exemplo n.º 8
0
/*
 * Send an APDU through T=1
 */
int t1_transceive(t1_state_t * t1, unsigned int dad,
		const void *snd_buf, size_t snd_len,
		void *rcv_buf, size_t rcv_len)
{
	ct_buf_t sbuf, rbuf, tbuf;
	unsigned char sdata[T1_BUFFER_SIZE], sblk[5];
	unsigned int slen, retries, resyncs, sent_length = 0;
	size_t last_send = 0;

	if (snd_len == 0)
		return -1;

	/* we can't talk to a dead card / reader. Reset it! */
	if (t1->state == DEAD)
	{
		DEBUG_CRITICAL("T=1 state machine is DEAD. Reset the card first.");
		return -1;
	}

	t1->state = SENDING;
	retries = t1->retries;
	resyncs = 3;

	/* Initialize send/recv buffer */
	ct_buf_set(&sbuf, (void *)snd_buf, snd_len);
	ct_buf_init(&rbuf, rcv_buf, rcv_len);

	/* Send the first block */
	slen = t1_build(t1, sdata, dad, T1_I_BLOCK, &sbuf, &last_send);

	while (1) {
		unsigned char pcb;
		int n;

		retries--;

		n = t1_xcv(t1, sdata, slen, sizeof(sdata));
		if (-2 == n)
		{
			DEBUG_COMM("Parity error");
			/* ISO 7816-3 Rule 7.4.2 */
			if (retries == 0)
				goto resync;

			/* ISO 7816-3 Rule 7.2 */
			if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
			{
				DEBUG_COMM("Rule 7.2");
				slen = t1_rebuild(t1, sdata);
				continue;
			}

			slen = t1_build(t1, sdata,
					dad, T1_R_BLOCK | T1_EDC_ERROR,
					NULL, NULL);
			continue;
		}

		if (n < 0) {
			DEBUG_CRITICAL("fatal: transmit/receive failed");
			t1->state = DEAD;
			goto error;
		}

		if ((sdata[NAD] != swap_nibbles(dad)) /* wrong NAD */
			|| (sdata[LEN] == 0xFF))	/* length == 0xFF (illegal) */
		{
			DEBUG_COMM("R-BLOCK required");
			/* ISO 7816-3 Rule 7.4.2 */
			if (retries == 0)
				goto resync;

			/* ISO 7816-3 Rule 7.2 */
			if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
			{
				DEBUG_COMM("Rule 7.2");
				slen = t1_rebuild(t1, sdata);
				continue;
			}

			slen = t1_build(t1, sdata,
				dad, T1_R_BLOCK | T1_OTHER_ERROR,
				NULL, NULL);
			continue;
		}

		if (!t1_verify_checksum(t1, sdata, n)) {
			DEBUG_COMM("checksum failed");
			/* ISO 7816-3 Rule 7.4.2 */
			if (retries == 0)
				goto resync;

			/* ISO 7816-3 Rule 7.2 */
			if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
			{
				DEBUG_COMM("Rule 7.2");
				slen = t1_rebuild(t1, sdata);
				continue;
			}

			slen = t1_build(t1, sdata,
				dad, T1_R_BLOCK | T1_EDC_ERROR,
				NULL, NULL);
			continue;
		}

		pcb = sdata[PCB];
		switch (t1_block_type(pcb)) {
		case T1_R_BLOCK:
			if ((sdata[LEN] != 0x00)	/* length != 0x00 (illegal) */
				|| (pcb & 0x20)			/* b6 of pcb is set */
			   )
			{
				DEBUG_COMM("R-Block required");
				/* ISO 7816-3 Rule 7.4.2 */
				if (retries == 0)
					goto resync;

				/* ISO 7816-3 Rule 7.2 */
				if (T1_R_BLOCK == t1_block_type(t1->previous_block[1]))
				{
					DEBUG_COMM("Rule 7.2");
					slen = t1_rebuild(t1, sdata);
					continue;
				}

				slen = t1_build(t1, sdata,
						dad, T1_R_BLOCK | T1_OTHER_ERROR,
						NULL, NULL);
				continue;
			}

			if (((t1_seq(pcb) != t1->ns)	/* wrong sequence number & no bit more */
					&& ! t1->more)
			   )
			{
				DEBUG_COMM4("received: %d, expected: %d, more: %d",
					t1_seq(pcb), t1->ns, t1->more);

				/* ISO 7816-3 Rule 7.2 */
				if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
				{
					DEBUG_COMM("Rule 7.2");
					slen = t1_rebuild(t1, sdata);
					continue;
				}

				DEBUG_COMM("R-Block required");
				/* ISO 7816-3 Rule 7.4.2 */
				if (retries == 0)
					goto resync;
				slen = t1_build(t1, sdata,
						dad, T1_R_BLOCK | T1_OTHER_ERROR,
						NULL, NULL);
				continue;
			}

			if (t1->state == RECEIVING) {
				/* ISO 7816-3 Rule 7.2 */
				if (T1_R_BLOCK == t1_block_type(t1->previous_block[1]))
				{
					DEBUG_COMM("Rule 7.2");
					slen = t1_rebuild(t1, sdata);
					continue;
				}

				DEBUG_COMM("");
				slen = t1_build(t1, sdata,
						dad, T1_R_BLOCK,
						NULL, NULL);
				break;
			}

			/* If the card terminal requests the next
			 * sequence number, it received the previous
			 * block successfully */
			if (t1_seq(pcb) != t1->ns) {
				ct_buf_get(&sbuf, NULL, last_send);
				sent_length += last_send;
				last_send = 0;
				t1->ns ^= 1;
			}

			/* If there's no data available, the ICC
			 * shouldn't be asking for more */
			if (ct_buf_avail(&sbuf) == 0)
				goto resync;

			slen = t1_build(t1, sdata, dad, T1_I_BLOCK,
					&sbuf, &last_send);
			break;

		case T1_I_BLOCK:
			/* The first I-block sent by the ICC indicates
			 * the last block we sent was received successfully. */
			if (t1->state == SENDING) {
				DEBUG_COMM("");
				ct_buf_get(&sbuf, NULL, last_send);
				last_send = 0;
				t1->ns ^= 1;
			}

			t1->state = RECEIVING;

			/* If the block sent by the card doesn't match
			 * what we expected it to send, reply with
			 * an R block */
			if (t1_seq(pcb) != t1->nr) {
				DEBUG_COMM("wrong nr");
				slen = t1_build(t1, sdata, dad,
						T1_R_BLOCK | T1_OTHER_ERROR,
						NULL, NULL);
				continue;
			}

			t1->nr ^= 1;

			if (ct_buf_put(&rbuf, sdata + 3, sdata[LEN]) < 0)
			{
				DEBUG_CRITICAL2("buffer overrun by %d bytes", sdata[LEN] - (rbuf.size - rbuf.tail));
				goto error;
			}

			if ((pcb & T1_MORE_BLOCKS) == 0)
				goto done;

			slen = t1_build(t1, sdata, dad, T1_R_BLOCK, NULL, NULL);
			break;

		case T1_S_BLOCK:
			if (T1_S_IS_RESPONSE(pcb) && t1->state == RESYNCH) {
				/* ISO 7816-3 Rule 6.2 */
				DEBUG_COMM("S-Block answer received");
				/* ISO 7816-3 Rule 6.3 */
				t1->state = SENDING;
				sent_length = 0;
				last_send = 0;
				resyncs = 3;
				retries = t1->retries;
				ct_buf_init(&rbuf, rcv_buf, rcv_len);
				slen = t1_build(t1, sdata, dad, T1_I_BLOCK,
						&sbuf, &last_send);
				continue;
			}

			if (T1_S_IS_RESPONSE(pcb))
			{
				/* ISO 7816-3 Rule 7.4.2 */
				if (retries == 0)
					goto resync;

				/* ISO 7816-3 Rule 7.2 */
				if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
				{
					DEBUG_COMM("Rule 7.2");
					slen = t1_rebuild(t1, sdata);
					continue;
				}

				DEBUG_CRITICAL("wrong response S-BLOCK received");
				slen = t1_build(t1, sdata,
						dad, T1_R_BLOCK | T1_OTHER_ERROR,
						NULL, NULL);
				continue;
			}

			ct_buf_init(&tbuf, sblk, sizeof(sblk));

			DEBUG_COMM("S-Block request received");
			switch (T1_S_TYPE(pcb)) {
			case T1_S_RESYNC:
				if (sdata[LEN] != 0)
				{
					DEBUG_COMM2("Wrong length: %d", sdata[LEN]);
					slen = t1_build(t1, sdata, dad,
						T1_R_BLOCK | T1_OTHER_ERROR,
						NULL, NULL);
					continue;
				}

				DEBUG_COMM("Resync requested");
				/* the card is not allowed to send a resync. */
				goto resync;

			case T1_S_ABORT:
				if (sdata[LEN] != 0)
				{
					DEBUG_COMM2("Wrong length: %d", sdata[LEN]);
					slen = t1_build(t1, sdata, dad,
						T1_R_BLOCK | T1_OTHER_ERROR,
						NULL, NULL);
					continue;
				}

				/* ISO 7816-3 Rule 9 */
				DEBUG_CRITICAL("abort requested");
				break;

			case T1_S_IFS:
				if (sdata[LEN] != 1)
				{
					DEBUG_COMM2("Wrong length: %d", sdata[LEN]);
					slen = t1_build(t1, sdata, dad,
						T1_R_BLOCK | T1_OTHER_ERROR,
						NULL, NULL);
					continue;
				}

				DEBUG_CRITICAL2("CT sent S-block with ifs=%u", sdata[DATA]);
				if (sdata[DATA] == 0)
					goto resync;
				t1->ifsc = sdata[DATA];
				ct_buf_putc(&tbuf, sdata[DATA]);
				break;

			case T1_S_WTX:
				if (sdata[LEN] != 1)
				{
					DEBUG_COMM2("Wrong length: %d", sdata[LEN]);
					slen = t1_build(t1, sdata, dad,
						T1_R_BLOCK | T1_OTHER_ERROR,
						NULL, NULL);
					continue;
				}

				DEBUG_COMM2("CT sent S-block with wtx=%u", sdata[DATA]);
				t1->wtx = sdata[DATA];
				ct_buf_putc(&tbuf, sdata[DATA]);
				break;

			default:
				DEBUG_CRITICAL2("T=1: Unknown S block type 0x%02x", T1_S_TYPE(pcb));
				goto resync;
			}

			slen = t1_build(t1, sdata, dad,
				T1_S_BLOCK | T1_S_RESPONSE | T1_S_TYPE(pcb),
				&tbuf, NULL);
		}

		/* Everything went just splendid */
		retries = t1->retries;
		continue;

resync:
		/* the number or resyncs is limited, too */
		/* ISO 7816-3 Rule 6.4 */
		if (resyncs == 0)
			goto error;

		/* ISO 7816-3 Rule 6 */
		resyncs--;
		t1->ns = 0;
		t1->nr = 0;
		slen = t1_build(t1, sdata, dad, T1_S_BLOCK | T1_S_RESYNC, NULL,
				NULL);
		t1->state = RESYNCH;
		t1->more = FALSE;
		retries = 1;
		continue;
	}

done:
	return ct_buf_avail(&rbuf);

error:
	t1->state = DEAD;
	return -1;
}
Exemplo n.º 9
0
/*
 * Process commands from local clients (i.e. those allowed
 * to claim a device).
 */
static int ria_svc_app_handler(ct_socket_t * sock, header_t * hdr,
                               ct_buf_t * args, ct_buf_t * resp)
{
    unsigned char cmd;
    ria_peer_t *clnt, *peer;
    int rc;

    clnt = (ria_peer_t *) sock->user_data;
    ria_print_packet(sock, 2, "app >>", hdr, args);

    if (ct_buf_get(args, &cmd, 1) < 0)
        return IFD_ERROR_INVALID_MSG;

    switch (cmd) {
    case RIA_MGR_LIST:
        peer = &clients;
        ifd_debug(1, "%s requests a device listing",
                  clnt->device.address);
        while ((peer = peer->next) != &clients) {
            if (peer->device.name[0] != '\0')
                ct_buf_put(resp, &peer->device,
                           sizeof(peer->device));
        }
        return 0;

    case RIA_MGR_INFO:
        peer =
            ria_find_device((const char *)ct_buf_head(args),
                            ct_buf_avail(args));
        if (peer == NULL)
            return IFD_ERROR_UNKNOWN_DEVICE;
        ct_buf_put(resp, &peer->device, sizeof(peer->device));
        return 0;

    case RIA_MGR_CLAIM:
        peer =
            ria_find_device((const char *)ct_buf_head(args),
                            ct_buf_avail(args));
        if (peer == NULL)
            return IFD_ERROR_UNKNOWN_DEVICE;
        if (peer->peer)
            return IFD_ERROR_DEVICE_BUSY;
        ifd_debug(1, "%s claimed %s device %s/%s",
                  clnt->device.address,
                  peer->device.type,
                  peer->device.address, peer->device.name);
        ct_buf_put(resp, &peer->device, sizeof(peer->device));
        clnt->peer = peer;
        peer->peer = clnt;
        return 0;
    }

    if (cmd < __RIA_PEER_CMD_BASE)
        return IFD_ERROR_INVALID_CMD;

    /* All subsequent commands require a device */
    if ((peer = clnt->peer) == NULL)
        return IFD_ERROR_NOT_CONNECTED;

    /* Push back the command byte */
    ct_buf_push(args, &cmd, 1);
    rc = ct_socket_put_packet(peer->sock, hdr, args);

    /* Tell the caller not to send a response */
    hdr->xid = 0;
    return rc;
}