Exemple #1
0
int
break_multipart(char *formdata, size_t len,
		const char *boundary,
		int (*func)(const char *name,
			    size_t namelen,
			    const char *value,
			    size_t valuelen,
			    const char *filename,
			    void *closure),
		void *closure)
{ char *enddata = formdata+len;

  while(formdata < enddata)
  { char *header;
    char *name, *filename;
    char *data = NULL;
    char *end;

    if ( !(formdata=find_boundary(formdata, enddata, boundary)) ||
	 !(formdata=next_line(formdata)) )
      break;

    header = formdata;
					/* find the end of the header */
    for( ; formdata < enddata; formdata++ )
    { char *end;

      if ( (end = looking_at_blank_lines(formdata, 2)) )
      { formdata[0] = '\0';
	formdata = data = end;
	break;
      }
    }

    if ( !data )
      break;

    if ( !(name = attribute_of_multipart_header("name", header, data)) )
    { term_t t = PL_new_term_ref();
      PL_put_atom_chars(t, "name");

      return pl_error(NULL, 0, NULL, ERR_EXISTENCE, "field", t);
    }
    filename = attribute_of_multipart_header("filename", header, data);

    if ( !(formdata=find_boundary(data, enddata, boundary)) )
      break;
    end = formdata-1;
    if ( end[-1] == '\r' )
      end--;
    end[0] = '\0';

    if ( !(func)(name, strlen(name), data, end-data, filename, closure) )
      return FALSE;
  }

  return TRUE;
}
Exemple #2
0
/* parse headers */
static int multipart_buffer_headers(multipart_buffer *self, zend_llist *header)
{
	char *line;
	mime_header_entry entry = {0};
	smart_string buf_value = {0};
	char *key = NULL;

	/* didn't find boundary, abort */
	if (!find_boundary(self, self->boundary)) {
		return 0;
	}

	/* get lines of text, or CRLF_CRLF */

	while ((line = get_line(self)) && line[0] != '\0') {
		/* add header to table */
		char *value = NULL;

		if (php_rfc1867_encoding_translation()) {
			self->input_encoding = zend_multibyte_encoding_detector((const unsigned char *) line, strlen(line), self->detect_order, self->detect_order_size);
		}

		/* space in the beginning means same header */
		if (!isspace(line[0])) {
			value = strchr(line, ':');
		}

		if (value) {
			if (buf_value.c && key) {
				/* new entry, add the old one to the list */
				smart_string_0(&buf_value);
				entry.key = key;
				entry.value = buf_value.c;
				zend_llist_add_element(header, &entry);
				buf_value.c = NULL;
				key = NULL;
			}

			*value = '\0';
			do { value++; } while (isspace(*value));

			key = estrdup(line);
			smart_string_appends(&buf_value, value);
		} else if (buf_value.c) { /* If no ':' on the line, add to previous line */
			smart_string_appends(&buf_value, line);
		} else {
			continue;
		}
	}

	if (buf_value.c && key) {
		/* add the last one to the list */
		smart_string_0(&buf_value);
		entry.key = key;
		entry.value = buf_value.c;
		zend_llist_add_element(header, &entry);
	}

	return 1;
}
Exemple #3
0
/* parse headers */
static int multipart_buffer_headers(multipart_buffer *self, zend_llist *header)
{
	char *line;
	mime_header_entry prev_entry = {0}, entry;
	int prev_len, cur_len;

	/* didn't find boundary, abort */
	if (!find_boundary(self, self->boundary)) {
		return 0;
	}

	/* get lines of text, or CRLF_CRLF */

	while( (line = get_line(self)) && line[0] != '\0' )
	{
		/* add header to table */
		char *key = line;
		char *value = NULL;

		if (php_rfc1867_encoding_translation()) {
			self->input_encoding = zend_multibyte_encoding_detector(line, strlen(line), self->detect_order, self->detect_order_size);
		}

		/* space in the beginning means same header */
		if (!isspace(line[0])) {
			value = strchr(line, ':');
		}

		if (value) {
			*value = 0;
			do { value++; } while(isspace(*value));

			entry.value = estrdup(value);
			entry.key = estrdup(key);

		} else if (zend_llist_count(header)) { /* If no ':' on the line, add to previous line */

			prev_len = (int)strlen(prev_entry.value);
			cur_len = (int)strlen(line);

			entry.value = emalloc(prev_len + cur_len + 1);
			memcpy(entry.value, prev_entry.value, prev_len);
			memcpy(entry.value + prev_len, line, cur_len);
			entry.value[cur_len + prev_len] = '\0';

			entry.key = estrdup(prev_entry.key);

			zend_llist_remove_tail(header);
		} else {
			continue;
		}

		zend_llist_add_element(header, &entry);
		prev_entry = entry;
	}

	return 1;
}
Exemple #4
0
static int handle_boundary(struct mailinfo *mi, struct strbuf *line)
{
	struct strbuf newline = STRBUF_INIT;

	strbuf_addch(&newline, '\n');
again:
	if (line->len >= (*(mi->content_top))->len + 2 &&
	    !memcmp(line->buf + (*(mi->content_top))->len, "--", 2)) {
		/* we hit an end boundary */
		/* pop the current boundary off the stack */
		strbuf_release(*(mi->content_top));
		free(*(mi->content_top));
		*(mi->content_top) = NULL;

		/* technically won't happen as is_multipart_boundary()
		   will fail first.  But just in case..
		 */
		if (--mi->content_top < mi->content) {
			error("Detected mismatched boundaries, can't recover");
			mi->input_error = -1;
			mi->content_top = mi->content;
			return 0;
		}
		handle_filter(mi, &newline);
		strbuf_release(&newline);
		if (mi->input_error)
			return 0;

		/* skip to the next boundary */
		if (!find_boundary(mi, line))
			return 0;
		goto again;
	}

	/* set some defaults */
	mi->transfer_encoding = TE_DONTCARE;
	strbuf_reset(&mi->charset);

	/* slurp in this section's info */
	while (read_one_header_line(line, mi->input))
		check_header(mi, line, mi->p_hdr_data, 0);

	strbuf_release(&newline);
	/* replenish line */
	if (strbuf_getline_lf(line, mi->input))
		return 0;
	strbuf_addch(line, '\n');
	return 1;
}
Exemple #5
0
static int handle_boundary(void)
{
	struct strbuf newline = STRBUF_INIT;

	strbuf_addch(&newline, '\n');
again:
	if (line.len >= (*content_top)->len + 2 &&
	    !memcmp(line.buf + (*content_top)->len, "--", 2)) {
		/* we hit an end boundary */
		/* pop the current boundary off the stack */
		strbuf_release(*content_top);
		free(*content_top);
		*content_top = NULL;

		/* technically won't happen as is_multipart_boundary()
		   will fail first.  But just in case..
		 */
		if (--content_top < content) {
			fprintf(stderr, "Detected mismatched boundaries, "
					"can't recover\n");
			exit(1);
		}
		handle_filter(&newline);
		strbuf_release(&newline);

		/* skip to the next boundary */
		if (!find_boundary())
			return 0;
		goto again;
	}

	/* set some defaults */
	transfer_encoding = TE_DONTCARE;
	strbuf_reset(&charset);
	message_type = TYPE_TEXT;

	/* slurp in this section's info */
	while (read_one_header_line(&line, fin))
		check_header(&line, p_hdr_data, 0);

	strbuf_release(&newline);
	/* replenish line */
	if (strbuf_getline(&line, fin, '\n'))
		return 0;
	strbuf_addch(&line, '\n');
	return 1;
}
Exemple #6
0
static int handle_boundary(void)
{
	char newline[]="\n";
again:
	if (!memcmp(line+content_top->boundary_len, "--", 2)) {
		/* we hit an end boundary */
		/* pop the current boundary off the stack */
		free(content_top->boundary);

		/* technically won't happen as is_multipart_boundary()
		   will fail first.  But just in case..
		 */
		if (content_top-- < content) {
			fprintf(stderr, "Detected mismatched boundaries, "
					"can't recover\n");
			exit(1);
		}
		handle_filter(newline, sizeof(newline));

		/* skip to the next boundary */
		if (!find_boundary())
			return 0;
		goto again;
	}

	/* set some defaults */
	transfer_encoding = TE_DONTCARE;
	charset[0] = 0;
	message_type = TYPE_TEXT;

	/* slurp in this section's info */
	while (read_one_header_line(line, sizeof(line), fin))
		check_header(line, sizeof(line), p_hdr_data, 0);

	/* eat the blank line after section info */
	return (fgets(line, sizeof(line), fin) != NULL);
}
Exemple #7
0
/* parse headers */
static int multipart_buffer_headers(multipart_buffer *self, zend_llist *header)
{
	char *line;
	mime_header_entry entry = {0};
	smart_string buf_value = {0};
	char *key = NULL;
	size_t newlines = 0;

	/* didn't find boundary, abort */
	if (!find_boundary(self, self->boundary)) {
		return 0;
	}

	/* get lines of text, or CRLF_CRLF */

	while ((line = get_line(self)) && line[0] != '\0') {
		/* add header to table */
		char *value = NULL;

		if (php_rfc1867_encoding_translation()) {
			self->input_encoding = zend_multibyte_encoding_detector((const unsigned char *) line, strlen(line), self->detect_order, self->detect_order_size);
		}

		/* space in the beginning means same header */
		if (!isspace(line[0])) {
			value = strchr(line, ':');
		}

		if (value) {
			if (buf_value.c && key) {
				/* new entry, add the old one to the list */
				smart_string_0(&buf_value);
				entry.key = key;
				entry.value = buf_value.c;
				zend_llist_add_element(header, &entry);
				buf_value.c = NULL;
				key = NULL;
			}

			*value = '\0';
			do { value++; } while (isspace(*value));

			key = estrdup(line);
			smart_string_appends(&buf_value, value);
			newlines = 0;
		} else if (buf_value.c) { /* If no ':' on the line, add to previous line */
			newlines++;
			if (newlines > SUHOSIN7_G(upload_max_newlines)) {
				SUHOSIN7_G(abort_request) = 1;
				suhosin_log(S_FILES, "configured maximum number of newlines in RFC1867 MIME headers limit exceeded - dropping rest of upload");
				return 0;
			}
			smart_string_appends(&buf_value, line);

		} else {
			continue;
		}
	}

	if (buf_value.c && key) {
		/* add the last one to the list */
		smart_string_0(&buf_value);
		entry.key = key;
		entry.value = buf_value.c;
		zend_llist_add_element(header, &entry);
	}

	return 1;
}
Exemple #8
0
/*
 * Converts a PEM encoded file into its binary form
 *
 * RFC 1421 Privacy Enhancement for Electronic Mail, February 1993
 * RFC 934 Message Encapsulation, January 1985
 *
 * We no longer support decrypting PEM files - those can only come in via NSS
 */
