1 // This file is under GNU General Public License 3.0
4 #include "pEp_internal.h"
5 #include "dynamic_api.h"
6 #include "message_api.h"
11 PEP_STATUS has_key_reset_been_sent(
14 const char* revoked_fpr,
21 assert(!EMPTYSTR(user_id));
23 if (!session || !contacted || EMPTYSTR(revoked_fpr) || EMPTYSTR(user_id))
24 return PEP_ILLEGAL_VALUE;
28 char* alias_default = NULL;
30 PEP_STATUS status = get_userid_alias_default(session, user_id, &alias_default);
32 if (status == PEP_CANNOT_FIND_ALIAS || EMPTYSTR(alias_default)) {
34 alias_default = strdup(user_id);
37 sqlite3_reset(session->was_id_for_revoke_contacted);
38 sqlite3_bind_text(session->was_id_for_revoke_contacted, 1, revoked_fpr, -1,
40 sqlite3_bind_text(session->was_id_for_revoke_contacted, 2, user_id, -1,
42 int result = Sqlite3_step(session->was_id_for_revoke_contacted);
45 *contacted = (sqlite3_column_int(session->was_id_for_revoke_contacted, 0) != 0);
49 sqlite3_reset(session->was_id_for_revoke_contacted);
51 return PEP_UNKNOWN_DB_ERROR;
54 sqlite3_reset(session->was_id_for_revoke_contacted);
58 //static const char *sql_set_revoke_contact_as_notified =
59 // "insert or replace into revocation_contact_list(fpr, contact_id) values (?1, ?2) ;";
61 PEP_STATUS set_reset_contact_notified(
63 const char* revoke_fpr,
64 const char* contact_id
67 PEP_STATUS status = PEP_STATUS_OK;
69 assert(session && !EMPTYSTR(revoke_fpr) && !EMPTYSTR(contact_id));
71 if (!session || EMPTYSTR(revoke_fpr) || EMPTYSTR(contact_id))
72 return PEP_ILLEGAL_VALUE;
74 sqlite3_reset(session->set_revoke_contact_as_notified);
75 sqlite3_bind_text(session->set_revoke_contact_as_notified, 1, revoke_fpr, -1,
77 sqlite3_bind_text(session->set_revoke_contact_as_notified, 2, contact_id, -1,
82 result = Sqlite3_step(session->set_revoke_contact_as_notified);
85 status = PEP_STATUS_OK;
89 status = PEP_UNKNOWN_DB_ERROR;
92 sqlite3_reset(session->set_revoke_contact_as_notified);
97 PEP_STATUS receive_key_reset(PEP_SESSION session,
100 if (!session || !reset_msg)
101 return PEP_ILLEGAL_VALUE;
103 pEp_identity* sender_id = reset_msg->from;
106 return PEP_MALFORMED_KEY_RESET_MSG;
108 PEP_STATUS status = update_identity(session, sender_id);
109 if (!sender_id->user_id)
110 return PEP_UNKNOWN_ERROR;
112 if (is_me(session, sender_id))
113 return PEP_ILLEGAL_VALUE;
115 if (!reset_msg->longmsg || strncmp(reset_msg->longmsg, "OLD: ", 5) != 0)
116 return PEP_MALFORMED_KEY_RESET_MSG;
118 status = PEP_STATUS_OK;
119 char* old_fpr = NULL;
120 char* new_fpr = NULL;
122 stringlist_t* keylist = NULL;
123 pEp_identity* temp_ident = identity_dup(sender_id);
125 status = PEP_OUT_OF_MEMORY;
130 char* p = strtok_r(reset_msg->longmsg, "\r\n", &rest);
131 if (!EMPTYSTR(p + 5))
132 old_fpr = strdup(p + 5);
134 status = PEP_MALFORMED_KEY_RESET_MSG;
138 bool own_key = false;
139 status = is_own_key(session, old_fpr, &own_key);
142 // Nope, no one can make us our own default. If we want to do that,
143 // that's keysync, NOT key reset.
144 status = PEP_ILLEGAL_VALUE;
148 p = strtok_r(NULL, "\r\n", &rest);
149 if (strncmp(p, "NEW: ", 5) != 0 || EMPTYSTR(p + 5)) {
150 status = PEP_MALFORMED_KEY_RESET_MSG;
154 new_fpr = strdup(p + 5);
156 // Reset the original key
157 status = key_reset(session, old_fpr, temp_ident);
158 if (status != PEP_STATUS_OK)
161 status = find_keys(session, new_fpr, &keylist);
162 if (status != PEP_STATUS_OK)
166 status = PEP_KEY_NOT_FOUND;
170 // alright, we've checked as best we can. Let's set that baby.
171 sender_id->fpr = new_fpr;
173 // This only sets as the default, does NOT TRUST IN ANY WAY
174 sender_id->comm_type = sender_id->comm_type & (~PEP_ct_confirmed);
175 status = set_identity(session, sender_id);
177 sender_id->fpr = NULL; // ownership for free
179 free_stringlist(keylist);
182 free_identity(temp_ident);
186 PEP_STATUS create_standalone_key_reset_message(PEP_SESSION session,
190 const char* new_fpr) {
192 if (!dst || !recip->user_id || !recip->address)
193 return PEP_ILLEGAL_VALUE;
195 if (!old_fpr || !new_fpr)
196 return PEP_ILLEGAL_VALUE;
199 // Get own identity user has corresponded with
200 pEp_identity* own_identity = NULL;
202 PEP_STATUS status = get_own_ident_for_contact_id(session,
205 if (status != PEP_STATUS_OK)
208 message* reset_message = new_message(PEP_dir_outgoing);
209 reset_message->from = own_identity;
210 reset_message->to = new_identity_list(identity_dup(recip)); // ?
212 const char* oldtag = "OLD: ";
213 const char* newtag = "\nNEW: ";
214 const size_t taglens = 11;
215 size_t full_len = taglens + strlen(old_fpr) + strlen(new_fpr) + 2; // \n and \0
216 char* longmsg = calloc(full_len, 1);
217 strlcpy(longmsg, oldtag, full_len);
218 strlcat(longmsg, old_fpr, full_len);
219 strlcat(longmsg, newtag, full_len);
220 strlcat(longmsg, new_fpr, full_len);
221 strlcat(longmsg, "\n", full_len);
222 reset_message->longmsg = longmsg;
223 reset_message->shortmsg = strdup("Key reset");
225 message* output_msg = NULL;
227 status = encrypt_message(session, reset_message, NULL,
228 &output_msg, PEP_enc_PGP_MIME,
229 PEP_encrypt_flag_key_reset_only);
231 if (status == PEP_STATUS_OK)
234 free_message(reset_message);
238 PEP_STATUS send_key_reset_to_recents(PEP_SESSION session,
240 const char* new_fpr) {
244 assert(session->messageToSend);
246 if (!session || !old_fpr || !new_fpr)
247 return PEP_ILLEGAL_VALUE;
249 messageToSend_t send_cb = session->messageToSend;
251 return PEP_SYNC_NO_MESSAGE_SEND_CALLBACK;
253 identity_list* recent_contacts = NULL;
254 message* reset_msg = NULL;
256 PEP_STATUS status = get_last_contacted(session, &recent_contacts);
258 if (status != PEP_STATUS_OK)
261 identity_list* curr_id_ptr = recent_contacts;
263 for (curr_id_ptr = recent_contacts; curr_id_ptr; curr_id_ptr = curr_id_ptr->next) {
264 pEp_identity* curr_id = curr_id_ptr->ident;
269 const char* user_id = curr_id->user_id;
271 // Should be impossible, but?
275 // Check if it's us - if so, pointless...
276 if (is_me(session, curr_id))
279 // Check if they've already been told - this shouldn't be the case, but...
280 bool contacted = false;
281 status = has_key_reset_been_sent(session, user_id, old_fpr, &contacted);
282 if (status != PEP_STATUS_OK)
288 // if not, make em a message
291 status = create_standalone_key_reset_message(session,
297 if (status == PEP_CANNOT_FIND_IDENTITY) { // this is ok, just means we never mailed them
298 status = PEP_STATUS_OK;
302 if (status != PEP_STATUS_OK) {
308 status = send_cb(reset_msg);
310 if (status != PEP_STATUS_OK) {
315 // Put into notified DB
316 status = set_reset_contact_notified(session, old_fpr, user_id);
317 if (status != PEP_STATUS_OK)
322 free_identity_list(recent_contacts);
326 DYNAMIC_API PEP_STATUS key_reset_identity(
332 if (!session || !ident || (ident && (EMPTYSTR(ident->user_id) || EMPTYSTR(ident->address))))
333 return PEP_ILLEGAL_VALUE;
335 return key_reset(session, fpr, ident);
338 DYNAMIC_API PEP_STATUS key_reset_user(
344 if (!session || EMPTYSTR(user_id))
345 return PEP_ILLEGAL_VALUE;
347 pEp_identity* input_ident = new_identity(NULL, NULL, user_id, NULL);
349 return PEP_OUT_OF_MEMORY;
351 if (is_me(session, input_ident) && EMPTYSTR(fpr))
352 return PEP_ILLEGAL_VALUE;
354 PEP_STATUS status = key_reset(session, fpr, input_ident);
355 free_identity(input_ident);
359 DYNAMIC_API PEP_STATUS key_reset_all_own_keys(PEP_SESSION session) {
360 return key_reset(session, NULL, NULL);
363 // Notes to integrate into header:
364 // IF there is an ident, it must have a user_id.
365 PEP_STATUS key_reset(
371 if (!session || (ident && EMPTYSTR(ident->user_id)))
372 return PEP_ILLEGAL_VALUE;
374 PEP_STATUS status = PEP_STATUS_OK;
376 char* fpr_copy = NULL;
378 char* user_id = NULL;
379 char* new_key = NULL;
380 pEp_identity* tmp_ident = NULL;
381 identity_list* key_idents = NULL;
382 stringlist_t* keys = NULL;
384 if (!EMPTYSTR(key_id)) {
385 fpr_copy = strdup(key_id);
387 return PEP_OUT_OF_MEMORY;
390 // This is true when we don't have a user_id and address and the fpr isn't specified
391 bool reset_all_for_user = !fpr_copy && (!ident || EMPTYSTR(ident->address));
393 // FIXME: does this need to be done everywhere?> I think not.
395 user_id = strdup(ident->user_id);
397 status = PEP_OUT_OF_MEMORY;
402 status = get_default_own_userid(session, &user_id);
403 if (status != PEP_STATUS_OK || !user_id)
407 // FIXME: Make sure this can't result in a double-free in recursive calls
408 tmp_ident = (ident ? identity_dup(ident) : new_identity(NULL, NULL, user_id, NULL));
410 if (reset_all_for_user) {
411 status = get_all_keys_for_user(session, user_id, &keys);
413 if (status == PEP_STATUS_OK) {
414 stringlist_t* curr_key;
416 for (curr_key = keys; curr_key && curr_key->value; curr_key = curr_key->next) {
417 // FIXME: Is the ident really necessary?
418 status = key_reset(session, curr_key->value, tmp_ident);
419 if (status != PEP_STATUS_OK)
426 // tmp_ident => tmp_ident->user_id (was checked)
428 // !(EMPTYSTR(fpr) && (!tmp_ident || EMPTYSTR(tmp_ident->address)))
429 // => fpr || (tmp_ident && tmp_ident->address)
431 // so: We have an fpr or we have an ident with user_id and address
434 // We are guaranteed to have an ident w/ id + addr here.
435 // Get the default key.
436 pEp_identity* stored_ident = NULL;
437 status = get_identity(session, tmp_ident->address,
438 tmp_ident->user_id, &stored_ident);
441 if (status == PEP_STATUS_OK) {
442 // transfer ownership
443 fpr_copy = stored_ident->fpr;
444 stored_ident->fpr = NULL;
445 free_identity(stored_ident);
448 if (!fpr_copy || status == PEP_CANNOT_FIND_IDENTITY) {
449 // There's no identity default. Try resetting user default
450 status = get_user_default_key(session, tmp_ident->user_id, &fpr_copy);
453 if (!fpr_copy || status != PEP_STATUS_OK) // No default to free. We're done here.
457 // Ok - now we have at least an ident with user_id and an fpr.
458 // Now it matters if we're talking about ourselves or a partner.
459 bool is_own_private = false;
460 if (is_me(session, tmp_ident)) {
461 bool own_key = false;
462 status = is_own_key(session, fpr_copy, &own_key);
464 if (status != PEP_STATUS_OK)
467 status = PEP_ILLEGAL_VALUE;
471 status = contains_priv_key(session, fpr_copy, &is_own_private);
472 if (status != PEP_STATUS_OK && status != PEP_KEY_NOT_FOUND)
476 // Up to this point, we haven't cared about whether or not we
477 // had a full identity. Now we have to deal with that in the
478 // case of own identities with private keys.
480 if (is_own_private) {
482 // If there's no address, we want to reset this key for every identity
483 // it's a part of. Since this means generating new keys, we have to
484 // grab all the identities associated with it.
485 if (EMPTYSTR(tmp_ident->address)) {
486 status = get_identities_by_main_key_id(session, fpr_copy, &key_idents);
488 if (status != PEP_CANNOT_FIND_IDENTITY) {
489 if (status == PEP_STATUS_OK) {
490 // now have ident list, or should
491 identity_list* curr_ident;
493 for (curr_ident = key_idents; curr_ident && curr_ident->ident;
494 curr_ident = curr_ident->next) {
496 pEp_identity* this_identity = curr_ident->ident;
497 // Do the full reset on this identity
498 status = key_reset(session, fpr_copy, this_identity);
500 // Ident list gets freed below, do not free here!
502 if (status != PEP_STATUS_OK)
507 // Ok, we've either now reset for each own identity with this key, or
508 // we got an error and want to bail anyway.
514 status = revoke_key(session, fpr_copy, NULL);
516 // If we have a full identity, we have some cleanup and generation tasks here
517 if (!EMPTYSTR(tmp_ident->address)) {
519 if (status == PEP_STATUS_OK) {
520 tmp_ident->fpr = NULL;
521 status = generate_keypair(session, tmp_ident);
523 if (status == PEP_STATUS_OK) {
524 new_key = strdup(tmp_ident->fpr);
525 status = set_own_key(session, tmp_ident, new_key);
527 // mistrust fpr from trust
528 tmp_ident->fpr = fpr_copy;
530 tmp_ident->comm_type = PEP_ct_mistrusted;
531 status = set_trust(session, tmp_ident);
532 tmp_ident->fpr = NULL;
534 // Done with old use of ident.
535 if (status == PEP_STATUS_OK) {
536 // Update fpr for outgoing
537 status = myself(session, tmp_ident);
541 if (status == PEP_STATUS_OK)
542 // cascade that mistrust for anyone using this key
543 status = mark_as_compromised(session, fpr_copy);
545 if (status == PEP_STATUS_OK)
546 status = remove_fpr_as_default(session, fpr_copy);
547 if (status == PEP_STATUS_OK)
548 status = add_mistrusted_key(session, fpr_copy);
550 // If there's a new key, do the DB linkage with the revoked one, and
551 // send the key reset mail opportunistically to recently contacted
554 // add to revocation list
555 if (status == PEP_STATUS_OK)
556 status = set_revoked(session, fpr_copy, new_key, time(NULL));
557 // for all active communication partners:
558 // active_send revocation
559 if (status == PEP_STATUS_OK)
560 status = send_key_reset_to_recents(session, fpr_copy, new_key);
562 } // end is_own_private
564 // This is a public key (or a private key that isn't ours, which means
565 // we want it gone anyway)
567 // Delete this key from the keyring.
568 status = delete_keypair(session, fpr_copy);
571 // REGARDLESS OF WHO OWNS THE KEY, WE NOW NEED TO REMOVE IT AS A DEFAULT.
572 PEP_STATUS cached_status = status;
573 // remove fpr from all identities
574 // remove fpr from all users
575 status = remove_fpr_as_default(session, fpr_copy);
576 // delete key from DB - this does NOT touch the keyring!
577 // Note: for own priv keys, we cannot do this. But we'll never encrypt to/from it.
578 if (status == PEP_STATUS_OK && !is_own_private) {
579 status = remove_key(session, fpr_copy);
581 if (status == PEP_STATUS_OK)
582 status = cached_status;
587 free_identity(tmp_ident);
590 free_identity_list(key_idents);
591 free_stringlist(keys);