1/*
2 * Copyright 2012, Haiku Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Michael Lotz, mmlr@mlotz.ch
7 */
8
9
10#include <Application.h>
11#include <KeyStore.h>
12
13#include <stdio.h>
14
15
16int
17add_password(const char* keyring, const char* identifier,
18	const char* secondaryIdentifier, const char* passwordString)
19{
20	BKeyStore keyStore;
21	BPasswordKey password(passwordString, B_KEY_PURPOSE_GENERIC, identifier,
22		secondaryIdentifier);
23
24	status_t result = keyStore.AddKey(keyring, password);
25	if (result != B_OK) {
26		printf("failed to add password: %s\n", strerror(result));
27		return 2;
28	}
29
30	return 0;
31}
32
33
34int
35remove_password(const char* keyring, const char* identifier,
36	const char* secondaryIdentifier)
37{
38	BKeyStore keyStore;
39	BPasswordKey password;
40
41	status_t result = keyStore.GetKey(keyring, B_KEY_TYPE_PASSWORD, identifier,
42		secondaryIdentifier, false, password);
43	if (result != B_OK) {
44		printf("failed to get password \"%s\": %s\n", identifier,
45			strerror(result));
46		return 2;
47	}
48
49	result = keyStore.RemoveKey(keyring, password);
50	if (result != B_OK) {
51		printf("failed to remove password: %s\n", strerror(result));
52		return 3;
53	}
54
55	return 0;
56}
57
58
59int
60add_keyring(const char* keyring)
61{
62	BKeyStore keyStore;
63
64	status_t result = keyStore.AddKeyring(keyring);
65	if (result != B_OK) {
66		printf("failed to add keyring: %s\n", strerror(result));
67		return 2;
68	}
69
70	return 0;
71}
72
73
74int
75remove_keyring(const char* keyring)
76{
77	BKeyStore keyStore;
78
79	status_t result = keyStore.RemoveKeyring(keyring);
80	if (result != B_OK) {
81		printf("failed to remove keyring: %s\n", strerror(result));
82		return 2;
83	}
84
85	return 0;
86}
87
88
89int
90list_passwords(const char* keyring)
91{
92	BKeyStore keyStore;
93	uint32 cookie = 0;
94
95	while (true) {
96		BPasswordKey password;
97		status_t result = keyStore.GetNextKey(keyring, B_KEY_TYPE_PASSWORD,
98			B_KEY_PURPOSE_ANY, cookie, password);
99		if (result == B_ENTRY_NOT_FOUND)
100			break;
101
102		if (result != B_OK) {
103			printf("failed to get next key with: %s\n", strerror(result));
104			return 2;
105		}
106
107		password.PrintToStream();
108	}
109
110	return 0;
111}
112
113
114int
115list_keyrings()
116{
117	BKeyStore keyStore;
118	uint32 cookie = 0;
119
120	while (true) {
121		BString keyring;
122		status_t result = keyStore.GetNextKeyring(cookie, keyring);
123		if (result == B_ENTRY_NOT_FOUND)
124			break;
125
126		if (result != B_OK) {
127			printf("failed to get next key with: %s\n", strerror(result));
128			return 2;
129		}
130
131		printf("keyring: \"%s\"\n", keyring.String());
132	}
133
134	return 0;
135}
136
137
138int
139show_status(const char* keyring)
140{
141	BKeyStore keyStore;
142	printf("keyring \"%s\" is %slocked\n", keyring,
143		keyStore.IsKeyringUnlocked(keyring) ? "un" : "");
144	return 0;
145}
146
147
148int
149lock_keyring(const char* keyring)
150{
151	BKeyStore keyStore;
152	status_t result = keyStore.LockKeyring(keyring);
153	if (result != B_OK) {
154		printf("failed to lock keyring \"%s\": %s\n", keyring,
155			strerror(result));
156		return 2;
157	}
158
159	return 0;
160}
161
162
163int
164add_keyring_to_master(const char* keyring)
165{
166	BKeyStore keyStore;
167	status_t result= keyStore.AddKeyringToMaster(keyring);
168	if (result != B_OK) {
169		printf("failed to add keyring \"%s\" to master: %s\n", keyring,
170			strerror(result));
171		return 2;
172	}
173
174	return 0;
175}
176
177
178int
179remove_keyring_from_master(const char* keyring)
180{
181	BKeyStore keyStore;
182	status_t result= keyStore.RemoveKeyringFromMaster(keyring);
183	if (result != B_OK) {
184		printf("failed to remove keyring \"%s\" from master: %s\n", keyring,
185			strerror(result));
186		return 2;
187	}
188
189	return 0;
190}
191
192
193int
194list_applications(const char* keyring)
195{
196	BKeyStore keyStore;
197	uint32 cookie = 0;
198
199	while (true) {
200		BString signature;
201		status_t result = keyStore.GetNextApplication(keyring,
202			cookie, signature);
203		if (result == B_ENTRY_NOT_FOUND)
204			break;
205
206		if (result != B_OK) {
207			printf("failed to get next application: %s\n", strerror(result));
208			return 2;
209		}
210
211		printf("application: \"%s\"\n", signature.String());
212	}
213
214	return 0;
215}
216
217
218int
219remove_application(const char* keyring, const char* signature)
220{
221	BKeyStore keyStore;
222
223	status_t result = keyStore.RemoveApplication(keyring, signature);
224	if (result != B_OK) {
225		printf("failed to remove application: %s\n", strerror(result));
226		return 3;
227	}
228
229	return 0;
230}
231
232
233int
234set_unlock_key(const char* keyring, const char* passwordString)
235{
236	BKeyStore keyStore;
237	BPasswordKey password(passwordString, B_KEY_PURPOSE_KEYRING, NULL);
238
239	status_t result = keyStore.SetUnlockKey(keyring, password);
240	if (result != B_OK) {
241		printf("failed to set unlock key: %s\n", strerror(result));
242		return 3;
243	}
244
245	return 0;
246}
247
248
249int
250remove_unlock_key(const char* keyring)
251{
252	BKeyStore keyStore;
253
254	status_t result = keyStore.RemoveUnlockKey(keyring);
255	if (result != B_OK) {
256		printf("failed to remove unlock key: %s\n", strerror(result));
257		return 3;
258	}
259
260	return 0;
261}
262
263
264int
265print_usage(const char* name)
266{
267	printf("usage:\n");
268	printf("\t%s list passwords [<fromKeyring>]\n", name);
269	printf("\t\tLists all passwords of the specified keyring or from the"
270		" master keyring if none is supplied.\n");
271	printf("\t%s list keyrings\n", name);
272	printf("\t\tLists all keyrings.\n");
273	printf("\t%s list applications [<fromKeyring>]\n", name);
274	printf("\t\tLists the applications that have been granted permanent access"
275		" to a keyring once it is unlocked.\n\n");
276
277	printf("\t%s add password <identifier> [<secondaryIdentifier>] <password>"
278		"\n", name);
279	printf("\t\tAdds the specified password to the master keyring.\n");
280	printf("\t%s add password to <keyring> <identifier> [<secondaryIdentifier>]"
281		" <password>\n", name);
282	printf("\t\tAdds the specified password to the specified keyring.\n\n");
283
284	printf("\t%s remove password <identifier> [<secondaryIdentifier>]\n", name);
285	printf("\t\tRemoves the specified password from the master keyring.\n");
286	printf("\t%s remove password from <keyring> <identifier>"
287		" [<secondaryIdentifier>]\n", name);
288	printf("\t\tRemoves the specified password from the specified keyring.\n\n");
289
290	printf("\t%s add keyring <name>\n", name);
291	printf("\t\tAdds a new keyring with the specified name.\n");
292	printf("\t%s remove keyring <name>\n", name);
293	printf("\t\tRemoves the specified keyring.\n\n");
294
295	printf("\t%s status [<keyring>]\n", name);
296	printf("\t\tShows the lock state of the specified keyring, or the"
297		" master keyring if none is supplied.\n\n");
298
299	printf("\t%s lock [<keyring>]\n", name);
300	printf("\t\tLock the specified keyring, or the master keyring if none is"
301		" supplied.\n\n");
302
303	printf("\t%s master add <keyring>\n", name);
304	printf("\t\tAdd the access key for the specified keyring to the master"
305		" keyring.\n");
306
307	printf("\t%s master remove <keyring>\n", name);
308	printf("\t\tRemove the access key for the specified keyring from the"
309		" master keyring.\n\n");
310
311	printf("\t%s remove application <signature>\n", name);
312	printf("\t\tRemove permanent access for the application with the given"
313		" signature from the master keyring.\n");
314	printf("\t%s remove application from <keyring> <signature>\n", name);
315	printf("\t\tRemove permanent access for the application with the given"
316		" signature from the specified keyring.\n\n");
317
318	printf("\t%s key set <keyring> <password>\n", name);
319	printf("\t\tSet the unlock key of the specified keyring to the given"
320		" password.\n");
321	printf("\t%s key remove <keyring>\n", name);
322	printf("\t\tRemove the unlock key of the specified keyring.\n");
323	return 1;
324}
325
326
327int
328main(int argc, char* argv[])
329{
330	BApplication app("application/x-vnd.Haiku-keystore-cli");
331
332	if (argc < 2)
333		return print_usage(argv[0]);
334
335	if (strcmp(argv[1], "list") == 0) {
336		if (argc < 3)
337			return print_usage(argv[0]);
338
339		if (strcmp(argv[2], "passwords") == 0)
340			return list_passwords(argc > 3 ? argv[3] : NULL);
341		if (strcmp(argv[2], "keyrings") == 0)
342			return list_keyrings();
343		if (strcmp(argv[2], "applications") == 0)
344			return list_applications(argc > 3 ? argv[3] : NULL);
345	} else if (strcmp(argv[1], "add") == 0) {
346		if (argc < 3)
347			return print_usage(argv[0]);
348
349		if (strcmp(argv[2], "password") == 0) {
350			if (argc < 5)
351				return print_usage(argv[0]);
352
353			const char* keyring = NULL;
354			const char* identifier = NULL;
355			const char* secondaryIdentifier = NULL;
356			const char* password = NULL;
357			if (argc >= 7 && argc <= 8 && strcmp(argv[3], "to") == 0) {
358				keyring = argv[4];
359				identifier = argv[5];
360				if (argc == 7)
361					password = argv[6];
362				else {
363					secondaryIdentifier = argv[6];
364					password = argv[7];
365				}
366			} else if (argc <= 6) {
367				identifier = argv[3];
368				if (argc == 5)
369					password = argv[4];
370				else {
371					secondaryIdentifier = argv[4];
372					password = argv[5];
373				}
374			}
375
376			if (password != NULL) {
377				return add_password(keyring, identifier, secondaryIdentifier,
378					password);
379			}
380		} else if (strcmp(argv[2], "keyring") == 0) {
381			if (argc < 4)
382				return print_usage(argv[0]);
383
384			return add_keyring(argv[3]);
385		}
386	} else if (strcmp(argv[1], "remove") == 0) {
387		if (argc < 3)
388			return print_usage(argv[0]);
389
390		if (strcmp(argv[2], "password") == 0) {
391			if (argc < 4)
392				return print_usage(argv[0]);
393
394			const char* keyring = NULL;
395			const char* identifier = NULL;
396			const char* secondaryIdentifier = NULL;
397			if (argc >= 6 && argc <= 7 && strcmp(argv[3], "from") == 0) {
398				keyring = argv[4];
399				identifier = argv[5];
400				if (argc == 7)
401					secondaryIdentifier = argv[6];
402			} else if (argc <= 5) {
403				identifier = argv[3];
404				if (argc == 5)
405					secondaryIdentifier = argv[4];
406			}
407
408			if (identifier != NULL) {
409				return remove_password(keyring, identifier,
410					secondaryIdentifier);
411			}
412		} else if (strcmp(argv[2], "keyring") == 0) {
413			if (argc == 4)
414				return remove_keyring(argv[3]);
415		} else if (strcmp(argv[2], "application") == 0) {
416			const char* keyring = NULL;
417			const char* signature = NULL;
418			if (argc == 6 && strcmp(argv[3], "from") == 0) {
419				keyring = argv[4];
420				signature = argv[5];
421			} else if (argc == 4)
422				signature = argv[3];
423
424			if (signature != NULL)
425				return remove_application(keyring, signature);
426		}
427	} else if (strcmp(argv[1], "status") == 0) {
428		if (argc != 2 && argc != 3)
429			return print_usage(argv[0]);
430
431		return show_status(argc == 3 ? argv[2] : "");
432	} else if (strcmp(argv[1], "lock") == 0) {
433		if (argc != 2 && argc != 3)
434			return print_usage(argv[0]);
435
436		return lock_keyring(argc == 3 ? argv[2] : "");
437	} else if (strcmp(argv[1], "master") == 0) {
438		if (argc != 4)
439			return print_usage(argv[0]);
440
441		if (strcmp(argv[2], "add") == 0)
442			return add_keyring_to_master(argv[3]);
443		if (strcmp(argv[2], "remove") == 0)
444			return remove_keyring_from_master(argv[3]);
445	} else if (strcmp(argv[1], "key") == 0) {
446		if (argc < 4)
447			return print_usage(argv[0]);
448
449		if (strcmp(argv[2], "set") == 0) {
450			if (argc == 5)
451				return set_unlock_key(argv[3], argv[4]);
452		} else if (strcmp(argv[2], "remove") == 0) {
453			if (argc == 4)
454				return remove_unlock_key(argv[3]);
455		}
456	}
457
458	return print_usage(argv[0]);
459}
460