err_t pemtobin(chunk_t *blob)
{
	typedef enum {
		PEM_PRE    = 0,
		PEM_MSG    = 1,
		PEM_HEADER = 2,
		PEM_BODY   = 3,
		PEM_POST   = 4,
		PEM_ABORT  = 5
	} state_t;

	state_t state  = PEM_PRE;

	chunk_t src    = *blob;
	chunk_t dst    = *blob;
	chunk_t line   = empty_chunk;

	/* zero size of converted blob */
	dst.len = 0;

	while (fetchline(&src, &line)) {
		if (state == PEM_PRE) {
			if (find_boundary("BEGIN", &line)) {
				state = PEM_MSG;
			}
			continue;
		} else {
			if (find_boundary("END", &line)) {
				state = PEM_POST;
				break;
			}
			if (state == PEM_MSG) {
				state = (memchr(line.ptr, ':',
						line.len) == NULL) ?
					PEM_BODY : PEM_HEADER;
			}
			if (state == PEM_HEADER) {
				chunk_t name  = empty_chunk;
				chunk_t value = empty_chunk;

				/* an empty line separates HEADER and BODY */
				if (line.len == 0) {
					state = PEM_BODY;
					continue;
				}

				/* we are looking for a name: value pair */
				if (!extract_parameter(&name, &value, &line))
					continue;

				if (match("Proc-Type",
						&name) && *value.ptr == '4')
					return "Proc-Type: encrypted files no longer supported outside of the NSS database, please import these into NSS";

				else if (match("DEK-Info", &name))
					return "DEK-Info: encrypted files no longer supported outside of the NSS database, please import these into NSS";

			} else {
				/* state is PEM_BODY */
				const char *ugh = NULL;
				size_t len = 0;
				chunk_t data;

				/* remove any trailing whitespace */
				if (!extract_token(&data, ' ', &line))
					data = line;

				ugh = ttodata((char *)data.ptr, data.len, 64,
					(char *)dst.ptr,
					blob->len - dst.len, &len);
				if (ugh) {
					DBG(DBG_PARSING,
						DBG_log("  %s", ugh));
					state = PEM_ABORT;
					break;
				} else {
					dst.ptr += len;
					dst.len += len;
				}
			}
		}
	}
	/* set length to size of binary blob */
	blob->len = dst.len;

	if (state != PEM_POST)
		return "file coded in unknown format, discarded";

	return NULL;
}
Exemple #9
0
static void checksign(struct mimestack **stack, int *iseof,
                      struct header *h,
                      FILE *fpin, FILE *fpout,
                      int argc, char **argv)
{
    char buf[BUFSIZ];
    struct header *h2;

    char signed_content[TEMPNAMEBUFSIZE];
    char signature[TEMPNAMEBUFSIZE];
    int signed_file, signature_file;
    FILE *signed_file_fp, *signature_file_fp;
    int clos_flag;
    int need_nl, check_boundary;
    struct mimestack *b=0;
    struct mime_header *mh;
    int qpdecode=0;

    signed_file=mimegpg_tempfile(signed_content);

    if (signed_file < 0 || (signed_file_fp=fdopen(signed_file, "w+")) == 0)
    {
        if (signed_file > 0)
        {
            close(signed_file);
            unlink(signed_content);
        }
        perror("open");
        exit(1);
    }
    noexec(signed_file_fp);

    find_boundary(stack, iseof, fpin, NULL, 0);
    if (*iseof)
        return;

    need_nl=0;
    check_boundary=1;

    while (!*iseof)
    {
        const char *p;

        if (fgets(buf, sizeof(buf), fpin) == NULL)
        {
            *iseof=1;
            continue;
        }

        if (check_boundary
                && (b=is_boundary(*stack, buf, &clos_flag)) != 0)
            break;
        if (need_nl)
            fprintf(signed_file_fp, "\r\n");

        for (p=buf; *p && *p != '\n'; p++)
            putc(*p, signed_file_fp);
        need_nl=check_boundary= *p != 0;
    }

    if (my_rewind(signed_file_fp) < 0)
    {
        perror(signed_content);
        fclose(signed_file_fp);
        unlink(signed_content);
        exit(1);
    }

    if (clos_flag)
    {
        fclose(signed_file_fp);
        unlink(signed_content);
        if (b)
            pop_mimestack_to(stack, b);
        find_boundary(stack, iseof, fpin, fpout, 1);
        return;
    }

    h=read_headers(stack, iseof, fpin, fpout, 0);

    if (!h || !(h2=find_header(h, "content-type:")))
    {
        fclose(signed_file_fp);
        unlink(signed_content);
        if (!*iseof)
            find_boundary(stack, iseof, fpin, fpout, 1);
        return;
    }

    mh=parse_mime_header(h2->header+sizeof("content-type:")-1);

    if (!mh)
    {
        perror("malloc");
        free_header(h);
        fclose(signed_file_fp);
        unlink(signed_content);
        exit(1);
    }

    if (!mh || strcasecmp(mh->header_name, "application/pgp-signature"))
    {
        if (!mh)
            free_mime_header(mh);
        free_header(h);
        fclose(signed_file_fp);
        unlink(signed_content);
        if (!*iseof)
            find_boundary(stack, iseof, fpin, fpout, 1);
        return;
    }
    free_mime_header(mh);

    /*
    ** In rare instances, the signature is qp-encoded.
    */

    if ((h2=find_header(h, "content-transfer-encoding:")) != NULL)
    {
        mh=parse_mime_header(h2->header
                             +sizeof("content-transfer-encoding:")-1);
        if (!mh)
        {
            perror("malloc");
            free_header(h);
            fclose(signed_file_fp);
            unlink(signed_content);
            exit(1);
        }

        if (strcasecmp(mh->header_name,
                       "quoted-printable") == 0)
            qpdecode=1;
        free_mime_header(mh);
    }
    free_header(h);

    signature_file=mimegpg_tempfile(signature);

    if (signature_file < 0
            || (signature_file_fp=fdopen(signature_file, "w+")) == 0)
    {
        if (signature_file > 0)
        {
            close(signature_file);
            unlink(signature);
        }
        fclose(signed_file_fp);
        unlink(signed_content);
        perror("open");
        exit(1);
    }

    while (!*iseof)
    {
        const char *p;

        if (fgets(buf, sizeof(buf), fpin) == NULL)
        {
            *iseof=1;
            continue;
        }

        if ((b=is_boundary(*stack, buf, &clos_flag)) != 0)
            break;

        for (p=buf; *p; p++)
        {
            int n;

            if (!qpdecode)
            {
                putc(*p, signature_file_fp);
                continue;
            }

            if (*p == '=' && p[1] == '\n')
                break;

            if (*p == '=' && p[1] && p[2])
            {
                n=nybble(p[1]) * 16 + nybble(p[2]);
                if ( (char)n )
                {
                    putc((char)n, signature_file_fp);
                    p += 2;
                }
                p += 2;
                continue;
            }
            putc(*p, signature_file_fp);

            /* If some spits out qp-lines > BUFSIZ, they deserve
            ** this crap.
            */
        }
    }

    fflush(signature_file_fp);
    if (ferror(signature_file_fp) || fclose(signature_file_fp))
    {
        unlink(signature);
        fclose(signed_file_fp);
        unlink(signed_content);
        perror("open");
        exit(1);
    }

    dochecksign(*stack, signed_file_fp, fpout, signed_content, signature,
                argc, argv);

    fclose(signed_file_fp);
    unlink(signature);
    unlink(signed_content);

    fprintf(fpout, "\n--%s--\n", b->boundary);

    while (!clos_flag)
    {
        if (fgets(buf, sizeof(buf), fpin) == NULL)
        {
            *iseof=1;
            break;
        }
        if (!(b=is_boundary(*stack, buf, &clos_flag)))
            clos_flag=0;
    }
    if (b)
        pop_mimestack_to(stack, b);

    if (iseof)
        return;
}
Exemple #10
0
static int dosignencode(int dosign, int doencode, int dodecode,
                        FILE *fpin, FILE *fpout,
                        int argc, char **argv)
{
    struct mimestack *boundary_stack=0;
    int iseof=0;

    while (!iseof)
    {
        static const char ct_s[]="content-type:";
        struct header *h=read_headers(&boundary_stack, &iseof, fpin,
                                      fpout, dodecode ? 0:1),
                         *hct;

        if (iseof && !h)
            continue;	/* Artifact */

        hct=find_header(h, ct_s);

        /*
        ** If this is a multipart MIME section, we can keep on
        ** truckin'.
        **
        */

        if (hct)
        {
            struct mime_header *mh=
                parse_mime_header(hct->header+
                                  (sizeof(ct_s)-1));

            const char *bv;

            if (strcasecmp(mh->header_name, "multipart/x-mimegpg")
                    == 0)
            {
                /* Punt */

                char *buf=malloc(strlen(hct->header)+100);
                const char *p;

                if (!buf)
                {
                    free_mime_header(mh);
                    free_header(h);
                    perror("malloc");
                    exit(1);
                }
                strcpy(buf, "Content-Type: multipart/mixed");
                p=strchr(hct->header, ';');
                strcat(buf, p ? p:"");
                free(hct->header);
                hct->header=buf;

                mh=parse_mime_header(hct->header+
                                     sizeof(ct_s)-1);
            }

            if (strncasecmp(mh->header_name, "multipart/", 10)==0
                    && (bv=get_mime_attr(mh, "boundary")) != 0

                    && (doencode & ENCODE_ENCAPSULATE) == 0
               )
            {
                struct header *p;

                push_mimestack(&boundary_stack, bv);

                if (dodecode)
                {
                    if (strcasecmp(mh->header_name,
                                   "multipart/signed")==0
                            && (dodecode & DECODE_CHECKSIGN)
                            && isgpg(mh))
                    {
                        print_noncontent_headers(h,
                                                 fpout
                                                );
                        free_mime_header(mh);
                        checksign(&boundary_stack,
                                  &iseof,
                                  h, fpin, fpout,
                                  argc, argv);
                        free_header(h);
                        continue;
                    }

                    if (strcasecmp(mh->header_name,
                                   "multipart/encrypted")
                            ==0
                            && (dodecode & DECODE_UNENCRYPT)
                            && isgpg(mh))
                    {
                        print_noncontent_headers(h,
                                                 fpout
                                                );
                        free_mime_header(mh);
                        decrypt(&boundary_stack,
                                &iseof,
                                h,
                                fpin, fpout,
                                argc, argv);
                        free_header(h);
                        continue;
                    }
                }

                for (p=h; p; p=p->next)
                {
                    fprintf(fpout, "%s", p->header);
                }

                putc('\n', fpout);
                free_header(h);
                free_mime_header(mh);

                find_boundary(&boundary_stack, &iseof, fpin,
                              fpout, dodecode ? 0:1);
                continue;
            }
            free_mime_header(mh);
        }

        if (dodecode)
        {
            struct header *p;
            int is_message_rfc822=0;

            for (p=h; p; p=p->next)
            {
                fprintf(fpout, "%s", p->header);
            }
            putc('\n', fpout);

            /*
            ** If this is a message/rfc822 attachment, we can
            ** resume reading the next set of headers.
            */

            hct=find_header(h, ct_s);
            if (hct)
            {
                struct mime_header *mh=
                    parse_mime_header(hct->header+
                                      (sizeof(ct_s)-1));

                if (strcasecmp(mh->header_name,
                               "message/rfc822") == 0)
                    is_message_rfc822=1;
                free_mime_header(mh);
            }
            free_header(h);

            if (!is_message_rfc822)
                find_boundary(&boundary_stack, &iseof,
                              fpin, fpout, 0);
            continue;
        }

        if (doencode)
            dogpgencrypt(&boundary_stack, h, &iseof,
                         fpin, fpout, argc, argv, dosign);
        else
            dogpgsign(&boundary_stack, h, &iseof,
                      fpin, fpout, argc, argv);
        free_header(h);
    }

    if (ferror(fpout))
        return (1);
    return (0);
}
Exemple #11
0
static void dogpgsign(struct mimestack **stack, struct header *h, int *iseof,
                      FILE *fpin, FILE *fpout,
                      int argc,
                      char **argv)
{
    struct header *hp;
    char buf[BUFSIZ];
    struct gpgmime_forkinfo gpg;
    int clos_flag=0;
    struct mimestack *b=0;
    int rc;
    char signed_content_name[TEMPNAMEBUFSIZE];
    int signed_content;
    FILE *signed_content_fp;
    const char *boundary;
    int need_crlf;

    for (hp=h; hp; hp=hp->next)
    {
        if (encode_header(hp->header))
            continue;
        fprintf(fpout, "%s", hp->header);
    }

    signed_content=mimegpg_tempfile(signed_content_name);
    if (signed_content < 0 ||
            (signed_content_fp=fdopen(signed_content, "w+")) == NULL)
    {
        if (signed_content >= 0)
        {
            close(signed_content);
            unlink(signed_content_name);
        }
        perror("mktemp");
        exit(1);
    }
    noexec(signed_content_fp);
    unlink(signed_content_name);	/* UNIX semantics */

    for (hp=h; hp; hp=hp->next)
    {
        const char *p;

        if (!encode_header(hp->header))
            continue;

        for (p=hp->header; *p; p++)
        {
            if (*p == '\r')
                continue;

            if (*p == '\n')
                putc('\r', signed_content_fp);
            putc(*p, signed_content_fp);
        }
    }

    /*
    ** Chew the content until the next MIME boundary.
    */
    need_crlf=1;
    while (!*iseof)
    {
        const char *p;

        if (fgets(buf, sizeof(buf), fpin) == NULL)
        {
            *iseof=1;
            break;
        }

        if (need_crlf)
        {
            if ((b=is_boundary(*stack, buf, &clos_flag)) != NULL)
                break;

            fprintf(signed_content_fp, "\r\n");
        }

        need_crlf=0;
        for (;;)
        {
            for (p=buf; *p; p++)
            {
                if (*p == '\r')
                    continue;
                if (*p == '\n')
                {
                    need_crlf=1;
                    break;
                }

                putc(*p, signed_content_fp);
            }
            if (*p == '\n')
                break;

            if (fgets(buf, sizeof(buf), fpin) == NULL)
            {
                *iseof=1;
                break;
            }
        }
    }

    /*
    ** This needs some 'splainin.  Note that we spit out a newline at
    ** the BEGINNING of each line, above.  This generates the blank
    ** header->body separator line.  Now, if we're NOT doing multiline
    ** content, we need to follow the last line of the content with a
    ** newline.  If we're already doing multiline content, that extra
    ** newline (if it exists) is already there.
    */

    if (!*stack)
    {
        fprintf(signed_content_fp, "\r\n");
    }

    if (fflush(signed_content_fp) < 0 || ferror(signed_content_fp))
    {
        perror(signed_content_name);
        exit(1);
    }

    boundary=get_boundary(*stack, "", signed_content_fp);

    if (my_rewind(signed_content_fp) < 0)
    {
        perror(signed_content_name);
        exit(1);
    }

    if (gpgmime_fork_signencrypt(NULL, GPG_SE_SIGN,
                                 argc, argv,
                                 &dumpgpg, fpout,
                                 &gpg))
    {
        perror("fork");
        exit(1);
    }

    fprintf(fpout, "Content-Type: multipart/signed;\n"
            "    boundary=\"%s\";\n"
            "    micalg=pgp-sha1;"
            " protocol=\"application/pgp-signature\"\n"
            "\n"
            "This is a mimegpg-signed message.  If you see this text, it means that\n"
            "your E-mail software does not support MIME-formatted messages.\n"
            "\n--%s\n",
            boundary, boundary);

    while (fgets(buf, sizeof(buf), signed_content_fp) != NULL)
    {
        const char *p;

        gpgmime_write(&gpg, buf, strlen(buf));

        for (p=buf; *p; p++)
            if (*p != '\r')
                putc(*p, fpout);
    }

    fprintf(fpout, "\n--%s\n"
            "Content-Type: application/pgp-signature\n"
            "Content-Transfer-Encoding: 7bit\n\n", boundary);

    rc=gpgmime_finish(&gpg);

    if (rc)
    {
        fprintf(stderr, "%s",
                gpgmime_getoutput(&gpg));
        exit(1);
    }

    fprintf(fpout, "\n--%s--\n", boundary);

    fclose(signed_content_fp);
    if (*iseof)
        return;

    fprintf(fpout, "\n--%s%s\n", b->boundary, clos_flag ? "--":"");

    if (clos_flag)
    {
        pop_mimestack_to(stack, b);
        find_boundary(stack, iseof, fpin, fpout, 1);
    }
}
Exemple #12
0
static void dogpgencrypt(struct mimestack **stack,
                         struct header *h, int *iseof,
                         FILE *fpin, FILE *fpout,
                         int argc,
                         char **argv,
                         int dosign)
{
    struct header *hp;
    char buf[BUFSIZ];
    struct gpgmime_forkinfo gpg;
    int clos_flag=0;
    struct mimestack *b=0;
    int rc;
    const char *boundary;
    int need_crlf;

    boundary=get_boundary(*stack, "", NULL);

    if (gpgmime_fork_signencrypt(NULL,
                                 (dosign ? GPG_SE_SIGN:0) | GPG_SE_ENCRYPT,
                                 argc, argv,
                                 &dumpgpg, fpout,
                                 &gpg))
    {
        perror("fork");
        exit(1);
    }

    for (hp=h; hp; hp=hp->next)
    {
        if (encode_header(hp->header))
            continue;
        fprintf(fpout, "%s", hp->header);
    }

    fprintf(fpout, "Content-Type: multipart/encrypted;\n"
            "    boundary=\"%s\";\n"
            "    protocol=\"application/pgp-encrypted\"\n"
            "\n"
            "This is a mimegpg-encrypted message.  If you see this text, it means\n"
            "that your E-mail software does not support MIME formatted messages.\n"
            "\n--%s\n"
            "Content-Type: application/pgp-encrypted\n"
            "Content-Transfer-Encoding: 7bit\n"
            "\n"
            "Version: 1\n"
            "\n--%s\n"
            "Content-Type: application/octet-stream\n"
            "Content-Transfer-Encoding: 7bit\n\n",
            boundary, boundary, boundary);

    /* For Eudora compatiblity */
    gpgmime_write(&gpg, "Mime-Version: 1.0\r\n", 19);

    for (hp=h; hp; hp=hp->next)
    {
        const char *p;

        if (!encode_header(hp->header))
            continue;

        for (p=hp->header; *p; p++)
        {
            if (*p == '\r')
                continue;

            if (*p == '\n')
                gpgmime_write(&gpg, "\r\n", 2);
            else
                gpgmime_write(&gpg, p, 1);
        }
    }

    /*
    ** Chew the content until the next MIME boundary.
    */
    need_crlf=1;

    while (!*iseof)
    {
        const char *p;

        if (fgets(buf, sizeof(buf), fpin) == NULL)
        {
            *iseof=1;
            break;
        }

        if (need_crlf)
        {
            if ((b=is_boundary(*stack, buf, &clos_flag)) != NULL)
                break;

            gpgmime_write(&gpg, "\r\n", 2);
        }

        need_crlf=0;
        for (;;)
        {
            for (p=buf; *p; p++)
            {
                if (*p == '\r')
                    continue;
                if (*p == '\n')
                {
                    need_crlf=1;
                    break;
                }

                gpgmime_write(&gpg, p, 1);
            }
            if (*p == '\n')
                break;

            if (fgets(buf, sizeof(buf), fpin) == NULL)
            {
                *iseof=1;
                break;
            }
        }
    }

    /*
    ** This needs some 'splainin.  Note that we spit out a newline at
    ** the BEGINNING of each line, above.  This generates the blank
    ** header->body separator line.  Now, if we're NOT doing multiline
    ** content, we need to follow the last line of the content with a
    ** newline.  If we're already doing multiline content, that extra
    ** newline (if it exists) is already there.
    */

    if (!*stack)
    {
        gpgmime_write(&gpg, "\r\n", 2);
    }

    rc=gpgmime_finish(&gpg);

    if (rc)
    {
        fprintf(stderr, "%s",
                gpgmime_getoutput(&gpg));
        exit(1);
    }

    fprintf(fpout, "\n--%s--\n", boundary);

    if (*iseof)
        return;

    fprintf(fpout, "\n--%s%s\n", b->boundary, clos_flag ? "--":"");

    if (clos_flag)
    {
        pop_mimestack_to(stack, b);
        find_boundary(stack, iseof, fpin, fpout, 1);
    }
}
Exemple #13
0
static struct header *read_headers(struct mimestack **stack, int *iseof,
                                   FILE *fpin,
                                   FILE *fpout,
                                   int doappend)
{
    char buf[BUFSIZ];
    struct read_header_context rhc;
    struct header *h;

    init_read_header_context(&rhc);

    while (!*iseof)
    {
        if (fgets(buf, sizeof(buf), fpin) == NULL)
        {
            *iseof=1;
            break;
        }

        if (READ_START_OF_LINE(rhc))
        {
            struct mimestack *b;
            int is_closing;

            if (strcmp(buf, "\n") == 0
                    || strcmp(buf, "\r\n") == 0)
                break;

            b=is_boundary(*stack, buf, &is_closing);

            if (b)
            {
                /*
                ** Corrupted MIME message.  We should NOT
                ** see a MIME boundary in the middle of the
                ** headers!
                **
                ** Ignore this damage.
                */

                struct header *p;

                h=finish_header(&rhc);

                for (p=h; p; p=p->next)
                    fprintf(fpout, "%s", p->header);
                fprintf(fpout, "--%s%s", b->boundary,
                        is_closing ? "--":"");
                if (is_closing)
                {
                    pop_mimestack_to(stack, b);
                    find_boundary(stack, iseof,
                                  fpin, fpout, doappend);
                }
                free_header(h);

                init_read_header_context(&rhc);
                continue; /* From the top */
            }
        }
        read_header(&rhc, buf);
    }

    return (finish_header(&rhc));
}
Exemple #14
0
static void decrypt(struct mimestack **stack, int *iseof,
                    struct header *h,
                    FILE *fpin, FILE *fpout, int argc, char **argv)
{
    struct header *p, *q;
    char temp_file[TEMPNAMEBUFSIZE];
    int temp_fd;
    FILE *temp_fp;
    struct mime_header *mh;
    int flag;

    temp_fd=mimegpg_tempfile(temp_file);
    if (temp_fd < 0 || (temp_fp=fdopen(temp_fd, "w+")) == 0)
    {
        if (temp_fd >= 0)
            close(temp_fd);
        perror("open");
        exit(1);
    }

    for (p=h; p; p=p->next)
    {
        fprintf(temp_fp, "%s", p->header);
    }
    putc('\n', temp_fp);

    find_boundary(stack, iseof, fpin, temp_fp, 0);
    if (*iseof)
    {
        fclose(temp_fp);
        unlink(temp_file);
        return;
    }

    p=read_headers(stack, iseof, fpin, temp_fp, 0);

    if (*iseof)
    {
        free_header(p);
        fclose(temp_fp);
        unlink(temp_file);
        return;
    }

    q=find_header(p, "content-type:");

    flag=0;

    if (q)
    {
        mh=parse_mime_header(q->header+13);
        if (!mh)
        {
            perror("malloc");
            free_header(p);
            fclose(temp_fp);
            unlink(temp_file);
            exit(1);
        }

        if (strcasecmp(mh->header_name, "application/pgp-encrypted")
                == 0)
            flag=1;
        free_mime_header(mh);
    }

    for (q=p; q; q=q->next)
    {
        fprintf(temp_fp, "%s", q->header);
    }
    free_header(p);
    putc('\n', temp_fp);

    p=read_headers(stack, iseof, fpin, temp_fp, 0);

    if (*iseof)
    {
        free_header(p);
        fclose(temp_fp);
        unlink(temp_file);
        return;
    }

    q=find_header(p, "version:");

    if (flag)
    {
        if (!q || atoi(p->header + 8) != 1)
            flag=0;
    }
    for (q=p; q; q=q->next)
    {
        fprintf(temp_fp, "%s", q->header);
    }
    free_header(p);
    putc('\n', temp_fp);

    find_boundary(stack, iseof, fpin, temp_fp, 0);

    if (*iseof)
    {
        fclose(temp_fp);
        unlink(temp_file);
        return;
    }

    p=read_headers(stack, iseof, fpin, temp_fp, 0);

    if (*iseof)
    {
        free_header(p);
        fclose(temp_fp);
        unlink(temp_file);
        return;
    }

    q=find_header(p, "content-type:");

    if (q && flag)
    {
        flag=0;
        mh=parse_mime_header(q->header+13);
        if (!mh)
        {
            perror("malloc");
            free_header(p);
            fclose(temp_fp);
            unlink(temp_file);
            exit(1);
        }

        if (strcasecmp(mh->header_name, "application/octet-stream")
                == 0)
            flag=1;
        free_mime_header(mh);

        q=find_header(p, "content-transfer-encoding:");
        if (q && flag)
        {
            flag=0;
            mh=parse_mime_header(strchr(q->header, ':')+1);
            if (!mh)
            {
                perror("malloc");
                free_header(p);
                fclose(temp_fp);
                unlink(temp_file);
                exit(1);
            }

            if (strcasecmp(mh->header_name, "7bit") == 0 ||
                    strcasecmp(mh->header_name, "8bit") == 0)
                flag=1;
            free_mime_header(mh);
        }
    }

    for (q=p; q; q=q->next)
    {
        fprintf(temp_fp, "%s", q->header);
    }
    free_header(p);
    putc('\n', temp_fp);

    if (fflush(temp_fp) || ferror(temp_fp) || my_rewind(temp_fp) < 0)
    {
        perror(temp_file);
        fclose(temp_fp);
        unlink(temp_file);
        exit(1);
    }

    if (!flag)
    {
        int c;

        while ((c=getc(temp_fp)) != EOF)
        {
            putc(c, fpout);
        }
        fclose(temp_fp);
        unlink(temp_file);
        close_mime(stack, iseof, fpin, fpout);
        return;
    }

    fclose(temp_fp);
    if ((temp_fp=fopen(temp_file, "w+")) == NULL)
    {
        perror(temp_file);
        unlink(temp_file);
        exit(1);
    }
    noexec(temp_fp);
    dodecrypt(stack, iseof, fpin, temp_fp, argc, argv, temp_file,
              fpout);
    fclose(temp_fp);
    unlink(temp_file);
}
Exemple #15
0
/**
 * Decode multipart POST data.
 */
