1 /*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdio.h>
18 #include <stdint.h>
19 #include <string.h>
20 #include <sys/types.h>
21
22 #include <keystore/IKeystoreService.h>
23 #include <binder/IPCThreadState.h>
24 #include <binder/IServiceManager.h>
25
26 #include <keystore/keystore.h>
27
28 using namespace android;
29
30 static const char* responses[] = {
31 NULL,
32 /* [NO_ERROR] = */ "No error",
33 /* [LOCKED] = */ "Locked",
34 /* [UNINITIALIZED] = */ "Uninitialized",
35 /* [SYSTEM_ERROR] = */ "System error",
36 /* [PROTOCOL_ERROR] = */ "Protocol error",
37 /* [PERMISSION_DENIED] = */ "Permission denied",
38 /* [KEY_NOT_FOUND] = */ "Key not found",
39 /* [VALUE_CORRUPTED] = */ "Value corrupted",
40 /* [UNDEFINED_ACTION] = */ "Undefined action",
41 /* [WRONG_PASSWORD] = */ "Wrong password (last chance)",
42 /* [WRONG_PASSWORD + 1] = */ "Wrong password (2 tries left)",
43 /* [WRONG_PASSWORD + 2] = */ "Wrong password (3 tries left)",
44 /* [WRONG_PASSWORD + 3] = */ "Wrong password (4 tries left)",
45 };
46
47 #define NO_ARG_INT_RETURN(cmd) \
48 do { \
49 if (strcmp(argv[1], #cmd) == 0) { \
50 int32_t ret = service->cmd(); \
51 if (ret < 0) { \
52 fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \
53 return 1; \
54 } else { \
55 printf(#cmd ": %s (%d)\n", responses[ret], ret); \
56 return 0; \
57 } \
58 } \
59 } while (0)
60
61 #define SINGLE_ARG_INT_RETURN(cmd) \
62 do { \
63 if (strcmp(argv[1], #cmd) == 0) { \
64 if (argc < 3) { \
65 fprintf(stderr, "Usage: %s " #cmd " <name>\n", argv[0]); \
66 return 1; \
67 } \
68 int32_t ret = service->cmd(String16(argv[2])); \
69 if (ret < 0) { \
70 fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \
71 return 1; \
72 } else { \
73 printf(#cmd ": %s (%d)\n", responses[ret], ret); \
74 return 0; \
75 } \
76 } \
77 } while (0)
78
79 #define SINGLE_INT_ARG_INT_RETURN(cmd) \
80 do { \
81 if (strcmp(argv[1], #cmd) == 0) { \
82 if (argc < 3) { \
83 fprintf(stderr, "Usage: %s " #cmd " <name>\n", argv[0]); \
84 return 1; \
85 } \
86 int32_t ret = service->cmd(atoi(argv[2])); \
87 if (ret < 0) { \
88 fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \
89 return 1; \
90 } else { \
91 printf(#cmd ": %s (%d)\n", responses[ret], ret); \
92 return 0; \
93 } \
94 } \
95 } while (0)
96
97 #define SINGLE_ARG_PLUS_UID_INT_RETURN(cmd) \
98 do { \
99 if (strcmp(argv[1], #cmd) == 0) { \
100 if (argc < 3) { \
101 fprintf(stderr, "Usage: %s " #cmd " <name> <uid>\n", argv[0]); \
102 return 1; \
103 } \
104 int uid = -1; \
105 if (argc > 3) { \
106 uid = atoi(argv[3]); \
107 fprintf(stderr, "Running as uid %d\n", uid); \
108 } \
109 int32_t ret = service->cmd(String16(argv[2]), uid); \
110 if (ret < 0) { \
111 fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \
112 return 1; \
113 } else { \
114 printf(#cmd ": %s (%d)\n", responses[ret], ret); \
115 return 0; \
116 } \
117 } \
118 } while (0)
119
120 #define SINGLE_ARG_PLUS_UID_DATA_RETURN(cmd) \
121 do { \
122 if (strcmp(argv[1], #cmd) == 0) { \
123 if (argc < 3) { \
124 fprintf(stderr, "Usage: %s " #cmd " <name> <uid>\n", argv[0]); \
125 return 1; \
126 } \
127 uint8_t* data; \
128 size_t dataSize; \
129 int uid = -1; \
130 if (argc > 3) { \
131 uid = atoi(argv[3]); \
132 fprintf(stderr, "Running as uid %d\n", uid); \
133 } \
134 int32_t ret = service->cmd(String16(argv[2]), uid, &data, &dataSize); \
135 if (ret < 0) { \
136 fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \
137 return 1; \
138 } else if (ret != ::NO_ERROR) { \
139 fprintf(stderr, "%s: " #cmd ": %s (%d)\n", argv[0], responses[ret], ret); \
140 return 1; \
141 } else { \
142 fwrite(data, dataSize, 1, stdout); \
143 fflush(stdout); \
144 free(data); \
145 return 0; \
146 } \
147 } \
148 } while (0)
149
150 #define STING_ARG_DATA_STDIN_INT_RETURN(cmd) \
151 do { \
152 if (strcmp(argv[1], #cmd) == 0) { \
153 if (argc < 3) { \
154 fprintf(stderr, "Usage: %s " #cmd " <name>\n", argv[0]); \
155 return 1; \
156 } \
157 uint8_t* data; \
158 size_t dataSize; \
159 read_input(&data, &dataSize); \
160 int32_t ret = service->cmd(String16(argv[2]), data, dataSize); \
161 if (ret < 0) { \
162 fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \
163 return 1; \
164 } else { \
165 printf(#cmd ": %s (%d)\n", responses[ret], ret); \
166 return 0; \
167 } \
168 } \
169 } while (0)
170
171 #define SINGLE_ARG_DATA_RETURN(cmd) \
172 do { \
173 if (strcmp(argv[1], #cmd) == 0) { \
174 if (argc < 3) { \
175 fprintf(stderr, "Usage: %s " #cmd " <name>\n", argv[0]); \
176 return 1; \
177 } \
178 uint8_t* data; \
179 size_t dataSize; \
180 int32_t ret = service->cmd(String16(argv[2]), &data, &dataSize); \
181 if (ret < 0) { \
182 fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \
183 return 1; \
184 } else if (ret != ::NO_ERROR) { \
185 fprintf(stderr, "%s: " #cmd ": %s (%d)\n", argv[0], responses[ret], ret); \
186 return 1; \
187 } else { \
188 fwrite(data, dataSize, 1, stdout); \
189 fflush(stdout); \
190 free(data); \
191 return 0; \
192 } \
193 } \
194 } while (0)
195
list(sp<IKeystoreService> service,const String16 & name,int uid)196 static int list(sp<IKeystoreService> service, const String16& name, int uid) {
197 Vector<String16> matches;
198 int32_t ret = service->list(name, uid, &matches);
199 if (ret < 0) {
200 fprintf(stderr, "list: could not connect: %d\n", ret);
201 return 1;
202 } else if (ret != ::NO_ERROR) {
203 fprintf(stderr, "list: %s (%d)\n", responses[ret], ret);
204 return 1;
205 } else {
206 Vector<String16>::const_iterator it = matches.begin();
207 for (; it != matches.end(); ++it) {
208 printf("%s\n", String8(*it).string());
209 }
210 return 0;
211 }
212 }
213
main(int argc,char * argv[])214 int main(int argc, char* argv[])
215 {
216 if (argc < 2) {
217 fprintf(stderr, "Usage: %s action [parameter ...]\n", argv[0]);
218 return 1;
219 }
220
221 sp<IServiceManager> sm = defaultServiceManager();
222 sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
223 sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
224
225 if (service == NULL) {
226 fprintf(stderr, "%s: error: could not connect to keystore service\n", argv[0]);
227 return 1;
228 }
229
230 /*
231 * All the commands should return a value
232 */
233
234 SINGLE_INT_ARG_INT_RETURN(getState);
235
236 SINGLE_ARG_PLUS_UID_DATA_RETURN(get);
237
238 // TODO: insert
239
240 SINGLE_ARG_PLUS_UID_INT_RETURN(del);
241
242 SINGLE_ARG_PLUS_UID_INT_RETURN(exist);
243
244 if (strcmp(argv[1], "list") == 0) {
245 return list(service, argc < 3 ? String16("") : String16(argv[2]),
246 argc < 4 ? -1 : atoi(argv[3]));
247 }
248
249 NO_ARG_INT_RETURN(reset);
250
251 // TODO: notifyUserPasswordChanged
252
253 SINGLE_INT_ARG_INT_RETURN(lock);
254
255 // TODO: unlock
256
257 SINGLE_INT_ARG_INT_RETURN(isEmpty);
258
259 // TODO: generate
260
261 SINGLE_ARG_DATA_RETURN(get_pubkey);
262
263 // TODO: grant
264
265 // TODO: ungrant
266
267 // TODO: getmtime
268
269 fprintf(stderr, "%s: unknown command: %s\n", argv[0], argv[1]);
270 return 1;
271 }
272