pgparmor.c
来自「著名的加密软件的应用于电子邮件中」· C语言 代码 · 共 1,332 行 · 第 1/3 页
C
1,332 行
* input buffer.
*/
static size_t
armorWriteBytes (struct PgpPipeline *myself, byte const *buf, size_t size,
int *error)
{
struct Context *context = (struct Context *)myself->priv;
size_t size0 = size;
size_t t;
pgpAssert(!context->outlen);
/* Repeat for each line... */
while (size) {
t = min ((size_t)(ARMOR_LINE_INPUT - context->inlen), size);
memcpy (context->input + context->inlen, buf, t);
buf += t;
size -= t;
context->inlen += (byte)t;
/* If we've filled it up, then flush it out */
if (context->inlen == ARMOR_LINE_INPUT) {
*error = armorWriteLine (myself);
if (*error)
return size0-size;
}
}
return size0-size;
}
/*
* Write out as much of the input FIFO as is possible.
*
* If context->version > PGPVERSION_2_6 then we only start writing things
* out if context->armorlines == 0 or when we have a full block worth of
* data (ARMOR_LINE_BYTES * (context->armorlines - context->lineno)).
* Otherwise, we wait until we have it all so we can set the number of
* parts header properly.
*/
static int
armorFlushFifo (struct PgpPipeline *myself, size_t flushlen)
{
struct Context *context = (struct Context *)myself->priv;
byte const *ptr;
unsigned len;
size_t retlen;
int error;
error = armorFlushPending (myself);
if (error)
return error;
ptr = pgpFifoPeek (context->fd, context->fifo, &len);
if (len > flushlen)
len = (unsigned)flushlen;
while (len) {
retlen = armorWriteBytes (myself, ptr, len, &error);
pgpFifoSeek (context->fd, context->fifo, retlen);
flushlen -= retlen;
if (error)
return error;
ptr = pgpFifoPeek (context->fd, context->fifo, &len);
if (len > flushlen)
len = (unsigned)flushlen;
}
return 0;
}
/*
* This is the function that processes a clearsigned message. It uses
* context->state to tell it what it is doing:
* 0) at the beginning -- check it
* 1) middle of line, pass it through
* 2) end of line with \r -- check next character for \n
*/
static size_t
armorDoClearsign (struct PgpPipeline *myself, byte const *buf, size_t size,
int *error)
{
struct Context *context = (struct Context *)myself->priv;
size_t written, size0 = size;
byte const *ptr;
byte const from[] = "From ";
int i, t, flag;
while (size) {
if (context->state == 2) {
context->state = 0;
if (*buf == '\n') {
ptr = buf+1;
goto do_write;
}
}
/*
* Here, we check the beginning of the line for "-" and
* "From ". We use the flag to denote what we've
* found/buffered:
* 0) no match
* 1) full match
* 2) partial match (and we buffered data)
*/
if (!context->state) {
flag = 0;
if (!context->linebuf) {
/* nothing is buffered */
if (*buf == '-')
flag = 1;
}
if (!flag) {
t = min (5, size - context->linebuf);
for (i = 0; i < t; i++)
if (buf[i] != from[context->linebuf+i])
{
pgpFifoWrite (context->fd,
context->header,
context->input,
context->linebuf);
context->linebuf = 0;
break;
}
if (i == t) {
/* We matched the whole input buffer */
if (i + context->linebuf == 5)
flag = 1;
else {
memcpy (context->input +
context->linebuf, buf,
t);
context->linebuf += t;
size -= t;
buf += t;
flag = 2;
}
}
}
if (flag == 1) {
pgpFifoWrite (context->fd, context->header,
(byte const *)"- ", 2);
if (context->linebuf) {
pgpFifoWrite (context->fd,
context->header,
context->input,
context->linebuf);
context->linebuf = 0;
}
}
if (flag != 2)
context->state = 1;
}
*error = armorFlushPending (myself);
if (*error)
return size0 - size;
for (ptr = buf; ptr < buf+size; ptr++) {
if (*ptr == '\r' || *ptr == '\n') {
context->state = (*ptr++ == '\r') ?
2 : 0;
break;
}
}
do_write:
written = context->tail->write (context->tail, buf,
ptr-buf, error);
buf += written;
size -= written;
if (*error)
return size0 - size;
}
return size0 - size;
}
/*
* This function creates a pgp-mime multipart/signed (clearsigned) message.
* It performs the MIME quoted printable canonicalization, except for
* handling end of line characters (=20, etc.).
* context->output is used to build up an output line. MIME quoted printable
* limits its size.
* context->state is used to record its status:
* 2 - just after '\r'
* 1 - just after '\n'
* 0 - otherwise
*/
static size_t
armorDoMimesign (struct PgpPipeline *myself, byte const *buf, size_t size,
int *error)
{
struct Context *context = (struct Context *)myself->priv;
size_t written, size0 = size;
char const *ptr; /* point into buf */
char *ptr2; /* point into context->output */
char c; /* character we are manipulating */
char pushback[2]; /* pushback char array */
unsigned pbsize = 0; /* chars in pushback */
int mimequote; /* true if char needs mime quoting (=XX) */
char const from[] = "From";
ptr = (char *)buf;
ptr2 = context->output + context->outlen;
/* Loop till we have consumed all input */
while (size || pbsize) {
/* Loop per line of output */
while (ptr < (char *)buf + size || pbsize) {
if (pbsize) {
c = pushback[--pbsize];
} else {
c = *ptr++;
}
/* state = 2 means prev line termed with cr */
if (context->state == 2) {
/* eat lf */
if (c == '\n') {
context->state = 1;
continue;
}
}
context->state = 0;
mimequote = 0;
if (c == '\r' || c == '\n') {
if (ptr2 > context->output &&
(ptr2[-1] == ' ' || ptr2[-1] == '\t')) {
/* Fixup space at end of line */
--ptr2;
pushback[pbsize++] = c;
c = ptr2[0];
mimequote = 1;
} else {
context->state = (c == '\r') ? 2 : 1;
break;
}
} else if ((c!='\t' && c<32) || c == '=' || c > 126) {
mimequote = 1;
} else if (ptr2 - context->output >= MIMEMAX) {
/* need soft break */
pushback[pbsize++] = c;
pushback[pbsize++] = ptr2[-1];
ptr2[-1] = '=';
context->state = 1; /* force newline */
break;
} else if (c == ' ' &&
ptr2 - context->output == sizeof(from)-1 &&
strncmp((char *)context->output, from,
sizeof(from) - 1) == 0) {
mimequote = 1;
} else {
*ptr2++ = c;
}
if (mimequote) {
mimequote = 0;
if (ptr2 - context->output > MIMEMAX - 3) {
/* Need soft break */
pushback[pbsize++] = c;
if (ptr2 - context->output >=
MIMEMAX) {
/* Need another pushback */
pgpAssert(pbsize <
sizeof(pushback));
pushback[pbsize++] = ptr2[-1];
ptr2[-1] = '=';
} else {
*ptr2++ = '=';
}
context->state = 1; /* force newline */
break;
} else {
*ptr2++ = '=';
*ptr2++ = "0123456789ABCDEF"[c>>4];
*ptr2++ = "0123456789ABCDEF"[c&0xf];
}
}
}
if (context->state) {
/* Output line now */
*error = armorFlushPending (myself);
if (*error)
return size0 - size;
*ptr2++ = '\n';
*ptr2 = '\0';
written = 0;
context->outptr = context->output;
while (written < (size_t)(ptr2 - context->outptr)) {
written += context->tail->write (context->tail,
(byte *)context->outptr,
ptr2-context->outptr, error);
context->outptr += written;
if (*error)
return ptr - (char *)buf;
}
}
size -= ptr - (char *)buf;
buf = (byte *)ptr;
ptr2 = context->output;
}
context->outlen = ptr2 - context->output;
return size0 - size;
}
/*
*
* Do we have to buffer? There are three cases:
* - If maxparts is known (non-zero), we can exit immediately.
* - Otherwise, if version > PGPVERSION_2_6, we can write as soon
* as we have *more* than one part's data, since we can postpone
* figuring out maxparts once we know it's more than the current
* part.
* - Otherwise, we need to wait until maxlines is known
*/
static size_t
armorMustBuffer (struct Context *context)
{
unsigned long needed;
if (context->maxparts) /* armorlines = 0 -> no buffering */
return 0;
pgpAssert(context->armorlines);
if (context->version <= PGPVERSION_2_6)
return 1; /* Must buffer */
needed = context->armorlines * ARMOR_LINE_INPUT;
return pgpFifoSize (context->fd, context->fifo) > needed;
}
static size_t
Write (struct PgpPipeline *myself, byte const *buf, size_t size, int *error)
{
struct Context *context;
pgpAssert (myself);
pgpAssert (myself->magic == ARMORMAGIC);
pgpAssert (error);
context = (struct Context *)myself->priv;
pgpAssert (context);
pgpAssert (context->tail);
pgpAssert (!context->at_eof); /* No writes after sizeAdvise(0)! */
*error = armorFlushPending (myself);
if (*error)
return 0;
/* XXX Should just change function pointers. */
if (context->clearsign) {
if (context->pgpmime)
return armorDoMimesign (myself, buf, size, error);
else
return armorDoClearsign (myself, buf, size, error);
}
/* Can we write it straight through? */
if (context->maxparts && !pgpFifoSize (context->fd, context->fifo))
return armorWriteBytes (myself, buf, size, error);
/* Nope, have to buffer it... */
size = pgpFifoWrite (context->fd, context->fifo, buf, size);
if (context->maxparts) {
*error = armorFlushFifo (myself, (size_t)-1);
return size;
}
/*
* Can we write out any of the buffered data? The new format
* (Omitting the "/05" of "PART 01/05" on all but the last part)
* allows us to if we have enough to be sure that this isn't
* the last part.
*/
if (context->version > PGPVERSION_2_6) {
unsigned long needed;
for (;;) {
needed = context->armorlines - context->lineno;
if (!needed)
needed = context->armorlines;
needed *= ARMOR_LINE_INPUT;
if (pgpFifoSize (context->fd, context->fifo) <= needed)
break;
pgpFifoSize (context->fd, context->fifo);
*error = armorFlushFifo (myself, needed);
if (*error)
break;
}
}
return size;
}
/*
* We mostly ingore annotations, since they can't be passed through
* interleaved with our own.
*/
static int
Annotate (struct PgpPipeline *myself, struct PgpPipeline *origin, int type,
byte const *string, size_t size)
{
struct Context *context;
int error = 0;
pgpAssert (myself);
pgpAssert (myself->magic == ARMORMAGIC);
context = (struct Context *)myself->priv;
pgpAssert (context);
#if 0
/* Suppress - this could confuse our downstream neighbours */
error = context->tail->annotate (context->tail, origin, type,
string, size);
if (!error)
#else
(void)origin;
(void)string;
(void)size;
#endif
PGP_SCOPE_DEPTH_UPDATE(context->scope_depth, type);
pgpAssert(context->scope_depth != -1);
return error;
}
/*
* We could in theory generate downstream SizeAdvises,
* but it's not worth the bother until somone wants the hint.
*/
static int
SizeAdvise (struct PgpPipeline *myself, unsigned long bytes)
{
struct Context *context;
int error = 0;
unsigned long total;
pgpAssert (myself);
pgpAssert (myself->magic == ARMORMAGIC);
context = (struct Context *)myself->priv;
pgpAssert (context);
pgpAssert (context->tail);
/* Ignore inner-scope SizeAdvise */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?