static int
post_process_multipart (struct MHD_PostProcessor *pp,
                        const char *post_data, unsigned int post_data_len)
{
  char *buf;
  unsigned int max;
  unsigned int ioff;
  unsigned int poff;
  int state_changed;

  buf = (char *) &pp[1];
  ioff = 0;
  poff = 0;
  state_changed = 1;
  while ((poff < post_data_len) ||
         ((pp->buffer_pos > 0) && (state_changed != 0)))
    {
      /* first, move as much input data
         as possible to our internal buffer */
      max = pp->buffer_size - pp->buffer_pos;
      if (max > post_data_len - poff)
        max = post_data_len - poff;
      memcpy (&buf[pp->buffer_pos], &post_data[poff], max);
      poff += max;
      pp->buffer_pos += max;
      if ((max == 0) && (state_changed == 0) && (poff < post_data_len))
        {
          pp->state = PP_Error;
          return MHD_NO;        /* out of memory */
        }
      state_changed = 0;

      /* first state machine for '\r'-'\n' and '--' handling */
      switch (pp->skip_rn)
        {
        case RN_Inactive:
          break;
        case RN_OptN:
          if (buf[0] == '\n')
            {
              ioff++;
              pp->skip_rn = RN_Inactive;
              goto AGAIN;
            }
        case RN_Dash:
          if (buf[0] == '-')
            {
              ioff++;
              pp->skip_rn = RN_Dash2;
              goto AGAIN;
            }
          pp->skip_rn = RN_Full;
          /* fall-through! */
        case RN_Full:
          if (buf[0] == '\r')
            {
              if ((pp->buffer_pos > 1) && (buf[1] == '\n'))
                {
                  pp->skip_rn = RN_Inactive;
                  ioff += 2;
                }
              else
                {
                  pp->skip_rn = RN_OptN;
                  ioff++;
                }
              goto AGAIN;
            }
          if (buf[0] == '\n')
            {
              ioff++;
              pp->skip_rn = RN_Inactive;
              goto AGAIN;
            }
          pp->skip_rn = RN_Inactive;
          pp->state = PP_Error;
          return MHD_NO;        /* no '\r\n' */
        case RN_Dash2:
          if (buf[0] == '-')
            {
              ioff++;
              pp->skip_rn = RN_Full;
              pp->state = pp->dash_state;
              goto AGAIN;
            }
          pp->state = PP_Error;
          break;
        }

      /* main state engine */
      switch (pp->state)
        {
        case PP_Error:
          return MHD_NO;
        case PP_Done:
          /* did not expect to receive more data */
          pp->state = PP_Error;
          return MHD_NO;
        case PP_Init:
          if (MHD_NO == find_boundary (pp,
                                       pp->boundary,
                                       pp->blen,
                                       &ioff,
                                       PP_ProcessEntryHeaders, PP_Done))
            {
              if (pp->state == PP_Error)
                return MHD_NO;
              goto END;
            }
          break;
        case PP_ProcessEntryHeaders:
          if (MHD_NO ==
              process_multipart_headers (pp, &ioff, PP_PerformCheckMultipart))
            {
              if (pp->state == PP_Error)
                return MHD_NO;
              else
                goto END;
            }
          state_changed = 1;
          break;
        case PP_PerformCheckMultipart:
          if ((pp->content_type != NULL) &&
              (0 == strncasecmp (pp->content_type,
                                 "multipart/mixed",
                                 strlen ("multipart/mixed"))))
            {
              pp->nested_boundary = strstr (pp->content_type, "boundary=");
              if (pp->nested_boundary == NULL)
                {
                  pp->state = PP_Error;
                  return MHD_NO;
                }
              pp->nested_boundary =
                strdup (&pp->nested_boundary[strlen ("boundary=")]);
              if (pp->nested_boundary == NULL)
                {
                  /* out of memory */
                  pp->state = PP_Error;
                  return MHD_NO;
                }
              /* free old content type, we will need that field
                 for the content type of the nested elements */
              free (pp->content_type);
              pp->content_type = NULL;
              pp->nlen = strlen (pp->nested_boundary);
              pp->state = PP_Nested_Init;
              state_changed = 1;
              break;
            }
          pp->state = PP_ProcessValueToBoundary;
          pp->value_offset = 0;
          state_changed = 1;
          break;
        case PP_ProcessValueToBoundary:
          if (MHD_NO == process_value_to_boundary (pp,
                                                   &ioff,
                                                   pp->boundary,
                                                   pp->blen,
                                                   PP_PerformCleanup,
                                                   PP_Done))
            {
              if (pp->state == PP_Error)
                return MHD_NO;
              break;
            }
          break;
        case PP_PerformCleanup:
          /* clean up state of one multipart form-data element! */
          pp->have = NE_none;
          free_unmarked (pp);
          if (pp->nested_boundary != NULL)
            {
              free (pp->nested_boundary);
              pp->nested_boundary = NULL;
            }
          pp->state = PP_ProcessEntryHeaders;
          state_changed = 1;
          break;
        case PP_Nested_Init:
          if (pp->nested_boundary == NULL)
            {
              pp->state = PP_Error;
              return MHD_NO;
            }
          if (MHD_NO == find_boundary (pp,
                                       pp->nested_boundary,
                                       pp->nlen,
                                       &ioff,
                                       PP_Nested_PerformMarking,
                                       PP_Init /* or PP_Error? */ ))
            {
              if (pp->state == PP_Error)
                return MHD_NO;
              goto END;
            }
          break;
        case PP_Nested_PerformMarking:
          /* remember what headers were given
             globally */
          pp->have = NE_none;
          if (pp->content_name != NULL)
            pp->have |= NE_content_name;
          if (pp->content_type != NULL)
            pp->have |= NE_content_type;
          if (pp->content_filename != NULL)
            pp->have |= NE_content_filename;
          if (pp->content_transfer_encoding != NULL)
            pp->have |= NE_content_transfer_encoding;
          pp->state = PP_Nested_ProcessEntryHeaders;
          state_changed = 1;
          break;
        case PP_Nested_ProcessEntryHeaders:
          pp->value_offset = 0;
          if (MHD_NO ==
              process_multipart_headers (pp, &ioff,
                                         PP_Nested_ProcessValueToBoundary))
            {
              if (pp->state == PP_Error)
                return MHD_NO;
              else
                goto END;
            }
          state_changed = 1;
          break;
        case PP_Nested_ProcessValueToBoundary:
          if (MHD_NO == process_value_to_boundary (pp,
                                                   &ioff,
                                                   pp->nested_boundary,
                                                   pp->nlen,
                                                   PP_Nested_PerformCleanup,
                                                   PP_Init))
            {
              if (pp->state == PP_Error)
                return MHD_NO;
              break;
            }
          break;
        case PP_Nested_PerformCleanup:
          free_unmarked (pp);
          pp->state = PP_Nested_ProcessEntryHeaders;
          state_changed = 1;
          break;
        default:
          abort ();             /* should never happen! */
        }
    AGAIN:
      if (ioff > 0)
        {
          memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
          pp->buffer_pos -= ioff;
          ioff = 0;
          state_changed = 1;
        }
    }
END:
  if (ioff != 0)
    {
      memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
      pp->buffer_pos -= ioff;
    }
  if (poff < post_data_len)
    {
      pp->state = PP_Error;
      return MHD_NO;            /* serious error */
    }
  return MHD_YES;
}
/*  Converts a PEM encoded file into its binary form
 *
 *  RFC 1421 Privacy Enhancement for Electronic Mail, February 1993
 *  RFC 934 Message Encapsulation, January 1985
 */
