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; }
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 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; }