blob: 5193b3dba5dea118383ad4b5f3962198e542f8eb [file] [log] [blame]
Chung-yih Wang82290482009-06-08 16:34:54 +08001/*
2** Copyright 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 "keystore.h"
18
19
20static int do_list_certs(char **arg, char reply[REPLY_MAX])
21{
22 return list_certs(reply);
23}
24
25static int do_list_userkeys(char **arg, char reply[REPLY_MAX])
26{
27 return list_userkeys(reply);
28}
29
30static int do_install_cert(char **arg, char reply[REPLY_MAX])
31{
32 return install_cert(arg[0]); /* move the certificate to keystore */
33}
34
35static int do_remove_cert(char **arg, char reply[REPLY_MAX])
36{
37 return remove_cert(arg[0]); /* certificate */
38}
39
40static int do_install_userkey(char **arg, char reply[REPLY_MAX])
41{
42 return install_userkey(arg[0]); /* move the certificate to keystore */
43}
44
45static int do_remove_userkey(char **arg, char reply[REPLY_MAX])
46{
47 return remove_userkey(arg[0]); /* userkey */
48}
49
50struct cmdinfo {
51 const char *name;
52 unsigned numargs;
53 int (*func)(char **arg, char reply[REPLY_MAX]);
54};
55
56
57struct cmdinfo cmds[] = {
58 { "listcerts", 0, do_list_certs },
59 { "listuserkeys", 0, do_list_userkeys },
60 { "installcert", 1, do_install_cert },
61 { "removecert", 1, do_remove_cert },
62 { "installuserkey", 1, do_install_userkey },
63 { "removeuserkey", 1, do_remove_userkey },
64};
65
66static int readx(int s, void *_buf, int count)
67{
68 char *buf = _buf;
69 int n = 0, r;
70 if (count < 0) return -1;
71 while (n < count) {
72 r = read(s, buf + n, count - n);
73 if (r < 0) {
74 if (errno == EINTR) continue;
75 LOGE("read error: %s\n", strerror(errno));
76 return -1;
77 }
78 if (r == 0) {
79 LOGE("eof\n");
80 return -1; /* EOF */
81 }
82 n += r;
83 }
84 return 0;
85}
86
87static int writex(int s, const void *_buf, int count)
88{
89 const char *buf = _buf;
90 int n = 0, r;
91 if (count < 0) return -1;
92 while (n < count) {
93 r = write(s, buf + n, count - n);
94 if (r < 0) {
95 if (errno == EINTR) continue;
96 LOGE("write error: %s\n", strerror(errno));
97 return -1;
98 }
99 n += r;
100 }
101 return 0;
102}
103
104
105/* Tokenize the command buffer, locate a matching command,
106 * ensure that the required number of arguments are provided,
107 * call the function(), return the result.
108 */
109static int execute(int s, char cmd[BUFFER_MAX])
110{
111 char reply[REPLY_MAX];
112 char *arg[TOKEN_MAX+1];
113 unsigned i;
114 unsigned n = 0;
115 unsigned short count;
Chung-yih Wang10e371f2009-06-10 18:45:14 +0800116 short ret = -1;
Chung-yih Wang82290482009-06-08 16:34:54 +0800117
118 /* default reply is "" */
119 reply[0] = 0;
120
121 /* n is number of args (not counting arg[0]) */
122 arg[0] = cmd;
123 while (*cmd) {
124 if (isspace(*cmd)) {
125 *cmd++ = 0;
126 n++;
127 arg[n] = cmd;
128 if (n == TOKEN_MAX) {
129 LOGE("too many arguments\n");
130 goto done;
131 }
132 }
133 cmd++;
134 }
135
136 for (i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++) {
137 if (!strcmp(cmds[i].name,arg[0])) {
138 if (n != cmds[i].numargs) {
139 LOGE("%s requires %d arguments (%d given)\n",
140 cmds[i].name, cmds[i].numargs, n);
141 } else {
Chung-yih Wang10e371f2009-06-10 18:45:14 +0800142 ret = (short) cmds[i].func(arg + 1, reply);
Chung-yih Wang82290482009-06-08 16:34:54 +0800143 }
144 goto done;
145 }
146 }
147 LOGE("unsupported command '%s'\n", arg[0]);
148
149done:
150 if (reply[0]) {
Chung-yih Wang10e371f2009-06-10 18:45:14 +0800151 strlcpy(cmd, reply, BUFFER_MAX);
152 count = strlen(cmd);
Chung-yih Wang82290482009-06-08 16:34:54 +0800153 } else {
Chung-yih Wang10e371f2009-06-10 18:45:14 +0800154 count = 0;
Chung-yih Wang82290482009-06-08 16:34:54 +0800155 }
Chung-yih Wang10e371f2009-06-10 18:45:14 +0800156 if (writex(s, &ret, sizeof(ret))) return -1;
157 if (ret == 0) {
158 if (writex(s, &count, sizeof(count))) return -1;
159 if (writex(s, cmd, count)) return -1;
160 }
Chung-yih Wang82290482009-06-08 16:34:54 +0800161
162 return 0;
163}
164
165int shell_command(const int argc, const char **argv)
166{
Chung-yih Wang10e371f2009-06-10 18:45:14 +0800167 int fd, i;
168 short ret;
Chung-yih Wang82290482009-06-08 16:34:54 +0800169 unsigned short count;
Chung-yih Wang10e371f2009-06-10 18:45:14 +0800170 char buf[BUFFER_MAX]="";
Chung-yih Wang82290482009-06-08 16:34:54 +0800171
172 fd = socket_local_client(SOCKET_PATH,
173 ANDROID_SOCKET_NAMESPACE_RESERVED,
174 SOCK_STREAM);
175 if (fd == -1) {
176 fprintf(stderr, "Keystore service is not up and running\n");
177 exit(1);
178 }
179 for(i = 0; i < argc; i++) {
Chung-yih Wang10e371f2009-06-10 18:45:14 +0800180 if (i > 0) strlcat(buf, " ", BUFFER_MAX);
181 if(strlcat(buf, argv[i], BUFFER_MAX) >= BUFFER_MAX) {
Chung-yih Wang82290482009-06-08 16:34:54 +0800182 fprintf(stderr, "Arguments are too long\n");
183 exit(1);
184 }
185 }
Chung-yih Wang10e371f2009-06-10 18:45:14 +0800186 count = strlen(buf);
Chung-yih Wang82290482009-06-08 16:34:54 +0800187 if (writex(fd, &count, sizeof(count))) return -1;
Chung-yih Wang10e371f2009-06-10 18:45:14 +0800188 if (writex(fd, buf, strlen(buf))) return -1;
189 if (readx(fd, &ret, sizeof(ret))) return -1;
190 if (ret == 0) {
191 if (readx(fd, &count, sizeof(count))) return -1;
192 if (readx(fd, buf, count)) return -1;
193 buf[count]=0;
194 fprintf(stdout, "%s\n", buf);
195 } else {
196 fprintf(stderr, "Failed, please check log!\n");
197 }
Chung-yih Wang82290482009-06-08 16:34:54 +0800198 return 0;
199}
200
201int main(const int argc, const char *argv[])
202{
203 char buf[BUFFER_MAX];
204 struct sockaddr addr;
205 socklen_t alen;
206 int lsocket, s, count;
207
208 if (argc > 1) {
209 return shell_command(argc - 1, argv + 1);
210 }
211
212 lsocket = android_get_control_socket(SOCKET_PATH);
213 if (lsocket < 0) {
214 LOGE("Failed to get socket from environment: %s\n", strerror(errno));
215 exit(1);
216 }
217 if (listen(lsocket, 5)) {
218 LOGE("Listen on socket failed: %s\n", strerror(errno));
219 exit(1);
220 }
221 fcntl(lsocket, F_SETFD, FD_CLOEXEC);
222
223 for (;;) {
224 alen = sizeof(addr);
225 s = accept(lsocket, &addr, &alen);
226 if (s < 0) {
227 LOGE("Accept failed: %s\n", strerror(errno));
228 continue;
229 }
230 fcntl(s, F_SETFD, FD_CLOEXEC);
231
232 LOGI("new connection\n");
233 for (;;) {
234 unsigned short count;
235 if (readx(s, &count, sizeof(count))) {
236 LOGE("failed to read size\n");
237 break;
238 }
239 if ((count < 1) || (count >= BUFFER_MAX)) {
240 LOGE("invalid size %d\n", count);
241 break;
242 }
243 if (readx(s, buf, count)) {
244 LOGE("failed to read command\n");
245 break;
246 }
247 buf[count] = 0;
248 if (execute(s, buf)) break;
249 }
250 LOGI("closing connection\n");
251 close(s);
252 }
253
254 return 0;
255}