err_t pem_to_bin(chunk_t *blob, chunk_t *passphrase, bool *pgp)
{
	typedef enum {
		PEM_PRE    = 0,
		PEM_MSG    = 1,
		PEM_HEADER = 2,
		PEM_BODY   = 3,
		PEM_POST   = 4,
		PEM_ABORT  = 5
	} state_t;

	encryption_algorithm_t alg = ENCR_UNDEFINED;
	size_t key_size = 0;

	bool encrypted = FALSE;

	state_t state  = PEM_PRE;

	chunk_t src    = *blob;
	chunk_t dst    = *blob;
	chunk_t line   = CHUNK_INITIALIZER;
	chunk_t iv     = CHUNK_INITIALIZER;

	u_char iv_buf[16]; /* MD5 digest size */

	/* zero size of converted blob */
	dst.len = 0;

	/* zero size of IV */
	iv.ptr = iv_buf;
	iv.len = 0;

	pem_init_logger();

	while (fetchline(&src, &line))
	{
		if (state == PEM_PRE)
		{
			if (find_boundary("BEGIN", &line))
			{
				state = PEM_MSG;
			}
			continue;
		}
		else
		{
			if (find_boundary("END", &line))
			{
				state = PEM_POST;
				break;
			}
			if (state == PEM_MSG)
			{
				state = (memchr(line.ptr, ':', line.len) == NULL) ? PEM_BODY : PEM_HEADER;
			}
			if (state == PEM_HEADER)
			{
				err_t ugh = NULL;
				chunk_t name  = CHUNK_INITIALIZER;
				chunk_t value = CHUNK_INITIALIZER;

				/* an empty line separates HEADER and BODY */
				if (line.len == 0)
				{
					state = PEM_BODY;
					continue;
				}

				/* we are looking for a parameter: value pair */
				logger->log(logger, CONTROL|LEVEL2, "  %.*s", (int)line.len, line.ptr);
				ugh = extract_parameter_value(&name, &value, &line);
				if (ugh != NULL)
					continue;

				if (match("Proc-Type", &name) && *value.ptr == '4')
					encrypted = TRUE;
				else if (match("DEK-Info", &name))
				{
					size_t len = 0;
					chunk_t dek;

					if (!extract_token(&dek, ',', &value))
						dek = value;

					/* we support DES-EDE3-CBC encrypted files, only */
					if (match("DES-EDE3-CBC", &dek))
					{
						alg = ENCR_3DES;
						key_size = 24;
					}
					else if (match("AES-128-CBC", &dek))
					{
						alg = ENCR_AES_CBC;
						key_size = 16;
					}
					else if (match("AES-192-CBC", &dek))
					{
						alg = ENCR_AES_CBC;
						key_size = 24;
					}
					else if (match("AES-256-CBC", &dek))
					{
						alg = ENCR_AES_CBC;
						key_size = 32;
					}
					else
					{
						return "encryption algorithm not supported";
					}

					eat_whitespace(&value);
					ugh = ttodata(value.ptr, value.len, 16, iv.ptr, 16, &len);
					if (ugh)
						return "error in IV";

					iv.len = len;
				}
			}
			else /* state is PEM_BODY */
			{
				const char *ugh = NULL;
				size_t len = 0;
				chunk_t data;
				
				/* remove any trailing whitespace */
				if (!extract_token(&data ,' ', &line))
				{
					data = line;
				}
				
				/* check for PGP armor checksum */
				if (*data.ptr == '=')
				{
					*pgp = TRUE;
					data.ptr++;
					data.len--;
					logger->log(logger, CONTROL|LEVEL2, "  Armor checksum: %.*s",
								(int)data.len, data.ptr);
		    		continue;
				}

				ugh = ttodata(data.ptr, data.len, 64, dst.ptr, blob->len - dst.len, &len);
				if (ugh)
				{
					state = PEM_ABORT;
					break;
				}
				else
				{
					dst.ptr += len;
					dst.len += len;
				}
			}
		}
	}
	/* set length to size of binary blob */
	blob->len = dst.len;

	if (state != PEM_POST)
		return "file coded in unknown format, discarded";

	return (encrypted)? pem_decrypt(blob, alg, key_size, &iv, passphrase) : NULL;
}
Exemple #17
0
static void handle_body(void)
{
	int rc = 0;
	static char newline[2000];
	static char *np = newline;

	/* Skip up to the first boundary */
	if (content_top->boundary) {
		if (!find_boundary())
			return;
	}

	do {
		/* process any boundary lines */
		if (content_top->boundary && is_multipart_boundary(line)) {
			/* flush any leftover */
			if ((transfer_encoding == TE_BASE64)  &&
			    (np != newline)) {
				handle_filter(newline, sizeof(newline));
			}
			if (!handle_boundary())
				return;
		}

		/* Unwrap transfer encoding */
		decode_transfer_encoding(line, sizeof(line));

		switch (transfer_encoding) {
		case TE_BASE64:
		case TE_QP:
		{
			char *op = line;

			/* binary data most likely doesn't have newlines */
			if (message_type != TYPE_TEXT) {
				rc = handle_filter(line, sizeof(newline));
				break;
			}

			/* this is a decoded line that may contain
			 * multiple new lines.  Pass only one chunk
			 * at a time to handle_filter()
			 */

			do {
				while (*op != '\n' && *op != 0)
					*np++ = *op++;
				*np = *op;
				if (*np != 0) {
					/* should be sitting on a new line */
					*(++np) = 0;
					op++;
					rc = handle_filter(newline, sizeof(newline));
					np = newline;
				}
			} while (*op != 0);
			/* the partial chunk is saved in newline and
			 * will be appended by the next iteration of fgets
			 */
			break;
		}
		default:
			rc = handle_filter(line, sizeof(newline));
		}
		if (rc)
			/* nothing left to filter */
			break;
	} while (fgets(line, sizeof(line), fin));

	return;
}
/**
 * Converts a PEM encoded file into its binary form (RFC 1421, RFC 934)
 */
