OSDN Git Service

merge in mnc-dr-release history after reset to mnc-dr-dev
[android-x86/system-vold.git] / CryptCommandListener.cpp
1 /*
2  * Copyright (C) 2015 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 <stdlib.h>
18 #include <sys/socket.h>
19 #include <sys/types.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
22 #include <dirent.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <fs_mgr.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdint.h>
29 #include <inttypes.h>
30
31 #define LOG_TAG "VoldCryptCmdListener"
32
33 #include <base/stringprintf.h>
34 #include <cutils/fs.h>
35 #include <cutils/log.h>
36 #include <cutils/sockets.h>
37
38 #include <sysutils/SocketClient.h>
39 #include <private/android_filesystem_config.h>
40
41 #include "CryptCommandListener.h"
42 #include "Process.h"
43 #include "ResponseCode.h"
44 #include "cryptfs.h"
45 #include "Ext4Crypt.h"
46
47 #define DUMP_ARGS 0
48
49 CryptCommandListener::CryptCommandListener() :
50 FrameworkListener("cryptd", true) {
51     registerCmd(new CryptfsCmd());
52 }
53
54 #if DUMP_ARGS
55 void CryptCommandListener::dumpArgs(int argc, char **argv, int argObscure) {
56     char buffer[4096];
57     char *p = buffer;
58
59     memset(buffer, 0, sizeof(buffer));
60     int i;
61     for (i = 0; i < argc; i++) {
62         unsigned int len = strlen(argv[i]) + 1; // Account for space
63         if (i == argObscure) {
64             len += 2; // Account for {}
65         }
66         if (((p - buffer) + len) < (sizeof(buffer)-1)) {
67             if (i == argObscure) {
68                 *p++ = '{';
69                 *p++ = '}';
70                 *p++ = ' ';
71                 continue;
72             }
73             strcpy(p, argv[i]);
74             p+= strlen(argv[i]);
75             if (i != (argc -1)) {
76                 *p++ = ' ';
77             }
78         }
79     }
80     SLOGD("%s", buffer);
81 }
82 #else
83 void CryptCommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
84 #endif
85
86 int CryptCommandListener::sendGenericOkFail(SocketClient *cli, int cond) {
87     if (!cond) {
88         return cli->sendMsg(ResponseCode::CommandOkay, "Command succeeded", false);
89     } else {
90         return cli->sendMsg(ResponseCode::OperationFailed, "Command failed", false);
91     }
92 }
93
94 CryptCommandListener::CryptfsCmd::CryptfsCmd() :
95                  VoldCommand("cryptfs") {
96 }
97
98 static int getType(const char* type)
99 {
100     if (!strcmp(type, "default")) {
101         return CRYPT_TYPE_DEFAULT;
102     } else if (!strcmp(type, "password")) {
103         return CRYPT_TYPE_PASSWORD;
104     } else if (!strcmp(type, "pin")) {
105         return CRYPT_TYPE_PIN;
106     } else if (!strcmp(type, "pattern")) {
107         return CRYPT_TYPE_PATTERN;
108     } else {
109         return -1;
110     }
111 }
112
113 int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
114                                                  int argc, char **argv) {
115     if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
116         cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run cryptfs commands", false);
117         return 0;
118     }
119
120     if (argc < 2) {
121         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
122         return 0;
123     }
124
125     int rc = 0;
126
127     if (!strcmp(argv[1], "checkpw")) {
128         if (argc != 3) {
129             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs checkpw <passwd>", false);
130             return 0;
131         }
132         dumpArgs(argc, argv, 2);
133         rc = cryptfs_check_passwd(argv[2]);
134     } else if (!strcmp(argv[1], "restart")) {
135         if (argc != 2) {
136             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs restart", false);
137             return 0;
138         }
139         dumpArgs(argc, argv, -1);
140         rc = cryptfs_restart();
141     } else if (!strcmp(argv[1], "cryptocomplete")) {
142         if (argc != 2) {
143             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs cryptocomplete", false);
144             return 0;
145         }
146         dumpArgs(argc, argv, -1);
147         rc = cryptfs_crypto_complete();
148     } else if (!strcmp(argv[1], "enablecrypto")) {
149         const char* syntax = "Usage: cryptfs enablecrypto <wipe|inplace> "
150                              "default|password|pin|pattern [passwd]";
151         if ( (argc != 4 && argc != 5)
152              || (strcmp(argv[2], "wipe") && strcmp(argv[2], "inplace")) ) {
153             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
154             return 0;
155         }
156         dumpArgs(argc, argv, 4);
157
158         int tries;
159         for (tries = 0; tries < 2; ++tries) {
160             int type = getType(argv[3]);
161             if (type == -1) {
162                 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax,
163                              false);
164                 return 0;
165             } else if (type == CRYPT_TYPE_DEFAULT) {
166               rc = cryptfs_enable_default(argv[2], /*allow_reboot*/false);
167             } else {
168                 rc = cryptfs_enable(argv[2], type, argv[4],
169                                     /*allow_reboot*/false);
170             }
171
172             if (rc == 0) {
173                 break;
174             } else if (tries == 0) {
175                 Process::killProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL);
176             }
177         }
178     } else if (!strcmp(argv[1], "enablefilecrypto")) {
179         const char* syntax = "Usage: cryptfs enablefilecrypto";
180         if (argc != 2) {
181             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
182             return 0;
183         }
184         dumpArgs(argc, argv, -1);
185         rc = cryptfs_enable_file();
186     } else if (!strcmp(argv[1], "changepw")) {
187         const char* syntax = "Usage: cryptfs changepw "
188                              "default|password|pin|pattern [newpasswd]";
189         const char* password;
190         if (argc == 3) {
191             password = "";
192         } else if (argc == 4) {
193             password = argv[3];
194         } else {
195             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
196             return 0;
197         }
198         int type = getType(argv[2]);
199         if (type == -1) {
200             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
201             return 0;
202         }
203         SLOGD("cryptfs changepw %s {}", argv[2]);
204         rc = cryptfs_changepw(type, password);
205     } else if (!strcmp(argv[1], "verifypw")) {
206         if (argc != 3) {
207             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs verifypw <passwd>", false);
208             return 0;
209         }
210         SLOGD("cryptfs verifypw {}");
211         rc = cryptfs_verify_passwd(argv[2]);
212     } else if (!strcmp(argv[1], "getfield")) {
213         char *valbuf;
214         int valbuf_len = PROPERTY_VALUE_MAX;
215
216         if (argc != 3) {
217             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs getfield <fieldname>", false);
218             return 0;
219         }
220         dumpArgs(argc, argv, -1);
221
222         // Increase the buffer size until it is big enough for the field value stored.
223         while (1) {
224             valbuf = (char*)malloc(valbuf_len);
225             if (valbuf == NULL) {
226                 cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", false);
227                 return 0;
228             }
229             rc = cryptfs_getfield(argv[2], valbuf, valbuf_len);
230             if (rc != CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL) {
231                 break;
232             }
233             free(valbuf);
234             valbuf_len *= 2;
235         }
236         if (rc == CRYPTO_GETFIELD_OK) {
237             cli->sendMsg(ResponseCode::CryptfsGetfieldResult, valbuf, false);
238         }
239         free(valbuf);
240     } else if (!strcmp(argv[1], "setfield")) {
241         if (argc != 4) {
242             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs setfield <fieldname> <value>", false);
243             return 0;
244         }
245         dumpArgs(argc, argv, -1);
246         rc = cryptfs_setfield(argv[2], argv[3]);
247     } else if (!strcmp(argv[1], "mountdefaultencrypted")) {
248         SLOGD("cryptfs mountdefaultencrypted");
249         dumpArgs(argc, argv, -1);
250         rc = cryptfs_mount_default_encrypted();
251     } else if (!strcmp(argv[1], "getpwtype")) {
252         SLOGD("cryptfs getpwtype");
253         dumpArgs(argc, argv, -1);
254         switch(cryptfs_get_password_type()) {
255         case CRYPT_TYPE_PASSWORD:
256             cli->sendMsg(ResponseCode::PasswordTypeResult, "password", false);
257             return 0;
258         case CRYPT_TYPE_PATTERN:
259             cli->sendMsg(ResponseCode::PasswordTypeResult, "pattern", false);
260             return 0;
261         case CRYPT_TYPE_PIN:
262             cli->sendMsg(ResponseCode::PasswordTypeResult, "pin", false);
263             return 0;
264         case CRYPT_TYPE_DEFAULT:
265             cli->sendMsg(ResponseCode::PasswordTypeResult, "default", false);
266             return 0;
267         default:
268           /** @TODO better error and make sure handled by callers */
269             cli->sendMsg(ResponseCode::OpFailedStorageNotFound, "Error", false);
270             return 0;
271         }
272     } else if (!strcmp(argv[1], "getpw")) {
273         SLOGD("cryptfs getpw");
274         dumpArgs(argc, argv, -1);
275         const char* password = cryptfs_get_password();
276         if (password) {
277             char* message = 0;
278             int size = asprintf(&message, "{{sensitive}} %s", password);
279             if (size != -1) {
280                 cli->sendMsg(ResponseCode::CommandOkay, message, false);
281                 memset(message, 0, size);
282                 free (message);
283                 return 0;
284             }
285         }
286         rc = -1;
287     } else if (!strcmp(argv[1], "clearpw")) {
288         SLOGD("cryptfs clearpw");
289         dumpArgs(argc, argv, -1);
290         cryptfs_clear_password();
291         rc = 0;
292     } else if (!strcmp(argv[1], "setusercryptopolicies")) {
293         if (argc != 3) {
294             cli->sendMsg(ResponseCode::CommandSyntaxError,
295                 "Usage: cryptfs setusercryptopolicies <path>", false);
296             return 0;
297         }
298         SLOGD("cryptfs setusercryptopolicies");
299         dumpArgs(argc, argv, -1);
300         rc = e4crypt_set_user_crypto_policies(argv[2]);
301     } else if (!strcmp(argv[1], "createnewuserdir")) {
302         if (argc != 4) {
303             cli->sendMsg(ResponseCode::CommandSyntaxError,
304                 "Usage: cryptfs createnewuserdir <userHandle> <path>", false);
305             return 0;
306         }
307         // ext4enc:TODO: send a CommandSyntaxError if argv[2] not an integer
308         SLOGD("cryptfs createnewuserdir");
309         dumpArgs(argc, argv, -1);
310         rc = e4crypt_create_new_user_dir(argv[2], argv[3]);
311     } else if (!strcmp(argv[1], "deleteuserkey")) {
312         if (argc != 3) {
313             cli->sendMsg(ResponseCode::CommandSyntaxError,
314                 "Usage: cryptfs deleteuserkey <userHandle>", false);
315             return 0;
316         }
317         // ext4enc:TODO: send a CommandSyntaxError if argv[2] not an integer
318         SLOGD("cryptfs deleteuserkey");
319         dumpArgs(argc, argv, -1);
320         rc = e4crypt_delete_user_key(argv[2]);
321     } else {
322         dumpArgs(argc, argv, -1);
323         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs cmd", false);
324         return 0;
325     }
326
327     // Always report that the command succeeded and return the error code.
328     // The caller will check the return value to see what the error was.
329     char msg[255];
330     snprintf(msg, sizeof(msg), "%d", rc);
331     cli->sendMsg(ResponseCode::CommandOkay, msg, false);
332
333     return 0;
334 }