bool agent_load_key(unsigned char key[KDF_HASH_LEN]) { _cleanup_free_ char *iterationbuf = NULL; _cleanup_free_ char *verify = NULL; _cleanup_free_ char *username = NULL; _cleanup_free_ char *password = NULL; int iterations; iterationbuf = config_read_string("iterations"); username = config_read_string("username"); if (!iterationbuf || !username || !config_exists("verify")) return false; iterations = strtoul(iterationbuf, NULL, 10); if (iterations <= 0) return false; for (;;) { free(password); password = password_prompt("Master Password", password ? "Incorrect master password; please try again." : NULL, "Please enter the LastPass master password for <%s>.", username); if (!password) return false; kdf_decryption_key(username, password, iterations, key); /* no longer need password contents, zero it */ secure_clear_str(password); verify = config_read_encrypted_string("verify", key); if (verify && !strcmp(verify, AGENT_VERIFICATION_STRING)) break; } return true; }
bool agent_get_decryption_key(unsigned char key[KDF_HASH_LEN]) { char *disable_str; if (config_exists("plaintext_key")) { _cleanup_free_ char *key_buffer = NULL; if (config_read_buffer("plaintext_key", &key_buffer) == KDF_HASH_LEN) { _cleanup_free_ char *verify = config_read_encrypted_string("verify", (unsigned char *)key_buffer); if (!verify || strcmp(verify, AGENT_VERIFICATION_STRING)) goto badkey; memcpy(key, key_buffer, KDF_HASH_LEN); secure_clear(key_buffer, KDF_HASH_LEN); mlock(key, KDF_HASH_LEN); return true; } badkey: config_unlink("plaintext_key"); } if (!agent_ask(key)) { if (!agent_load_key(key)) return false; disable_str = getenv("LPASS_AGENT_DISABLE"); if (!disable_str || strcmp(disable_str, "1")) { agent_start(key); } } mlock(key, KDF_HASH_LEN); return true; }
static void agent_start(unsigned const char key[KDF_HASH_LEN]) { pid_t child; agent_kill(); if (config_exists("plaintext_key")) return; child = fork(); if (child < 0) die_errno("fork(agent)"); if (child == 0) { int null = open("/dev/null", 0); if (null < 0) _exit(EXIT_FAILURE); dup2(null, 0); dup2(null, 1); dup2(null, 2); close(null); setsid(); if (chdir("/") < 0) _exit(EXIT_FAILURE); process_disable_ptrace(); process_set_name("lpass [agent]"); agent_run(key); _exit(EXIT_FAILURE); } }
int create_listen_sockets(void) { listen_backlog = (int) config_get_number("global", "http port listen backlog", LISTEN_BACKLOG); if(config_exists("global", "bind socket to IP") && !config_exists("global", "bind to")) config_rename("global", "bind socket to IP", "bind to"); if(config_exists("global", "port") && !config_exists("global", "default port")) config_rename("global", "port", "default port"); listen_port = (int) config_get_number("global", "default port", LISTEN_PORT); if(listen_port < 1 || listen_port > 65535) { error("Invalid listen port %d given. Defaulting to %d.", listen_port, LISTEN_PORT); listen_port = (int) config_set_number("global", "default port", LISTEN_PORT); } debug(D_OPTIONS, "Default listen port set to %d.", listen_port); char *s = config_get("global", "bind to", "*"); while(*s) { char *e = s; // skip separators, moving both s(tart) and e(nd) while(isspace(*e) || *e == ',') s = ++e; // move e(nd) to the first separator while(*e && !isspace(*e) && *e != ',') e++; // is there anything? if(!*s || s == e) break; char buf[e - s + 1]; strncpyz(buf, s, e - s); bind_to_one(buf, listen_port, listen_backlog); s = e; } if(!listen_fds_count) fatal("Cannot listen on any socket. Exiting..."); return listen_fds_count; }
static void backwards_compatible_config() { // allow existing configurations to work with the current version of netdata if(config_exists(CONFIG_SECTION_GLOBAL, "multi threaded web server")) { int mode = config_get_boolean(CONFIG_SECTION_GLOBAL, "multi threaded web server", 1); web_server_mode = (mode)?WEB_SERVER_MODE_MULTI_THREADED:WEB_SERVER_MODE_SINGLE_THREADED; } // move [global] options to the [web] section config_move(CONFIG_SECTION_GLOBAL, "http port listen backlog", CONFIG_SECTION_WEB, "listen backlog"); config_move(CONFIG_SECTION_GLOBAL, "bind socket to IP", CONFIG_SECTION_WEB, "bind to"); config_move(CONFIG_SECTION_GLOBAL, "bind to", CONFIG_SECTION_WEB, "bind to"); config_move(CONFIG_SECTION_GLOBAL, "port", CONFIG_SECTION_WEB, "default port"); config_move(CONFIG_SECTION_GLOBAL, "default port", CONFIG_SECTION_WEB, "default port"); config_move(CONFIG_SECTION_GLOBAL, "disconnect idle web clients after seconds", CONFIG_SECTION_WEB, "disconnect idle clients after seconds"); config_move(CONFIG_SECTION_GLOBAL, "respect web browser do not track policy", CONFIG_SECTION_WEB, "respect do not track policy"); config_move(CONFIG_SECTION_GLOBAL, "web x-frame-options header", CONFIG_SECTION_WEB, "x-frame-options response header"); config_move(CONFIG_SECTION_GLOBAL, "enable web responses gzip compression", CONFIG_SECTION_WEB, "enable gzip compression"); config_move(CONFIG_SECTION_GLOBAL, "web compression strategy", CONFIG_SECTION_WEB, "gzip compression strategy"); config_move(CONFIG_SECTION_GLOBAL, "web compression level", CONFIG_SECTION_WEB, "gzip compression level"); config_move(CONFIG_SECTION_GLOBAL, "web files owner", CONFIG_SECTION_WEB, "web files owner"); config_move(CONFIG_SECTION_GLOBAL, "web files group", CONFIG_SECTION_WEB, "web files group"); config_move(CONFIG_SECTION_BACKEND, "opentsdb host tags", CONFIG_SECTION_BACKEND, "host tags"); }
struct blob *blob_load(enum blobsync sync, struct session *session, const unsigned char key[KDF_HASH_LEN]) { if (sync == BLOB_SYNC_AUTO) { if (!config_exists("blob")) return blob_get_latest(session, key); else if (time(NULL) - config_mtime("blob") <= auto_sync_time()) return local_blob(key, &session->private_key); return blob_get_latest(session, key); } else if (sync == BLOB_SYNC_YES) return blob_get_latest(session, key); else if (sync == BLOB_SYNC_NO) return local_blob(key, &session->private_key); return NULL; }
int cmd_logout(int argc, char **argv) { static struct option long_options[] = { {"force", no_argument, NULL, 'f'}, {0, 0, 0, 0} }; int option; int option_index; bool force = false; struct session *session = NULL; unsigned char key[KDF_HASH_LEN]; while ((option = getopt_long(argc, argv, "f", long_options, &option_index)) != -1) { switch (option) { case 'f': force = true; break; case '?': default: die_usage(cmd_logout_usage); } } if (optind < argc) die_usage(cmd_logout_usage); if (!config_exists("verify")) die("Not currently logged in."); if (!force && !ask_yes_no(true, "Are you sure you would like to log out?")) { terminal_printf(TERMINAL_FG_YELLOW TERMINAL_BOLD "Log out" TERMINAL_RESET ": aborted.\n"); return 1; } init_all(0, key, &session, NULL); if (!config_unlink("verify") || !config_unlink("username") || !config_unlink("session_sessionid") || !config_unlink("iterations")) die_errno("could not log out."); config_unlink("blob"); config_unlink("session_token"); config_unlink("session_uid"); config_unlink("session_privatekey"); config_unlink("plaintext_key"); agent_kill(); upload_queue_kill(); lastpass_logout(session); terminal_printf(TERMINAL_FG_YELLOW TERMINAL_BOLD "Log out" TERMINAL_RESET ": complete.\n"); return 0; }
static void upload_queue_write_entry(const char *entry, unsigned const char key[KDF_HASH_LEN]) { _cleanup_free_ char *name = NULL; unsigned long serial; make_upload_dir("upload-queue"); for (serial = 0; serial < ULONG_MAX; ++serial) { free(name); xasprintf(&name, "upload-queue/%lu%04lu", time(NULL), serial); if (!config_exists(name)) break; } if (serial == ULONG_MAX) die("No more upload queue entry slots available."); config_write_encrypted_string(name, entry, key); }
/* * Destroys directory config and file config. */ void config_destroy(char *path) { int ret; char *config_path; config_path = config_get_file_path(path); if (config_path == NULL) { return; } if (!config_exists(config_path)) { goto end; } DBG("Removing %s\n", config_path); ret = remove(config_path); if (ret < 0) { perror("remove config file"); } end: free(config_path); }
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; }