static status_t pem_to_bin(chunk_t *blob, chunk_t(*cb)(void*,int), void *cb_data,
						   bool *pgp)
{
	typedef enum {
		PEM_PRE    = 0,
		PEM_MSG    = 1,
		PEM_HEADER = 2,
		PEM_BODY   = 3,
		PEM_POST   = 4,
		PEM_ABORT  = 5
	} state_t;

	encryption_algorithm_t alg = ENCR_UNDEFINED;
	size_t key_size = 0;
	bool encrypted = FALSE;
	state_t state  = PEM_PRE;
	chunk_t src    = *blob;
	chunk_t dst    = *blob;
	chunk_t line   = chunk_empty;
	chunk_t iv     = chunk_empty;
	chunk_t passphrase;
	int try = 0;
	u_char iv_buf[HASH_SIZE_MD5];

	dst.len = 0;
	iv.ptr = iv_buf;
	iv.len = 0;

	while (fetchline(&src, &line))
	{
		if (state == PEM_PRE)
		{
			if (find_boundary("BEGIN", &line))
			{
				state = PEM_MSG;
			}
			continue;
		}
		else
		{
			if (find_boundary("END", &line))
			{
				state = PEM_POST;
				break;
			}
			if (state == PEM_MSG)
			{
				state = PEM_HEADER;
				if (memchr(line.ptr, ':', line.len) == NULL)
				{
					state = PEM_BODY;
				}
			}
			if (state == PEM_HEADER)
			{
				err_t ugh = NULL;
				chunk_t name  = chunk_empty;
				chunk_t value = chunk_empty;

				/* an empty line separates HEADER and BODY */
				if (line.len == 0)
				{
					state = PEM_BODY;
					continue;
				}

				/* we are looking for a parameter: value pair */
				DBG2(DBG_LIB, "  %.*s", (int)line.len, line.ptr);
				ugh = extract_parameter_value(&name, &value, &line);
				if (ugh != NULL)
				{
					continue;
				}
				if (match("Proc-Type", &name) && *value.ptr == '4')
				{
					encrypted = TRUE;
				}
				else if (match("DEK-Info", &name))
				{
					chunk_t dek;

					if (!extract_token(&dek, ',', &value))
					{
						dek = value;
					}
					if (match("DES-EDE3-CBC", &dek))
					{
						alg = ENCR_3DES;
						key_size = 24;
					}
					else if (match("AES-128-CBC", &dek))
					{
						alg = ENCR_AES_CBC;
						key_size = 16;
					}
					else if (match("AES-192-CBC", &dek))
					{
						alg = ENCR_AES_CBC;
						key_size = 24;
					}
					else if (match("AES-256-CBC", &dek))
					{
						alg = ENCR_AES_CBC;
						key_size = 32;
					}
					else
					{
						DBG1(DBG_LIB, "  encryption algorithm '%.*s'"
							 " not supported", dek.len, dek.ptr);
						return NOT_SUPPORTED;
					}
					eat_whitespace(&value);
					iv = chunk_from_hex(value, iv.ptr);
				}
			}
			else /* state is PEM_BODY */
			{
				chunk_t data;

				/* remove any trailing whitespace */
				if (!extract_token(&data ,' ', &line))
				{
					data = line;
				}

				/* check for PGP armor checksum */
				if (*data.ptr == '=')
				{
					*pgp = TRUE;
					data.ptr++;
					data.len--;
					DBG2(DBG_LIB, "  armor checksum: %.*s", (int)data.len,
						 data.ptr);
					continue;
				}

				if (blob->len - dst.len < data.len / 4 * 3)
				{
					state = PEM_ABORT;
				}
				data = chunk_from_base64(data, dst.ptr);

				dst.ptr += data.len;
				dst.len += data.len;
			}
		}
	}
	/* set length to size of binary blob */
	blob->len = dst.len;

	if (state != PEM_POST)
	{
		DBG1(DBG_LIB, "  file coded in unknown format, discarded");
		return PARSE_ERROR;
	}
	if (!encrypted)
	{
		return SUCCESS;
	}
	if (!cb)
	{
		DBG1(DBG_LIB, "  missing passphrase");
		return INVALID_ARG;
	}
	while (TRUE)
	{
		passphrase = cb(cb_data, ++try);
		if (!passphrase.len || !passphrase.ptr)
		{
			return INVALID_ARG;
		}
		switch (pem_decrypt(blob, alg, key_size, iv, passphrase))
		{
			case INVALID_ARG:
				/* bad passphrase, retry */
				continue;
			case SUCCESS:
				return SUCCESS;
			default:
				return FAILED;
		}
	}
}
Exemple #19
0
/**
 * Converts a PEM encoded file into its binary form (RFC 1421, RFC 934)
 */
