/
cmd.c
161 lines (141 loc) · 4.59 KB
/
cmd.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/*
* Copyright (c) 2014-2015 LastPass.
*/
#include "cmd.h"
#include "agent.h"
#include "blob.h"
#include "session.h"
#include "util.h"
#include "process.h"
#include <strings.h>
#include <string.h>
#include <regex.h>
enum blobsync parse_sync_string(const char *syncstr)
{
if (!syncstr || !strcasecmp(syncstr, "auto"))
return BLOB_SYNC_AUTO;
else if (!strcasecmp(syncstr, "now"))
return BLOB_SYNC_YES;
else if (!strcasecmp(syncstr, "no"))
return BLOB_SYNC_NO;
else
die_usage("... --sync=auto|now|no");
}
enum color_mode parse_color_mode_string(const char *colormode)
{
if (!colormode || strcmp(colormode, "auto") == 0)
return COLOR_MODE_AUTO;
else if (strcmp(colormode, "never") == 0)
return COLOR_MODE_NEVER;
else if (strcmp(colormode, "always") == 0)
return COLOR_MODE_ALWAYS;
else
die_usage("... --color=auto|never|always");
}
void init_all(enum blobsync sync, unsigned char key[KDF_HASH_LEN], struct session **session, struct blob **blob)
{
if (!agent_get_decryption_key(key))
die("Could not find decryption key. Perhaps you need to login with `%s login`.", ARGV[0]);
*session = sesssion_load(key);
if (!*session)
die("Could not find session. Perhaps you need to login with `%s login`.", ARGV[0]);
if (blob) {
*blob = blob_load(sync, *session, key);
if (!*blob)
die("Unable to fetch blob. Either your session is invalid and you need to login with `%s login`, you need to synchronize, your blob is empty, or there is something wrong with your internet connection.", ARGV[0]);
}
}
/*
* cmp_regex - do regex comparison with a basic regex
*/
static int cmp_regex(const char *haystack, const char *needle)
{
return regexec((void *) needle, haystack, 0, NULL, 0);
}
/*
* cmp_substr - do substring comparison with a fixed pattern
*/
static int cmp_substr(const char *haystack, const char *needle)
{
return strstr(haystack, needle) == NULL;
}
static void search_accounts(struct blob *blob,
const void *needle,
int (*cmp)(const char *haystack, const char *needle),
int fields,
struct list_head *ret_list)
{
for (struct account *account = blob->account_head; account;
account = account->next) {
if (((fields & ACCOUNT_ID) && cmp(account->id, needle) == 0) ||
((fields & ACCOUNT_NAME) && cmp(account->name, needle) == 0) ||
((fields & ACCOUNT_FULLNAME) && cmp(account->fullname, needle) == 0) ||
((fields & ACCOUNT_URL) && cmp(account->url, needle) == 0) ||
((fields & ACCOUNT_USERNAME) && cmp(account->username, needle) == 0)) {
list_add_tail(&account->match_list, ret_list);
}
}
}
/*
* Search accounts on given fields, returning results into ret_list.
*
* @pattern - a basic regular expression
* @fields - which fields to search on
*/
void find_matching_regex(struct blob *blob, const char *pattern,
int fields, struct list_head *ret_list)
{
regex_t regex;
if (regcomp(®ex, pattern, REG_ICASE))
die("Invalid regex '%s'", pattern);
search_accounts(blob, ®ex, cmp_regex, fields, ret_list);
regfree(®ex);
}
/*
* Search accounts on name, username, and url fields, adding all matches
* into ret_list.
*
* @pattern - a basic regular expression
* @fields - which fields to search on
*/
void find_matching_substr(struct blob *blob, const char *pattern,
int fields, struct list_head *ret_list)
{
search_accounts(blob, pattern, cmp_substr, fields, ret_list);
}
/*
* Search blob for any and all accounts matching a given name.
* Matching accounts are appended to ret_list which should be initialized
* by the caller.
*
* In the case of an id match, we return only the matching id entry.
*/
void find_matching_accounts(struct blob *blob, const char *name,
struct list_head *ret_list)
{
/* look for exact id match */
for (struct account *account = blob->account_head; account; account = account->next) {
if (strcmp(name, "0") && !strcasecmp(account->id, name)) {
list_add_tail(&account->match_list, ret_list);
/* if id match, stop processing */
return;
}
}
/* search for fullname or name match */
search_accounts(blob, name, strcmp, ACCOUNT_NAME | ACCOUNT_FULLNAME,
ret_list);
}
struct account *find_unique_account(struct blob *blob, const char *name)
{
struct list_head matches;
struct account *account, *last_account;
INIT_LIST_HEAD(&matches);
find_matching_accounts(blob, name, &matches);
if (list_empty(&matches))
return NULL;
account = list_first_entry(&matches, struct account, match_list);
last_account = list_last_entry(&matches, struct account, match_list);
if (account != last_account)
die("Multiple matches found for '%s'. You must specify an ID instead of a name.", name);
return account;
}