char * mailprivacy_dup_imf_file(struct mailprivacy * privacy, char * source_filename) { char filename[PATH_MAX]; FILE * dest_f; int r; struct stat stat_info; char * dest_filename; char * mapping; int fd; int col; dest_f = mailprivacy_get_tmp_file(privacy, filename, sizeof(filename)); if (dest_f == NULL) goto err; dest_filename = strdup(filename); if (dest_filename == NULL) goto close_dest; fd = open(source_filename, O_RDONLY); if (fd < 0) goto free_dest; r = fstat(fd, &stat_info); if (r < 0) goto close_src; mapping = mmap(NULL, stat_info.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (mapping == (char *)MAP_FAILED) goto close_src; col = 0; r = mailimf_string_write(dest_f, &col, mapping, stat_info.st_size); if (r != MAILIMF_NO_ERROR) goto unmap; munmap(mapping, stat_info.st_size); close(fd); fclose(dest_f); return dest_filename; unmap: munmap(mapping, stat_info.st_size); close_src: close(fd); free_dest: free(dest_filename); close_dest: fclose(dest_f); err: return NULL; }
static char * dup_file(struct mailprivacy * privacy, char * source_filename) { char filename[PATH_MAX]; FILE * dest_f; int r; struct stat stat_info; char * dest_filename; char * mapping; size_t written; int fd; dest_f = mailprivacy_get_tmp_file(privacy, filename, sizeof(filename)); if (dest_f == NULL) goto err; dest_filename = strdup(filename); if (dest_filename == NULL) goto close_dest; fd = open(source_filename, O_RDONLY); if (fd < 0) goto free_dest; r = fstat(fd, &stat_info); if (r < 0) goto close_src; mapping = mmap(NULL, stat_info.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (mapping == (char *)MAP_FAILED) goto close_src; written = fwrite(mapping, 1, stat_info.st_size, dest_f); if (written != (size_t) stat_info.st_size) goto unmap; munmap(mapping, stat_info.st_size); close(fd); fclose(dest_f); return dest_filename; unmap: munmap(mapping, stat_info.st_size); close_src: close(fd); free_dest: free(dest_filename); close_dest: fclose(dest_f); err: return NULL; }
int mailprivacy_get_tmp_filename(struct mailprivacy * privacy, char * filename, size_t size) { FILE * f; f = mailprivacy_get_tmp_file(privacy, filename, size); if (f == NULL) return MAIL_ERROR_FILE; fclose(f); return MAIL_NO_ERROR; }
struct mailmime_fields * mailprivacy_mime_fields_dup(struct mailprivacy * privacy, struct mailmime_fields * mime_fields) { FILE * f; char tmp_file[PATH_MAX]; int col; int r; struct mailmime_fields * dup_mime_fields; int fd; char * mapping; struct stat stat_info; struct mailimf_fields * fields; size_t cur_token; f = mailprivacy_get_tmp_file(privacy, tmp_file, sizeof(tmp_file)); if (f == NULL) goto err; col = 0; r = mailmime_fields_write(f, &col, mime_fields); if (r != MAILIMF_NO_ERROR) goto unlink; fflush(f); fd = fileno(f); if (fd == -1) goto unlink; r = fstat(fd, &stat_info); if (r < 0) goto unlink; mapping = mmap(NULL, stat_info.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (mapping == (char *)MAP_FAILED) goto unlink; cur_token = 0; r = mailimf_optional_fields_parse(mapping, stat_info.st_size, &cur_token, &fields); if (r != MAILIMF_NO_ERROR) goto unmap; r = mailmime_fields_parse(fields, &dup_mime_fields); mailimf_fields_free(fields); if (r != MAILIMF_NO_ERROR) goto unmap; munmap(mapping, stat_info.st_size); fclose(f); unlink(tmp_file); return dup_mime_fields; unmap: munmap(mapping, stat_info.st_size); unlink: fclose(f); unlink(tmp_file); err: return NULL; }
int mailprivacy_fetch_mime_body_to_file(struct mailprivacy * privacy, char * filename, size_t size, mailmessage * msg, struct mailmime * mime) { int r; int res; FILE * f; char * content; size_t content_len; int col; if (mime->mm_parent_type == MAILMIME_NONE) { res = MAIL_ERROR_INVAL; goto err; } f = mailprivacy_get_tmp_file(privacy, filename, size); if (f == NULL) { res = MAIL_ERROR_FETCH; goto err; } r = mailprivacy_msg_fetch_section_mime(privacy, msg, mime, &content, &content_len); if (r != MAIL_NO_ERROR) { res = MAIL_ERROR_FETCH; goto close; } col = 0; r = mailimf_string_write(f, &col, content, content_len); mailprivacy_msg_fetch_result_free(privacy, msg, content); if (r != MAILIMF_NO_ERROR) { res = r; goto close; } r = mailprivacy_msg_fetch_section(privacy, msg, mime, &content, &content_len); if (r != MAIL_NO_ERROR) { res = MAIL_ERROR_FETCH; goto close; } r = mailimf_string_write(f, &col, content, content_len); mailprivacy_msg_fetch_result_free(privacy, msg, content); if (r != MAILIMF_NO_ERROR) { res = r; goto close; } fclose(f); return MAIL_NO_ERROR; close: fclose(f); unlink(filename); err: return res; }
static int mime_data_replace(struct mailprivacy * privacy, int encoding_type, struct mailmime_data * data, int reencode) { char filename[PATH_MAX]; FILE * f; size_t written; char * dup_filename; int res; int r; int decoded; if (data->dt_type != MAILMIME_DATA_TEXT) { res = MAIL_NO_ERROR; goto err; } f = mailprivacy_get_tmp_file(privacy, filename, sizeof(filename)); if (f == NULL) { res = MAIL_ERROR_FILE; goto err; } decoded = 0; if (reencode) { if (encoding_type != -1) { char * content; size_t content_len; size_t cur_token; cur_token = 0; r = mailmime_part_parse(data->dt_data.dt_text.dt_data, data->dt_data.dt_text.dt_length, &cur_token, encoding_type, &content, &content_len); if (r == MAILIMF_NO_ERROR) { /* write decoded */ written = fwrite(content, 1, content_len, f); if (written != content_len) { fclose(f); unlink(filename); res = MAIL_ERROR_FILE; goto err; } mmap_string_unref(content); decoded = 1; data->dt_encoded = 0; } } } if (!decoded) { written = fwrite(data->dt_data.dt_text.dt_data, 1, data->dt_data.dt_text.dt_length, f); if (written != data->dt_data.dt_text.dt_length) { fclose(f); unlink(filename); res = MAIL_ERROR_FILE; goto err; } } fclose(f); dup_filename = strdup(filename); if (dup_filename == NULL) { unlink(filename); res = MAIL_ERROR_MEMORY; goto err; } data->dt_type = MAILMIME_DATA_FILE; data->dt_data.dt_filename = dup_filename; return MAIL_NO_ERROR; err: return res; }
int mailprivacy_fetch_decoded_to_file(struct mailprivacy * privacy, char * filename, size_t size, mailmessage * msg, struct mailmime * mime) { int r; int res; FILE * f; char * content; size_t content_len; size_t written; struct mailmime_single_fields single_fields; int encoding; size_t cur_token; char * parsed_content; size_t parsed_content_len; mailmime_single_fields_init(&single_fields, mime->mm_mime_fields, mime->mm_content_type); if (single_fields.fld_encoding != NULL) encoding = single_fields.fld_encoding->enc_type; else encoding = MAILMIME_MECHANISM_8BIT; r = mailprivacy_msg_fetch_section(privacy, msg, mime, &content, &content_len); if (r != MAIL_NO_ERROR) { res = MAIL_ERROR_FETCH; goto err; } cur_token = 0; r = mailmime_part_parse(content, content_len, &cur_token, encoding, &parsed_content, &parsed_content_len); mailprivacy_msg_fetch_result_free(privacy, msg, content); if (r != MAILIMF_NO_ERROR) { res = MAIL_ERROR_PARSE; goto err; } f = mailprivacy_get_tmp_file(privacy, filename, size); if (f == NULL) { res = MAIL_ERROR_FETCH; goto free_fetch; } written = fwrite(parsed_content, 1, parsed_content_len, f); if (written != parsed_content_len) { res = MAIL_ERROR_FILE; goto close; } fclose(f); mmap_string_unref(parsed_content); return MAIL_NO_ERROR; close: fclose(f); unlink(filename); free_fetch: mmap_string_unref(parsed_content); err: return res; }
static int smime_encrypt(struct mailprivacy * privacy, mailmessage * msg, struct mailmime * mime, struct mailmime ** result) { char encrypted_filename[PATH_MAX]; int res; int r; int col; char description_filename[PATH_MAX]; char decrypted_filename[PATH_MAX]; FILE * decrypted_f; char command[PATH_MAX]; char quoted_decrypted_filename[PATH_MAX]; struct mailmime * encrypted_mime; struct mailmime * root; struct mailimf_fields * fields; char recipient[PATH_MAX]; root = mime; while (root->mm_parent != NULL) root = root->mm_parent; fields = NULL; if (root->mm_type == MAILMIME_MESSAGE) fields = root->mm_data.mm_message.mm_fields; /* recipient */ r = collect_smime_cert(recipient, sizeof(recipient), fields); if (r != MAIL_NO_ERROR) { res = r; goto err; } /* part to encrypt */ /* encode quoted printable all text parts */ mailprivacy_prepare_mime(mime); decrypted_f = mailprivacy_get_tmp_file(privacy, decrypted_filename, sizeof(decrypted_filename)); if (decrypted_f == NULL) { res = MAIL_ERROR_FILE; goto err; } col = 0; r = mailmime_write(decrypted_f, &col, mime); if (r != MAILIMF_NO_ERROR) { fclose(decrypted_f); res = MAIL_ERROR_FILE; goto unlink_decrypted; } fclose(decrypted_f); /* prepare destination file for encryption */ r = mailprivacy_get_tmp_filename(privacy, encrypted_filename, sizeof(encrypted_filename)); if (r != MAIL_NO_ERROR) { res = MAIL_ERROR_FILE; goto unlink_decrypted; } r = mailprivacy_get_tmp_filename(privacy, description_filename, sizeof(description_filename)); if (r != MAIL_NO_ERROR) { res = MAIL_ERROR_FILE; goto unlink_encrypted; } r = mail_quote_filename(quoted_decrypted_filename, sizeof(quoted_decrypted_filename), decrypted_filename); if (r < 0) { res = MAIL_ERROR_MEMORY; goto unlink_description; } snprintf(command, sizeof(command), "openssl smime -encrypt -in '%s' %s", quoted_decrypted_filename, recipient); r = smime_command_passphrase(privacy, msg, command, NULL, encrypted_filename, description_filename); switch (r) { case NO_ERROR_SMIME: break; case ERROR_SMIME_NOPASSPHRASE: case ERROR_SMIME_CHECK: res = MAIL_ERROR_COMMAND; goto unlink_description; break; case ERROR_SMIME_COMMAND: res = MAIL_ERROR_COMMAND; goto unlink_encrypted; case ERROR_SMIME_FILE: res = MAIL_ERROR_FILE; goto unlink_description; } /* encrypted part */ r = mailprivacy_get_part_from_file(privacy, 0, 0, encrypted_filename, &encrypted_mime); if (r != MAIL_NO_ERROR) { res = r; goto unlink_description; } strip_mime_headers(encrypted_mime); unlink(description_filename); unlink(encrypted_filename); unlink(decrypted_filename); * result = encrypted_mime; return MAIL_NO_ERROR; unlink_description: unlink(description_filename); unlink_encrypted: unlink(encrypted_filename); unlink_decrypted: unlink(decrypted_filename); err: return res; }
static int smime_sign(struct mailprivacy * privacy, mailmessage * msg, struct mailmime * mime, struct mailmime ** result) { char signed_filename[PATH_MAX]; FILE * signed_f; int res; int r; int col; char description_filename[PATH_MAX]; char signature_filename[PATH_MAX]; char command[PATH_MAX]; char quoted_signed_filename[PATH_MAX]; struct mailmime * signed_mime; char * smime_cert; char * smime_key; char quoted_smime_cert[PATH_MAX]; char quoted_smime_key[PATH_MAX]; char * email; /* get signing key */ email = get_first_from_addr(mime); if (email == NULL) { res = MAIL_ERROR_INVAL; goto err; } smime_key = get_private_key_file(email); smime_cert = get_cert_file(email); if ((smime_cert == NULL) || (smime_key == NULL)) { res = MAIL_ERROR_INVAL; goto err; } /* part to sign */ /* encode quoted printable all text parts */ mailprivacy_prepare_mime(mime); signed_f = mailprivacy_get_tmp_file(privacy, signed_filename, sizeof(signed_filename)); if (signed_f == NULL) { res = MAIL_ERROR_FILE; goto err; } col = 0; r = mailmime_write(signed_f, &col, mime); if (r != MAILIMF_NO_ERROR) { fclose(signed_f); res = MAIL_ERROR_FILE; goto unlink_signed; } fclose(signed_f); /* prepare destination file for signature */ r = mailprivacy_get_tmp_filename(privacy, signature_filename, sizeof(signature_filename)); if (r != MAIL_NO_ERROR) { res = r; goto unlink_signed; } r = mailprivacy_get_tmp_filename(privacy, description_filename, sizeof(description_filename)); if (r != MAIL_NO_ERROR) { res = r; goto unlink_signature; } r = mail_quote_filename(quoted_signed_filename, sizeof(quoted_signed_filename), signed_filename); if (r < 0) { res = MAIL_ERROR_MEMORY; goto unlink_description; } r = mail_quote_filename(quoted_smime_key, sizeof(quoted_smime_key), smime_key); if (r < 0) { res = MAIL_ERROR_MEMORY; goto unlink_description; } r = mail_quote_filename(quoted_smime_cert, sizeof(quoted_smime_cert), smime_cert); if (r < 0) { res = MAIL_ERROR_MEMORY; goto unlink_description; } snprintf(command, sizeof(command), "openssl smime -sign -passin fd:0 -in '%s' -signer '%s' -inkey '%s'", quoted_signed_filename, quoted_smime_cert, quoted_smime_key); r = smime_command_passphrase(privacy, msg, command, email, signature_filename, description_filename); switch (r) { case NO_ERROR_SMIME: break; case ERROR_SMIME_NOPASSPHRASE: case ERROR_SMIME_CHECK: res = MAIL_ERROR_COMMAND; goto unlink_description; break; case ERROR_SMIME_COMMAND: res = MAIL_ERROR_COMMAND; goto unlink_description; case ERROR_SMIME_FILE: res = MAIL_ERROR_FILE; goto unlink_description; } /* signature part */ r = mailprivacy_get_part_from_file(privacy, 0, 0, signature_filename, &signed_mime); if (r != MAIL_NO_ERROR) { res = r; goto unlink_description; } strip_mime_headers(signed_mime); unlink(description_filename); /* unlink(signature_filename); */ /* unlink(signed_filename); */ * result = signed_mime; return MAIL_NO_ERROR; unlink_description: unlink(description_filename); unlink_signature: unlink(signature_filename); unlink_signed: unlink(signed_filename); err: return res; }
static int smime_decrypt(struct mailprivacy * privacy, mailmessage * msg, struct mailmime * mime, struct mailmime ** result) { char smime_filename[PATH_MAX]; char quoted_smime_filename[PATH_MAX]; char description_filename[PATH_MAX]; char decrypted_filename[PATH_MAX]; char command[PATH_MAX]; struct mailmime * description_mime; struct mailmime * decrypted_mime; int r; int res; int sign_ok; struct mailmime * multipart; char * smime_cert; char * smime_key; char quoted_smime_cert[PATH_MAX]; char quoted_smime_key[PATH_MAX]; char * email; chashiter * iter; /* fetch the whole multipart and write it to a file */ r = mailprivacy_fetch_mime_body_to_file(privacy, smime_filename, sizeof(smime_filename), msg, mime); if (r != MAIL_NO_ERROR) { res = r; goto err; } /* we are in a safe directory */ r = mailprivacy_get_tmp_filename(privacy, decrypted_filename, sizeof(decrypted_filename)); if (r != MAIL_NO_ERROR) { res = MAIL_ERROR_FILE; goto unlink_smime; } /* description */ r = mailprivacy_get_tmp_filename(privacy, description_filename, sizeof(description_filename)); if (r != MAIL_NO_ERROR) { res = MAIL_ERROR_FILE; goto unlink_decrypted; } sign_ok = 0; for(iter = chash_begin(private_keys) ; iter != NULL ; iter = chash_next(private_keys, iter)) { chashdatum key; char email_buf[BUF_SIZE]; chash_key(iter, &key); if (key.len >= sizeof(email_buf)) continue; strncpy(email_buf, key.data, key.len); email_buf[key.len] = '\0'; email = email_buf; /* get encryption key */ smime_key = get_private_key_file(email); smime_cert = get_cert_file(email); if ((smime_cert == NULL) || (smime_key == NULL)) { res = MAIL_ERROR_INVAL; goto unlink_description; } r = mail_quote_filename(quoted_smime_cert, sizeof(quoted_smime_cert), smime_cert); if (r < 0) { res = MAIL_ERROR_MEMORY; goto unlink_description; } r = mail_quote_filename(quoted_smime_key, sizeof(quoted_smime_key), smime_key); if (r < 0) { res = MAIL_ERROR_MEMORY; goto unlink_description; } /* run the command */ r = mail_quote_filename(quoted_smime_filename, sizeof(quoted_smime_filename), smime_filename); if (r < 0) { res = MAIL_ERROR_MEMORY; goto unlink_description; } sign_ok = 0; snprintf(command, sizeof(command), "openssl smime -decrypt -passin fd:0 -in '%s' -inkey '%s' -recip '%s'", quoted_smime_filename, quoted_smime_key, quoted_smime_cert); unlink(description_filename); r = smime_command_passphrase(privacy, msg, command, email, decrypted_filename, description_filename); switch (r) { case NO_ERROR_SMIME: sign_ok = 1; break; case ERROR_SMIME_CHECK: case ERROR_SMIME_NOPASSPHRASE: sign_ok = 0; break; case ERROR_SMIME_COMMAND: res = MAIL_ERROR_COMMAND; goto unlink_description; case ERROR_SMIME_FILE: res = MAIL_ERROR_FILE; goto unlink_description; } if (sign_ok) { break; } } if (!sign_ok) { if (chash_count(private_keys) == 0) { FILE * description_f; description_f = mailprivacy_get_tmp_file(privacy, description_filename, sizeof(description_filename)); if (description_f == NULL) { res = MAIL_ERROR_FILE; goto unlink_decrypted; } fprintf(description_f, SMIME_DECRYPT_FAILED); fclose(description_f); } } else { mailprivacy_smime_encryption_id_list_clear(privacy, msg); } /* building multipart */ r = mailmime_new_with_content("multipart/x-decrypted", NULL, &multipart); if (r != MAILIMF_NO_ERROR) { res = MAIL_ERROR_MEMORY; goto unlink_description; } /* building the description part */ description_mime = mailprivacy_new_file_part(privacy, description_filename, "text/plain", MAILMIME_MECHANISM_8BIT); if (description_mime == NULL) { mailprivacy_mime_clear(multipart); mailmime_free(multipart); res = MAIL_ERROR_MEMORY; goto unlink_description; } /* adds the description part */ r = mailmime_smart_add_part(multipart, description_mime); if (r != MAIL_NO_ERROR) { mailprivacy_mime_clear(description_mime); mailmime_free(description_mime); mailprivacy_mime_clear(multipart); mailmime_free(multipart); res = MAIL_ERROR_MEMORY; goto unlink_description; } /* building the decrypted part */ r = mailprivacy_get_part_from_file(privacy, 1, 0, decrypted_filename, &decrypted_mime); if (r == MAIL_NO_ERROR) { /* adds the decrypted part */ r = mailmime_smart_add_part(multipart, decrypted_mime); if (r != MAIL_NO_ERROR) { mailprivacy_mime_clear(decrypted_mime); mailmime_free(decrypted_mime); mailprivacy_mime_clear(multipart); mailmime_free(multipart); res = MAIL_ERROR_MEMORY; goto unlink_description; } } unlink(description_filename); unlink(decrypted_filename); unlink(smime_filename); * result = multipart; return MAIL_NO_ERROR; unlink_description: unlink(description_filename); unlink_decrypted: unlink(decrypted_filename); unlink_smime: unlink(smime_filename); err: return res; }
void mailprivacy_smime_set_CA_dir(struct mailprivacy * privacy, char * directory) { DIR * dir; struct dirent * ent; FILE * f_CA; char CA_filename[PATH_MAX]; if (directory == NULL) return; if (* directory == '\0') return; /* make a temporary file that contains all the CAs */ if (CAfile != NULL) { unlink(CAfile); free(CAfile); CAfile = NULL; } f_CA = mailprivacy_get_tmp_file(privacy, CA_filename, sizeof(CA_filename)); if (f_CA == NULL) return; strncpy(CAcert_dir, directory, sizeof(CAcert_dir)); CAcert_dir[sizeof(CAcert_dir) - 1] = '\0'; dir = opendir(directory); if (dir == NULL) { fclose(f_CA); goto unlink_CA; } while ((ent = readdir(dir)) != NULL) { char filename[PATH_MAX]; char buf[MAX_BUF]; FILE * f; snprintf(filename, sizeof(filename), "%s/%s", directory, ent->d_name); f = fopen(filename, "r"); if (f == NULL) continue; while (fgets(buf, sizeof(buf), f) != NULL) fputs(buf, f_CA); fclose(f); } closedir(dir); fclose(f_CA); CAfile = strdup(CA_filename); if (CAfile == NULL) goto unlink_CA; return; unlink_CA: unlink(CA_filename); }