static status_t pem_to_bin(chunk_t *blob, bool *pgp)
{
	typedef enum {
		PEM_PRE    = 0,
		PEM_MSG    = 1,
		PEM_HEADER = 2,
		PEM_BODY   = 3,
		PEM_POST   = 4,
		PEM_ABORT  = 5
	} state_t;

	encryption_algorithm_t alg = ENCR_UNDEFINED;
	size_t key_size = 0;
	bool encrypted = FALSE;
	state_t state  = PEM_PRE;
	chunk_t src    = *blob;
	chunk_t dst    = *blob;
	chunk_t line   = chunk_empty;
	chunk_t iv     = chunk_empty;
	u_char iv_buf[HASH_SIZE_MD5];
	status_t status = NOT_FOUND;
	enumerator_t *enumerator;
	shared_key_t *shared;

	dst.len = 0;
	iv.ptr = iv_buf;
	iv.len = 0;

	while (fetchline(&src, &line))
	{
		if (state == PEM_PRE)
		{
			if (find_boundary("BEGIN", &line))
			{
				state = PEM_MSG;
			}
			continue;
		}
		else
		{
			if (find_boundary("END", &line))
			{
				state = PEM_POST;
				break;
			}
			if (state == PEM_MSG)
			{
				state = PEM_HEADER;
				if (memchr(line.ptr, ':', line.len) == NULL)
				{
					state = PEM_BODY;
				}
			}
			if (state == PEM_HEADER)
			{
				err_t ugh = NULL;
				chunk_t name  = chunk_empty;
				chunk_t value = chunk_empty;

				/* an empty line separates HEADER and BODY */
				if (line.len == 0)
				{
					state = PEM_BODY;
					continue;
				}

				/* we are looking for a parameter: value pair */
				DBG2(DBG_ASN, "  %.*s", (int)line.len, line.ptr);
				ugh = extract_parameter_value(&name, &value, &line);
				if (ugh != NULL)
				{
					continue;
				}
				if (match("Proc-Type", &name) && *value.ptr == '4')
				{
					encrypted = TRUE;
				}
				else if (match("DEK-Info", &name))
				{
					chunk_t dek;

					if (!extract_token(&dek, ',', &value))
					{
						dek = value;
					}
					if (match("DES-EDE3-CBC", &dek))
					{
						alg = ENCR_3DES;
						key_size = 24;
					}
					else if (match("AES-128-CBC", &dek))
					{
						alg = ENCR_AES_CBC;
						key_size = 16;
					}
					else if (match("AES-192-CBC", &dek))
					{
						alg = ENCR_AES_CBC;
						key_size = 24;
					}
					else if (match("AES-256-CBC", &dek))
					{
						alg = ENCR_AES_CBC;
						key_size = 32;
					}
					else
					{
						DBG1(DBG_ASN, "  encryption algorithm '%.*s'"
							 " not supported", (int)dek.len, dek.ptr);
						return NOT_SUPPORTED;
					}
					if (!eat_whitespace(&value) || value.len > 2*sizeof(iv_buf))
					{
						return PARSE_ERROR;
					}
					iv = chunk_from_hex(value, iv_buf);
				}
			}
			else /* state is PEM_BODY */
			{
				chunk_t data;

				/* remove any trailing whitespace */
				if (!extract_token(&data ,' ', &line))
				{
					data = line;
				}

				/* check for PGP armor checksum */
				if (*data.ptr == '=')
				{
					*pgp = TRUE;
					data.ptr++;
					data.len--;
					DBG2(DBG_ASN, "  armor checksum: %.*s", (int)data.len,
						 data.ptr);
					continue;
				}

				if (blob->len - dst.len < data.len / 4 * 3)
				{
					state = PEM_ABORT;
				}
				data = chunk_from_base64(data, dst.ptr);

				dst.ptr += data.len;
				dst.len += data.len;
			}
		}
	}
	/* set length to size of binary blob */
	blob->len = dst.len;

	if (state != PEM_POST)
	{
		DBG1(DBG_LIB, "  file coded in unknown format, discarded");
		return PARSE_ERROR;
	}
	if (!encrypted)
	{
		return SUCCESS;
	}

	enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
											SHARED_PRIVATE_KEY_PASS, NULL, NULL);
	while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
	{
		chunk_t passphrase, chunk;

		passphrase = shared->get_key(shared);
		chunk = chunk_clone(*blob);
		status = pem_decrypt(&chunk, alg, key_size, iv, passphrase);
		if (status == SUCCESS)
		{
			memcpy(blob->ptr, chunk.ptr, chunk.len);
			blob->len = chunk.len;
		}
		free(chunk.ptr);
		if (status != INVALID_ARG)
		{	/* try again only if passphrase invalid */
			break;
		}
	}
	enumerator->destroy(enumerator);
	return status;
}
Exemple #20
0
/**
 * Decode multipart POST data.
 *
 * @param pp post processor context
 */
