I believe I have run across a bug in the experimental Domainkey (dk.c) &
DKIM (dkim-exim.c) support in Exim. This bug only effects Big Endian (
http://en.wikipedia.org/wiki/Endianness ) machines (in my case Sun Sparc).
The code between the two is very similar, hence the same bug. In the
dk_receive_getc ( / dkim_receive_getc), it wants to get a character from
Exim and pass it to the respective dk/dkim routine...
int dkbuff[6] = {256,256,256,256,256,256};
/* receive_getc() wrapper that feeds DK while Exim reads
the message. */
int dk_receive_getc(void) {
int i;
int c = receive_getc();
if (dk_context != NULL) {
/* Send oldest byte */
if ((dkbuff[0] < 256) && (dk_internal_status == DK_STAT_OK)) {
dk_internal_status = dk_message(dk_context, CUS &dkbuff[0], 1);
.
.
.
/* Send remaining bytes from input which are still in the buffer. */
for (i=0;i<6;i++)
if (dkbuff[i] < 256)
dk_internal_status = dk_message(dk_context, CUS &dkbuff[i], 1);
the problem is the definition of dkbuff - i.e. int. On Big Endian
machines, &dkbuff[something] returns the address of the most significant
byte!!, always 0.
I have two potential "fixes":
1) Put the int into a real char, and pass the address of the char...
int dkbuff[6] = {256,256,256,256,256,256};
/* receive_getc() wrapper that feeds DK while Exim reads
the message. */
int dk_receive_getc(void) {
int i;
int c = receive_getc();
if (dk_context != NULL) {
/* Send oldest byte */
if ((dkbuff[0] < 256) && (dk_internal_status == DK_STAT_OK)) {
unsigned char s = dkbuff[0];
dk_internal_status = dk_message(dk_context, CUS &s, 1);
.
.
.
/* Send remaining bytes from input which are still in the buffer. */
for (i=0;i<6;i++)
if (dkbuff[i] < 256) {
unsigned char s = dkbuff[i];
dk_internal_status = dk_message(dk_context, CUS &s, 1);
}
2) Fix-up the address being sent...
#ifdef _BIG_ENDIAN
#define ENDIAN_OFFSET sizeof( int ) - 1
#else
#define ENDIAN_OFFSET 0
#endif
.
.
.
int dkbuff[6] = {256,256,256,256,256,256};
/* receive_getc() wrapper that feeds DK while Exim reads
the message. */
int dk_receive_getc(void) {
int i;
int c = receive_getc();
if (dk_context != NULL) {
/* Send oldest byte */
if ((dkbuff[0] < 256) && (dk_internal_status == DK_STAT_OK)) {
dk_internal_status = dk_message(dk_context, CUS &dkbuff[0] +
ENDIAN_OFFSET, 1);
.
.
.
/* Send remaining bytes from input which are still in the buffer. */
for (i=0;i<6;i++)
if (dkbuff[i] < 256)
dk_internal_status = dk_message(dk_context, CUS &dkbuff[i] +
ENDIAN_OFFSET, 1);
I think I like #1 better, but I'm not sure.
I was hoping that the maintainer's of this code might have some additional
insight and could possibly point me at other places where endian'ness
might be an issue.
Thanks,
Dan