static int smime_sign_encrypt(struct mailprivacy * privacy, mailmessage * msg, struct mailmime * mime, struct mailmime ** result) { struct mailmime * signed_part; struct mailmime * encrypted; int r; int res; r = smime_sign(privacy, msg, mime, &signed_part); if (r != MAIL_NO_ERROR) { res = r; goto err; } r = smime_encrypt(privacy, msg, signed_part, &encrypted); if (r != MAIL_NO_ERROR) { res = r; goto free_signed; } * result = encrypted; return MAIL_NO_ERROR; free_signed: mailprivacy_mime_clear(signed_part); mailmime_free(signed_part); err: return res; }
void mailprivacy_mime_clear(struct mailmime * mime) { struct mailmime_data * data; clistiter * cur; switch (mime->mm_type) { case MAILMIME_SINGLE: data = mime->mm_data.mm_single; if (data != NULL) { if (data->dt_type == MAILMIME_DATA_FILE) unlink(data->dt_data.dt_filename); } break; case MAILMIME_MULTIPLE: data = mime->mm_data.mm_multipart.mm_preamble; if (data != NULL) { if (data->dt_type == MAILMIME_DATA_FILE) unlink(data->dt_data.dt_filename); } data = mime->mm_data.mm_multipart.mm_epilogue; if (data != NULL) { if (data->dt_type == MAILMIME_DATA_FILE) unlink(data->dt_data.dt_filename); } for(cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailmime * submime; submime = clist_content(cur); mailprivacy_mime_clear(submime); } break; case MAILMIME_MESSAGE: if (mime->mm_data.mm_message.mm_msg_mime != NULL) { mailprivacy_mime_clear(mime->mm_data.mm_message.mm_msg_mime); } break; } }
int mailprivacy_get_mime(struct mailprivacy * privacy, int check_privacy, int reencode, char * content, size_t content_len, struct mailmime ** result_mime) { struct mailmime * mime; mailmessage * msg; int r; int res; #if 0 int check_privacy; check_privacy = (privacy != NULL); #endif /* use message data driver, get bodystructure and convert all the data part in MAILMIME_SINGLE to files. */ msg = data_message_init(content, content_len); if (msg == NULL) { res = MAIL_ERROR_MEMORY; goto err; } #if 0 if (msg->mime == NULL) { if (check_privacy) { r = mailprivacy_msg_get_bodystructure(privacy, msg, &mime); } else { /* don't use etpan_msg_get_bodystructure because it is not useful and to avoid loops due to security part */ r = mailmessage_get_bodystructure(msg, &mime); } } else { mime = msg->mime; } #endif if (check_privacy) r = mailprivacy_msg_get_bodystructure(privacy, msg, &mime); else r = mailmessage_get_bodystructure(msg, &mime); if (r != MAIL_NO_ERROR) { res = r; goto free_msg; } /* should be done so that the MIME structure need not to be unregistered. */ mailprivacy_recursive_unregister_mime(privacy, mime); r = recursive_replace_single_parts(privacy, mime, reencode); if (r != MAIL_NO_ERROR) { res = r; goto clear_mime; } data_message_detach_mime(msg); #if 0 if (check_privacy) mailprivacy_msg_flush(privacy, msg); else mailmessage_flush(msg); #endif mailprivacy_msg_flush(privacy, msg); mailmessage_free(msg); * result_mime = mime; return MAIL_NO_ERROR; clear_mime: mailprivacy_mime_clear(mime); mailprivacy_msg_flush(privacy, msg); free_msg: mailmessage_free(msg); err: return res; }
static int smime_verify(struct mailprivacy * privacy, mailmessage * msg, struct mailmime * mime, struct mailmime ** result) { char smime_filename[PATH_MAX]; char quoted_smime_filename[PATH_MAX]; int res; int r; char command[PATH_MAX]; int sign_ok; struct mailmime * description_mime; char description_filename[PATH_MAX]; struct mailmime * multipart; char stripped_filename[PATH_MAX]; struct mailmime * stripped_mime; char check_CA[PATH_MAX]; char quoted_CAfile[PATH_MAX]; char noverify[PATH_MAX]; if (store_cert) get_cert_from_sig(privacy, msg, mime); * check_CA = '\0'; if (CAfile != NULL) { r = mail_quote_filename(quoted_CAfile, sizeof(quoted_CAfile), CAfile); if (r < 0) { res = MAIL_ERROR_MEMORY; goto err; } snprintf(check_CA, sizeof(check_CA), "-CAfile '%s'", quoted_CAfile); } * noverify = '\0'; if (!CA_check) { snprintf(noverify, sizeof(noverify), "-noverify"); } /* 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; } r = mailprivacy_get_tmp_filename(privacy,stripped_filename, sizeof(stripped_filename)); if (r != MAIL_NO_ERROR) { res = r; goto unlink_smime; } /* description */ r = mailprivacy_get_tmp_filename(privacy, description_filename, sizeof(description_filename)); if (r != MAIL_NO_ERROR) { res = r; goto unlink_stripped; } /* 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 -verify -in '%s' %s %s", quoted_smime_filename, check_CA, noverify); r = smime_command_passphrase(privacy, msg, command, NULL, stripped_filename, description_filename); switch (r) { case NO_ERROR_SMIME: sign_ok = 1; break; case ERROR_SMIME_NOPASSPHRASE: case ERROR_SMIME_CHECK: 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; } /* building multipart */ r = mailmime_new_with_content("multipart/x-verified", 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; } /* insert the signed part */ if (!sign_ok) { if (mime->mm_type == MAILMIME_MULTIPLE) { clistiter * child_iter; struct mailmime * child; child_iter = clist_begin(mime->mm_data.mm_multipart.mm_mp_list); child = clist_content(child_iter); r = mailprivacy_fetch_mime_body_to_file(privacy, stripped_filename, sizeof(stripped_filename), msg, child); } } r = mailprivacy_get_part_from_file(privacy, 1, 0, stripped_filename, &stripped_mime); if (r != MAIL_NO_ERROR) { mailprivacy_mime_clear(multipart); mailmime_free(multipart); res = r; goto unlink_description; } r = mailmime_smart_add_part(multipart, stripped_mime); if (r != MAIL_NO_ERROR) { mailprivacy_mime_clear(stripped_mime); mailmime_free(stripped_mime); mailprivacy_mime_clear(multipart); mailmime_free(multipart); res = MAIL_ERROR_MEMORY; goto unlink_description; } unlink(description_filename); unlink(stripped_filename); /* unlink(smime_filename); */ * result = multipart; return MAIL_NO_ERROR; unlink_description: unlink(description_filename); unlink_stripped: unlink(stripped_filename); unlink_smime: unlink(smime_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; }
static int recursive_check_privacy(struct mailprivacy * privacy, mailmessage * msg, struct mailmime * mime) { int r; clistiter * cur; struct mailmime * alternative; int res; struct mailmime * multipart; if (privacy == NULL) return MAIL_NO_ERROR; if (mime_is_registered(privacy, mime)) return MAIL_ERROR_INVAL; r = privacy_handler(privacy, msg, mime, &alternative); if (r == MAIL_NO_ERROR) { if (privacy->make_alternative) { multipart = mime_add_alternative(privacy, msg, mime, alternative); if (multipart == NULL) { mailprivacy_mime_clear(alternative); mailmime_free(alternative); return MAIL_ERROR_MEMORY; } } else { mailmime_substitute(mime, alternative); mailmime_free(mime); mime = NULL; } return MAIL_NO_ERROR; } else { switch (mime->mm_type) { case MAILMIME_SINGLE: return MAIL_ERROR_INVAL; case MAILMIME_MULTIPLE: res = MAIL_ERROR_INVAL; for(cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailmime * child; child = clist_content(cur); r = recursive_check_privacy(privacy, msg, child); if (r == MAIL_NO_ERROR) res = MAIL_NO_ERROR; } return res; case MAILMIME_MESSAGE: if (mime->mm_data.mm_message.mm_msg_mime != NULL) return recursive_check_privacy(privacy, msg, mime->mm_data.mm_message.mm_msg_mime); return MAIL_ERROR_INVAL; default: return MAIL_ERROR_INVAL; } } }
static struct mailmime * mime_add_alternative(struct mailprivacy * privacy, mailmessage * msg, struct mailmime * mime, struct mailmime * alternative) { struct mailmime * multipart; int r; struct mailmime * mime_copy; char original_filename[PATH_MAX]; if (mime->mm_parent == NULL) goto err; r = mailmime_new_with_content("multipart/alternative", NULL, &multipart); if (r != MAILIMF_NO_ERROR) goto err; r = mailmime_smart_add_part(multipart, alternative); if (r != MAILIMF_NO_ERROR) { goto free_multipart; } /* get copy of mime part "mime" and set parts */ r = mailprivacy_fetch_mime_body_to_file(privacy, original_filename, sizeof(original_filename), msg, mime); if (r != MAIL_NO_ERROR) goto detach_alternative; r = mailprivacy_get_part_from_file(privacy, 0, 0, original_filename, &mime_copy); unlink(original_filename); if (r != MAIL_NO_ERROR) { goto detach_alternative; } r = mailmime_smart_add_part(multipart, mime_copy); if (r != MAILIMF_NO_ERROR) { goto free_mime_copy; } r = recursive_register_mime(privacy, multipart); if (r != MAIL_NO_ERROR) goto detach_mime_copy; mailmime_substitute(mime, multipart); mailmime_free(mime); return multipart; detach_mime_copy: mailprivacy_recursive_unregister_mime(privacy, multipart); mailmime_remove_part(alternative); free_mime_copy: mailprivacy_mime_clear(mime_copy); mailmime_free(mime_copy); detach_alternative: mailmime_remove_part(alternative); free_multipart: mailmime_free(multipart); err: return NULL; }