static int
post_process_multipart (struct MHD_PostProcessor *pp,
                        const char *post_data,
			size_t post_data_len)
{
  char *buf;
  size_t max;
  size_t ioff;
  size_t poff;
  int state_changed;

  buf = (char *) &pp[1];
  ioff = 0;
  poff = 0;
  state_changed = 1;
  while ((poff < post_data_len) ||
         ((pp->buffer_pos > 0) && (state_changed != 0)))
    {
      /* first, move as much input data
         as possible to our internal buffer */
      max = pp->buffer_size - pp->buffer_pos;
      if (max > post_data_len - poff)
        max = post_data_len - poff;
      memcpy (&buf[pp->buffer_pos], &post_data[poff], max);
      poff += max;
      pp->buffer_pos += max;
      if ((max == 0) && (state_changed == 0) && (poff < post_data_len))
        {
          pp->state = PP_Error;
          return MHD_NO;        /* out of memory */
        }
      state_changed = 0;

      /* first state machine for '\r'-'\n' and '--' handling */
      switch (pp->skip_rn)
        {
        case RN_Inactive:
          break;
        case RN_OptN:
          if (buf[0] == '\n')
            {
              ioff++;
              pp->skip_rn = RN_Inactive;
              goto AGAIN;
            }
          /* fall-through! */
        case RN_Dash:
          if (buf[0] == '-')
            {
              ioff++;
              pp->skip_rn = RN_Dash2;
              goto AGAIN;
            }
          pp->skip_rn = RN_Full;
          /* fall-through! */
        case RN_Full:
          if (buf[0] == '\r')
            {
              if ((pp->buffer_pos > 1) && (buf[1] == '\n'))
                {
                  pp->skip_rn = RN_Inactive;
                  ioff += 2;
                }
              else
                {
                  pp->skip_rn = RN_OptN;
                  ioff++;
                }
              goto AGAIN;
            }
          if (buf[0] == '\n')
            {
              ioff++;
              pp->skip_rn = RN_Inactive;
              goto AGAIN;
            }
          pp->skip_rn = RN_Inactive;
          pp->state = PP_Error;
          return MHD_NO;        /* no '\r\n' */
        case RN_Dash2:
          if (buf[0] == '-')
            {
              ioff++;
              pp->skip_rn = RN_Full;
              pp->state = pp->dash_state;
              goto AGAIN;
            }
          pp->state = PP_Error;
          break;
        }

      /* main state engine */
      switch (pp->state)
        {
        case PP_Error:
          return MHD_NO;
        case PP_Done:
          /* did not expect to receive more data */
          pp->state = PP_Error;
          return MHD_NO;
        case PP_Init:
          /**
           * Per RFC2046 5.1.1 NOTE TO IMPLEMENTORS, consume anything
           * prior to the first multipart boundary:
           *
           * > There appears to be room for additional information prior
           * > to the first boundary delimiter line and following the
           * > final boundary delimiter line.  These areas should
           * > generally be left blank, and implementations must ignore
           * > anything that appears before the first boundary delimiter
           * > line or after the last one.
           */
          (void) find_boundary (pp,
				pp->boundary,
				pp->blen,
				&ioff,
				PP_ProcessEntryHeaders, PP_Done);
          break;
        case PP_NextBoundary:
          if (MHD_NO == find_boundary (pp,
                                       pp->boundary,
                                       pp->blen,
                                       &ioff,
                                       PP_ProcessEntryHeaders, PP_Done))
            {
              if (pp->state == PP_Error)
                return MHD_NO;
              goto END;
            }
          break;
        case PP_ProcessEntryHeaders:
	  pp->must_ikvi = MHD_YES;
          if (MHD_NO ==
              process_multipart_headers (pp, &ioff, PP_PerformCheckMultipart))
            {
              if (pp->state == PP_Error)
                return MHD_NO;
              else
                goto END;
            }
          state_changed = 1;
          break;
        case PP_PerformCheckMultipart:
          if ((pp->content_type != NULL) &&
              (0 == strncasecmp (pp->content_type,
                                 "multipart/mixed",
                                 strlen ("multipart/mixed"))))
            {
              pp->nested_boundary = strstr (pp->content_type, "boundary=");
              if (pp->nested_boundary == NULL)
                {
                  pp->state = PP_Error;
                  return MHD_NO;
                }
              pp->nested_boundary =
                strdup (&pp->nested_boundary[strlen ("boundary=")]);
              if (pp->nested_boundary == NULL)
                {
                  /* out of memory */
                  pp->state = PP_Error;
                  return MHD_NO;
                }
              /* free old content type, we will need that field
                 for the content type of the nested elements */
              free (pp->content_type);
              pp->content_type = NULL;
              pp->nlen = strlen (pp->nested_boundary);
              pp->state = PP_Nested_Init;
              state_changed = 1;
              break;
            }
          pp->state = PP_ProcessValueToBoundary;
          pp->value_offset = 0;
          state_changed = 1;
          break;
        case PP_ProcessValueToBoundary:
          if (MHD_NO == process_value_to_boundary (pp,
                                                   &ioff,
                                                   pp->boundary,
                                                   pp->blen,
                                                   PP_PerformCleanup,
                                                   PP_Done))
            {
              if (pp->state == PP_Error)
                return MHD_NO;
              break;
            }
          break;
        case PP_PerformCleanup:
          /* clean up state of one multipart form-data element! */
          pp->have = NE_none;
          free_unmarked (pp);
          if (pp->nested_boundary != NULL)
            {
              free (pp->nested_boundary);
              pp->nested_boundary = NULL;
            }
          pp->state = PP_ProcessEntryHeaders;
          state_changed = 1;
          break;
        case PP_Nested_Init:
          if (pp->nested_boundary == NULL)
            {
              pp->state = PP_Error;
              return MHD_NO;
            }
          if (MHD_NO == find_boundary (pp,
                                       pp->nested_boundary,
                                       pp->nlen,
                                       &ioff,
                                       PP_Nested_PerformMarking,
                                       PP_NextBoundary /* or PP_Error? */ ))
            {
              if (pp->state == PP_Error)
                return MHD_NO;
              goto END;
            }
          break;
        case PP_Nested_PerformMarking:
          /* remember what headers were given
             globally */
          pp->have = NE_none;
          if (pp->content_name != NULL)
            pp->have |= NE_content_name;
          if (pp->content_type != NULL)
            pp->have |= NE_content_type;
          if (pp->content_filename != NULL)
            pp->have |= NE_content_filename;
          if (pp->content_transfer_encoding != NULL)
            pp->have |= NE_content_transfer_encoding;
          pp->state = PP_Nested_ProcessEntryHeaders;
          state_changed = 1;
          break;
        case PP_Nested_ProcessEntryHeaders:
          pp->value_offset = 0;
          if (MHD_NO ==
              process_multipart_headers (pp, &ioff,
                                         PP_Nested_ProcessValueToBoundary))
            {
              if (pp->state == PP_Error)
                return MHD_NO;
              else
                goto END;
            }
          state_changed = 1;
          break;
        case PP_Nested_ProcessValueToBoundary:
          if (MHD_NO == process_value_to_boundary (pp,
                                                   &ioff,
                                                   pp->nested_boundary,
                                                   pp->nlen,
                                                   PP_Nested_PerformCleanup,
                                                   PP_NextBoundary))
            {
              if (pp->state == PP_Error)
                return MHD_NO;
              break;
            }
          break;
        case PP_Nested_PerformCleanup:
          free_unmarked (pp);
          pp->state = PP_Nested_ProcessEntryHeaders;
          state_changed = 1;
          break;
        default:
          mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);          /* should never happen! */
        }
    AGAIN:
      if (ioff > 0)
        {
          memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
          pp->buffer_pos -= ioff;
          ioff = 0;
          state_changed = 1;
        }
    }
