static void upload_queue_run(const struct session *session, unsigned const char key[KDF_HASH_LEN]) { _cleanup_free_ char *pid = NULL; upload_queue_kill(); pid_t child = fork(); if (child < 0) die_errno("fork(agent)"); if (child == 0) { int null = open("/dev/null", 0); if (null >= 0) { dup2(null, 0); dup2(null, 1); dup2(null, 2); close(null); } setsid(); IGNORE_RESULT(chdir("/")); process_set_name("lpass [upload queue]"); signal(SIGHUP, upload_queue_cleanup); signal(SIGINT, upload_queue_cleanup); signal(SIGQUIT, upload_queue_cleanup); signal(SIGTERM, upload_queue_cleanup); signal(SIGALRM, upload_queue_cleanup); upload_queue_upload_all(session, key); upload_queue_cleanup(0); _exit(EXIT_SUCCESS); } pid = xultostr(child); config_write_string("uploader.pid", pid); }
void agent_save(const char *username, int iterations, unsigned const char key[KDF_HASH_LEN]) { _cleanup_free_ char *iterations_str = xultostr(iterations); config_write_string("iterations", iterations_str); config_write_string("username", username); config_write_encrypted_string("verify", AGENT_VERIFICATION_STRING, key); agent_start(key); }
static void upload_queue_run(const struct session *session, unsigned const char key[KDF_HASH_LEN]) { _cleanup_free_ char *pid = NULL; upload_queue_kill(); pid_t child = fork(); if (child < 0) die_errno("fork(agent)"); if (child == 0) { _cleanup_free_ char *upload_log_path = NULL; int null = open("/dev/null", 0); int upload_log = null; if (lpass_log_level() >= 0) { upload_log_path = config_path("lpass.log"); upload_log = open(upload_log_path, O_WRONLY | O_CREAT | O_APPEND, 0600); } if (null >= 0) { dup2(null, 0); dup2(upload_log, 1); dup2(null, 2); close(null); close(upload_log); } setsid(); IGNORE_RESULT(chdir("/")); process_set_name("lpass [upload queue]"); signal(SIGHUP, upload_queue_cleanup); signal(SIGINT, upload_queue_cleanup); signal(SIGQUIT, upload_queue_cleanup); signal(SIGTERM, upload_queue_cleanup); signal(SIGALRM, upload_queue_cleanup); setvbuf(stdout, NULL, _IOLBF, 0); if (http_init()) { lpass_log(LOG_ERROR, "UQ: unable to restart curl\n"); _exit(EXIT_FAILURE); } lpass_log(LOG_DEBUG, "UQ: starting queue run\n"); upload_queue_upload_all(session, key); lpass_log(LOG_DEBUG, "UQ: queue run complete\n"); upload_queue_cleanup(0); _exit(EXIT_SUCCESS); } pid = xultostr(child); config_write_string("uploader.pid", pid); }
static void write_share_chunk(struct buffer *buffer, struct share *share) { struct buffer sharebuf = { .bytes = share->chunk, .len = share->chunk_len, .max = share->chunk_len }; write_chunk(buffer, &sharebuf, "SHAR"); } size_t blob_write(const struct blob *blob, const unsigned char key[KDF_HASH_LEN], char **out) { struct buffer buffer; struct share *last_share = NULL; _cleanup_free_ char *version; memset(&buffer, 0, sizeof(buffer)); version = xultostr(blob->version); buffer_append(&buffer, "LPAV", 4); write_plain_string(&buffer, version); buffer_append(&buffer, "LOCL", 4); write_plain_string(&buffer, LASTPASS_CLI_VERSION); for (struct account *account = blob->account_head; account; account = account->next) { if (!account->share) write_account_chunk(&buffer, account, key); } for (struct account *account = blob->account_head; account; account = account->next) { if (!account->share) continue; if (last_share != account->share) { write_share_chunk(&buffer, account->share); last_share = account->share; } write_account_chunk(&buffer, account, account->share->key); } *out = buffer.bytes; return buffer.len; } static struct blob *local_blob(const unsigned char key[KDF_HASH_LEN], const struct private_key *private_key) { _cleanup_free_ char *blob = NULL; size_t len = config_read_encrypted_buffer("blob", &blob, key); if (!blob) return NULL; return blob_parse(blob, len, key, private_key); }
static char *upload_queue_next_entry(unsigned const char key[KDF_HASH_LEN], char **name, char **lock) { unsigned long long smallest = ULLONG_MAX, current; _cleanup_free_ char *smallest_name = NULL; _cleanup_free_ char *base_path = config_path("upload-queue"); _cleanup_free_ char *pidstr = NULL; pid_t pid; char *result, *p; DIR *dir = opendir(base_path); struct dirent *entry; if (!dir) return NULL; while ((entry = readdir(dir))) { if (entry->d_type != DT_REG) continue; for (p = entry->d_name; *p; ++p) { if (!isdigit(*p)) break; } if (*p) continue; current = strtoull(entry->d_name, NULL, 10); if (!current) continue; if (current < smallest) { smallest = current; free(smallest_name); smallest_name = xstrdup(entry->d_name); } } closedir(dir); if (smallest == ULLONG_MAX) return NULL; xasprintf(name, "upload-queue/%s", smallest_name); xasprintf(lock, "%s.lock", *name); while (config_exists(*lock)) { free(pidstr); pidstr = config_read_encrypted_string(*lock, key); if (!pidstr) { config_unlink(*lock); break; } pid = strtoul(pidstr, NULL, 10); if (!pid) { config_unlink(*lock); break; } if (process_is_same_executable(pid)) sleep(1); else { config_unlink(*lock); break; } } free(pidstr); pidstr = xultostr(getpid()); config_write_encrypted_string(*lock, pidstr, key); result = config_read_encrypted_string(*name, key); if (!result) { /* could not decrypt: drop this file */ upload_queue_drop(*name); config_unlink(*lock); return NULL; } return result; }