static struct blob *blob_get_latest(struct session *session, const unsigned char key[KDF_HASH_LEN]) { struct blob *local; unsigned long long remote_version; local = local_blob(key, &session->private_key); if (!local) return lastpass_get_blob(session, key); remote_version = lastpass_get_blob_version(session, key); if (remote_version == 0) { blob_free(local); return NULL; } if (local->version < remote_version || (local->local_version && local->version == remote_version)) { blob_free(local); return lastpass_get_blob(session, key); } config_touch("blob"); return local; }
static void upload_queue_upload_all(const struct session *session, unsigned const char key[KDF_HASH_LEN]) { char *entry, *next_entry, *result; int size; char **argv = NULL; char **argv_ptr; char *name, *lock, *p; bool do_break; bool should_fetch_new_blob_after = false; int curl_ret; long http_code; bool http_failed_all; int backoff; while ((entry = upload_queue_next_entry(key, &name, &lock))) { size = 0; for (p = entry; *p; ++p) { if (*p == '\n') ++size; } if (p > entry && p[-1] != '\n') ++size; if (size < 1) { config_unlink(name); config_unlink(lock); goto end; } argv_ptr = argv = xcalloc(size + 1, sizeof(char **)); for (do_break = false, p = entry, next_entry = entry; ; ++p) { if (!*p) do_break = true; if (*p == '\n' || !*p) { *p = '\0'; *(argv_ptr++) = pinentry_unescape(next_entry); next_entry = p + 1; if (do_break) break; } } argv[size] = NULL; http_failed_all = true; backoff = 1; for (int i = 0; i < 5; ++i) { if (i) { sleep(backoff); backoff *= 8; } result = http_post_lastpass_v_noexit(argv[0], session->sessionid, NULL, &argv[1], &curl_ret, &http_code); http_failed_all &= (curl_ret == HTTP_ERROR_CODE || curl_ret == HTTP_ERROR_CONNECT); if (result && strlen(result)) should_fetch_new_blob_after = true; free(result); if (result) break; } if (!result) { /* server failed response 5 times, remove it */ if (http_failed_all) upload_queue_drop(name); config_unlink(lock); } else { config_unlink(name); config_unlink(lock); } for (argv_ptr = argv; *argv_ptr; ++argv_ptr) free(*argv_ptr); free(argv); end: free(name); free(lock); free(entry); } if (should_fetch_new_blob_after) blob_free(lastpass_get_blob(session, key)); }