int cmd_rm(int argc, char **argv) { unsigned char key[KDF_HASH_LEN]; struct session *session = NULL; struct blob *blob = NULL; static struct option long_options[] = { {"sync", required_argument, NULL, 'S'}, {"color", required_argument, NULL, 'C'}, {0, 0, 0, 0} }; int option; int option_index; char *name; enum blobsync sync = BLOB_SYNC_AUTO; struct account *found; while ((option = getopt_long(argc, argv, "", long_options, &option_index)) != -1) { switch (option) { case 'S': sync = parse_sync_string(optarg); break; case 'C': terminal_set_color_mode( parse_color_mode_string(optarg)); break; case '?': default: die_usage(cmd_rm_usage); } } if (argc - optind != 1) die_usage(cmd_rm_usage); name = argv[optind]; init_all(sync, key, &session, &blob); found = find_unique_account(blob, name); if (!found) die("Could not find specified account '%s'.", name); if (found->share && found->share->readonly) die("%s is a readonly shared entry from %s. It cannot be deleted.", found->fullname, found->share->name); list_del(&found->list); lastpass_remove_account(sync, key, session, found, blob); blob_save(blob, key); account_free(found); session_free(session); blob_free(blob); return 0; }
int cmd_edit(int argc, char **argv) { unsigned char key[KDF_HASH_LEN]; struct session *session = NULL; struct blob *blob = NULL; static struct option long_options[] = { {"sync", required_argument, NULL, 'S'}, {"username", no_argument, NULL, 'U'}, {"password", no_argument, NULL, 'P'}, {"url", no_argument, NULL, 'L'}, {"field", required_argument, NULL, 'F'}, {"name", no_argument, NULL, 'N'}, {"notes", no_argument, NULL, 'O'}, {"non-interactive", no_argument, NULL, 'X'}, {0, 0, 0, 0} }; char option; int option_index; enum { NONE, USERNAME, PASSWORD, URL, FIELD, NAME, NOTES } choice = NONE; _cleanup_free_ char *field = NULL; _cleanup_free_ char *tmppath = NULL; _cleanup_free_ char *tmpdir = NULL; _cleanup_free_ char *editcmd = NULL; int tmpfd; FILE *tmpfile; char *name; char *value; bool non_interactive = false; enum blobsync sync = BLOB_SYNC_AUTO; struct account *editable; struct account *notes_expansion, *notes_collapsed = NULL; struct field *editable_field = NULL; size_t len, read; bool should_log_read = false; #define ensure_choice() if (choice != NONE) goto choice_die; while ((option = getopt_long(argc, argv, "", long_options, &option_index)) != -1) { switch (option) { case 'S': sync = parse_sync_string(optarg); break; case 'U': ensure_choice(); choice = USERNAME; break; case 'P': ensure_choice(); choice = PASSWORD; break; case 'L': ensure_choice(); choice = URL; break; case 'F': ensure_choice(); choice = FIELD; field = xstrdup(optarg); break; case 'N': ensure_choice(); choice = NAME; break; case 'O': ensure_choice(); choice = NOTES; break; case 'X': non_interactive = true; break; case '?': default: die_usage(cmd_edit_usage); } } #undef ensure_choice if (argc - optind != 1) die_usage(cmd_edit_usage); if (choice == NONE) choice_die: die_usage("edit ... {--name|--username|--password|--url|--notes|--field=FIELD}"); name = argv[optind]; init_all(sync, key, &session, &blob); editable = find_unique_account(blob, name); if (editable) { if (editable->share && editable->share->readonly) die("%s is a readonly shared entry from %s. It cannot be edited.", editable->fullname, editable->share->name); should_log_read = true; } else { editable = new0(struct account, 1); editable->id = xstrdup("0"); account_set_password(editable, xstrdup(""), key); account_set_fullname(editable, xstrdup(name), key); account_set_username(editable, xstrdup(""), key); account_set_note(editable, xstrdup(""), key); editable->url = xstrdup(""); editable->next = blob->account_head; blob->account_head = editable; } notes_expansion = notes_expand(editable); if (notes_expansion) { notes_collapsed = editable; editable = notes_expansion; } else if (choice == FIELD) die("Editing fields of entries that are not secure notes is currently not supported."); if (choice == USERNAME) value = editable->username; else if (choice == PASSWORD) value = editable->password; else if (choice == URL) value = editable->url; else if (choice == NAME) value = editable->fullname; else if (choice == FIELD) { for (editable_field = editable->field_head; editable_field; editable_field = editable_field->next) { if (!strcmp(editable_field->name, field)) break; } if (!editable_field) { editable_field = new0(struct field, 1); editable_field->type = xstrdup("text"); editable_field->name = xstrdup(field); field_set_value(editable, editable_field, xstrdup(""), key); editable_field->next = editable->field_head; editable->field_head = editable_field; } value = editable_field->value; } else if (choice == NOTES)
int cmd_edit(int argc, char **argv) { unsigned char key[KDF_HASH_LEN]; struct session *session = NULL; struct blob *blob = NULL; static struct option long_options[] = { {"sync", required_argument, NULL, 'S'}, {"username", no_argument, NULL, 'u'}, {"password", no_argument, NULL, 'p'}, {"url", no_argument, NULL, 'L'}, {"field", required_argument, NULL, 'F'}, {"name", no_argument, NULL, 'N'}, {"notes", no_argument, NULL, 'O'}, {"non-interactive", no_argument, NULL, 'X'}, {"color", required_argument, NULL, 'C'}, {0, 0, 0, 0} }; int option; int option_index; _cleanup_free_ char *field = NULL; char *name; bool non_interactive = false; enum blobsync sync = BLOB_SYNC_AUTO; struct account *editable; enum edit_choice choice = EDIT_ANY; enum note_type note_type = NOTE_TYPE_NONE; #define ensure_choice() if (choice != EDIT_ANY) goto choice_die; while ((option = getopt_long(argc, argv, "up", long_options, &option_index)) != -1) { switch (option) { case 'S': sync = parse_sync_string(optarg); break; case 'u': ensure_choice(); choice = EDIT_USERNAME; break; case 'p': ensure_choice(); choice = EDIT_PASSWORD; break; case 'L': ensure_choice(); choice = EDIT_URL; break; case 'F': ensure_choice(); choice = EDIT_FIELD; field = xstrdup(optarg); break; case 'N': ensure_choice(); choice = EDIT_NAME; break; case 'O': ensure_choice(); choice = EDIT_NOTES; break; case 'X': non_interactive = true; break; case 'C': terminal_set_color_mode( parse_color_mode_string(optarg)); break; case '?': default: die_usage(cmd_edit_usage); } } #undef ensure_choice if (argc - optind != 1) die_usage(cmd_edit_usage); if (choice == EDIT_NONE) choice_die: die_usage("edit ... {--name|--username|--password|--url|--notes|--field=FIELD}"); name = argv[optind]; init_all(sync, key, &session, &blob); editable = find_unique_account(blob, name); if (!editable) return edit_new_account(session, blob, sync, name, choice, field, non_interactive, false, note_type, key); if (editable->share && editable->share->readonly) die("%s is a readonly shared entry from %s. It cannot be edited.", editable->fullname, editable->share->name); return edit_account(session, blob, sync, editable, choice, field, non_interactive, key); }
int cmd_export(int argc, char **argv) { static struct option long_options[] = { {"sync", required_argument, NULL, 'S'}, {"color", required_argument, NULL, 'C'}, {0, 0, 0, 0} }; int option; int option_index; enum blobsync sync = BLOB_SYNC_AUTO; while ((option = getopt_long(argc, argv, "c", long_options, &option_index)) != -1) { switch (option) { case 'S': sync = parse_sync_string(optarg); break; case 'C': terminal_set_color_mode( parse_color_mode_string(optarg)); break; case '?': default: die_usage(cmd_export_usage); } } unsigned char key[KDF_HASH_LEN]; struct session *session = NULL; struct blob *blob = NULL; init_all(sync, key, &session, &blob); /* reprompt once if any one account is password protected */ for (struct account *account = blob->account_head; account; account = account->next) { if (account->pwprotect) { unsigned char pwprotect_key[KDF_HASH_LEN]; if (!agent_load_key(pwprotect_key)) die("Could not authenticate for protected entry."); if (memcmp(pwprotect_key, key, KDF_HASH_LEN)) die("Current key is not on-disk key."); break; } } printf("url,username,password,hostname,name,grouping\r\n"); for (struct account *account = blob->account_head; account; account = account->next) { /* skip shared notes */ if (!strcmp(account->url, "http://sn")) continue; lastpass_log_access(sync, session, key, account); print_csv_cell(account->url, false); print_csv_cell(account->username, false); print_csv_cell(account->password, false); print_csv_cell(account->fullname, false); print_csv_cell(account->name, false); print_csv_cell(account->group, true); } session_free(session); blob_free(blob); return 0; }