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; }
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); }
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); }
/* Example multipart form-data request content format: --AaB03x Content-Disposition: form-data; name="submit-name" Larry --AaB03x Content-Disposition: form-data; name="file"; filename="file1.txt" Content-Type: text/plain ... contents of file1.txt ... --AaB03x-- */ static evhtp_res upload_read_cb (evhtp_request_t *req, evbuf_t *buf, void *arg) { RecvFSM *fsm = arg; char *line; size_t len; gboolean no_line = FALSE; int res = EVHTP_RES_OK; if (fsm->state == RECV_ERROR) return EVHTP_RES_OK; /* Update upload progress. */ fsm->progress->uploaded += (gint64)evbuffer_get_length(buf); seaf_debug ("progress: %lld/%lld\n", fsm->progress->uploaded, fsm->progress->size); evbuffer_add_buffer (fsm->line, buf); /* Drain the buffer so that evhtp don't copy it to another buffer * after this callback returns. */ evbuffer_drain (buf, evbuffer_get_length (buf)); while (!no_line) { switch (fsm->state) { case RECV_INIT: line = evbuffer_readln (fsm->line, &len, EVBUFFER_EOL_CRLF_STRICT); if (line != NULL) { seaf_debug ("[upload] boundary line: %s.\n", line); if (!strstr (line, fsm->boundary)) { seaf_warning ("[upload] no boundary found in the first line.\n"); free (line); res = EVHTP_RES_BADREQ; goto out; } else { fsm->state = RECV_HEADERS; free (line); } } else { no_line = TRUE; } break; case RECV_HEADERS: line = evbuffer_readln (fsm->line, &len, EVBUFFER_EOL_CRLF_STRICT); if (line != NULL) { seaf_debug ("[upload] mime header line: %s.\n", line); if (len == 0) { /* Read an blank line, headers end. */ free (line); if (g_strcmp0 (fsm->input_name, "file") == 0) { if (open_temp_file (fsm) < 0) { seaf_warning ("[upload] Failed open temp file.\n"); res = EVHTP_RES_SERVERR; goto out; } } seaf_debug ("[upload] Start to recv %s.\n", fsm->input_name); fsm->state = RECV_CONTENT; } else if (parse_mime_header (line, fsm) < 0) { free (line); res = EVHTP_RES_BADREQ; goto out; } else { free (line); } } else { no_line = TRUE; } break; case RECV_CONTENT: if (g_strcmp0 (fsm->input_name, "file") == 0) res = recv_file_data (fsm, &no_line); else res = recv_form_field (fsm, &no_line); if (res != EVHTP_RES_OK) goto out; break; } } out: if (res != EVHTP_RES_OK) { /* Don't receive any data before the connection is closed. */ evhtp_request_pause (req); /* Set keepalive to 0. This will cause evhtp to close the * connection after sending the reply. */ req->keepalive = 0; fsm->state = RECV_ERROR; } if (res == EVHTP_RES_BADREQ) { evhtp_send_reply (req, EVHTP_RES_BADREQ); } else if (res == EVHTP_RES_SERVERR) { evbuffer_add_printf (req->buffer_out, "Internal server error\n"); evhtp_send_reply (req, EVHTP_RES_SERVERR); } return EVHTP_RES_OK; }