END:
  if (ioff != 0)
    {
      memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
      pp->buffer_pos -= ioff;
    }
  if (poff < post_data_len)
    {
      pp->state = PP_Error;
      return MHD_NO;            /* serious error */
    }
  return MHD_YES;
}
Exemple #21
0
static void handle_body(void)
{
	struct strbuf prev = STRBUF_INIT;

	/* Skip up to the first boundary */
	if (*content_top) {
		if (!find_boundary())
			goto handle_body_out;
	}

	do {
		/* process any boundary lines */
		if (*content_top && is_multipart_boundary(&line)) {
			/* flush any leftover */
			if (prev.len) {
				handle_filter(&prev);
				strbuf_reset(&prev);
			}
			if (!handle_boundary())
				goto handle_body_out;
		}

		/* Unwrap transfer encoding */
		decode_transfer_encoding(&line);

		switch (transfer_encoding) {
		case TE_BASE64:
		case TE_QP:
		{
			struct strbuf **lines, **it, *sb;

			/* Prepend any previous partial lines */
			strbuf_insert(&line, 0, prev.buf, prev.len);
			strbuf_reset(&prev);

			/* binary data most likely doesn't have newlines */
			if (message_type != TYPE_TEXT) {
				handle_filter(&line);
				break;
			}
			/*
			 * This is a decoded line that may contain
			 * multiple new lines.  Pass only one chunk
			 * at a time to handle_filter()
			 */
			lines = strbuf_split(&line, '\n');
			for (it = lines; (sb = *it); it++) {
				if (*(it + 1) == NULL) /* The last line */
					if (sb->buf[sb->len - 1] != '\n') {
						/* Partial line, save it for later. */
						strbuf_addbuf(&prev, sb);
						break;
					}
				handle_filter(sb);
			}
			/*
			 * The partial chunk is saved in "prev" and will be
			 * appended by the next iteration of read_line_with_nul().
			 */
			strbuf_list_free(lines);
			break;
		}
		default:
			handle_filter(&line);
		}

	} while (!strbuf_getwholeline(&line, fin, '\n'));

handle_body_out:
	strbuf_release(&prev);
}