• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CryptCommandListener()49 CryptCommandListener::CryptCommandListener() :
50 FrameworkListener("cryptd", true) {
51     registerCmd(new CryptfsCmd());
52 }
53 
54 #if DUMP_ARGS
dumpArgs(int argc,char ** argv,int argObscure)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
dumpArgs(int,char **,int)83 void CryptCommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
84 #endif
85 
sendGenericOkFail(SocketClient * cli,int cond)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 
CryptfsCmd()94 CryptCommandListener::CryptfsCmd::CryptfsCmd() :
95                  VoldCommand("cryptfs") {
96 }
97 
getType(const char * type)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 
runCommand(SocketClient * cli,int argc,char ** argv)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] [noui]";
151 
152         // This should be replaced with a command line parser if more options
153         // are added
154         bool valid = true;
155         bool no_ui = false;
156         int type = CRYPT_TYPE_DEFAULT;
157         int options = 4; // Optional parameters are at this offset
158         if (argc < 4) {
159             // Minimum 4 parameters
160             valid = false;
161         } else if (strcmp(argv[2], "wipe") && strcmp(argv[2], "inplace") ) {
162             // Second parameter must be wipe or inplace
163             valid = false;
164         } else {
165             // Third parameter must be valid type
166             type = getType(argv[3]);
167             if (type == -1) {
168                 valid = false;
169             } else if (type != CRYPT_TYPE_DEFAULT) {
170                 options++;
171             }
172         }
173 
174         if (valid) {
175             if(argc < options) {
176                 // Too few parameters
177                 valid = false;
178             } else if (argc == options) {
179                 // No more, done
180             } else if (argc == options + 1) {
181                 // One option, must be noui
182                 if (!strcmp(argv[options], "noui")) {
183                     no_ui = true;
184                 } else {
185                     valid = false;
186                 }
187             } else {
188                 // Too many options
189                 valid = false;
190             }
191         }
192 
193         if (!valid ) {
194             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
195             return 0;
196         }
197 
198         dumpArgs(argc, argv, 4);
199 
200         int tries;
201         for (tries = 0; tries < 2; ++tries) {
202             if (type == -1) {
203                 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax,
204                              false);
205                 return 0;
206             } else if (type == CRYPT_TYPE_DEFAULT) {
207               rc = cryptfs_enable_default(argv[2], no_ui);
208             } else {
209                 rc = cryptfs_enable(argv[2], type, argv[4], no_ui);
210             }
211 
212             if (rc == 0) {
213                 break;
214             } else if (tries == 0) {
215                 Process::killProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL);
216             }
217         }
218     } else if (!strcmp(argv[1], "enablefilecrypto")) {
219         const char* syntax = "Usage: cryptfs enablefilecrypto";
220         if (argc != 2) {
221             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
222             return 0;
223         }
224         dumpArgs(argc, argv, -1);
225         rc = cryptfs_enable_file();
226     } else if (!strcmp(argv[1], "changepw")) {
227         const char* syntax = "Usage: cryptfs changepw "
228                              "default|password|pin|pattern [newpasswd]";
229         const char* password;
230         if (argc == 3) {
231             password = "";
232         } else if (argc == 4) {
233             password = argv[3];
234         } else {
235             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
236             return 0;
237         }
238         int type = getType(argv[2]);
239         if (type == -1) {
240             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
241             return 0;
242         }
243         SLOGD("cryptfs changepw %s {}", argv[2]);
244         rc = cryptfs_changepw(type, password);
245     } else if (!strcmp(argv[1], "verifypw")) {
246         if (argc != 3) {
247             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs verifypw <passwd>", false);
248             return 0;
249         }
250         SLOGD("cryptfs verifypw {}");
251         rc = cryptfs_verify_passwd(argv[2]);
252     } else if (!strcmp(argv[1], "getfield")) {
253         char *valbuf;
254         int valbuf_len = PROPERTY_VALUE_MAX;
255 
256         if (argc != 3) {
257             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs getfield <fieldname>", false);
258             return 0;
259         }
260         dumpArgs(argc, argv, -1);
261 
262         // Increase the buffer size until it is big enough for the field value stored.
263         while (1) {
264             valbuf = (char*)malloc(valbuf_len);
265             if (valbuf == NULL) {
266                 cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", false);
267                 return 0;
268             }
269             rc = cryptfs_getfield(argv[2], valbuf, valbuf_len);
270             if (rc != CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL) {
271                 break;
272             }
273             free(valbuf);
274             valbuf_len *= 2;
275         }
276         if (rc == CRYPTO_GETFIELD_OK) {
277             cli->sendMsg(ResponseCode::CryptfsGetfieldResult, valbuf, false);
278         }
279         free(valbuf);
280     } else if (!strcmp(argv[1], "setfield")) {
281         if (argc != 4) {
282             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs setfield <fieldname> <value>", false);
283             return 0;
284         }
285         dumpArgs(argc, argv, -1);
286         rc = cryptfs_setfield(argv[2], argv[3]);
287     } else if (!strcmp(argv[1], "mountdefaultencrypted")) {
288         SLOGD("cryptfs mountdefaultencrypted");
289         dumpArgs(argc, argv, -1);
290         rc = cryptfs_mount_default_encrypted();
291     } else if (!strcmp(argv[1], "getpwtype")) {
292         SLOGD("cryptfs getpwtype");
293         dumpArgs(argc, argv, -1);
294         switch(cryptfs_get_password_type()) {
295         case CRYPT_TYPE_PASSWORD:
296             cli->sendMsg(ResponseCode::PasswordTypeResult, "password", false);
297             return 0;
298         case CRYPT_TYPE_PATTERN:
299             cli->sendMsg(ResponseCode::PasswordTypeResult, "pattern", false);
300             return 0;
301         case CRYPT_TYPE_PIN:
302             cli->sendMsg(ResponseCode::PasswordTypeResult, "pin", false);
303             return 0;
304         case CRYPT_TYPE_DEFAULT:
305             cli->sendMsg(ResponseCode::PasswordTypeResult, "default", false);
306             return 0;
307         default:
308           /** @TODO better error and make sure handled by callers */
309             cli->sendMsg(ResponseCode::OpFailedStorageNotFound, "Error", false);
310             return 0;
311         }
312     } else if (!strcmp(argv[1], "getpw")) {
313         SLOGD("cryptfs getpw");
314         dumpArgs(argc, argv, -1);
315         const char* password = cryptfs_get_password();
316         if (password) {
317             char* message = 0;
318             int size = asprintf(&message, "{{sensitive}} %s", password);
319             if (size != -1) {
320                 cli->sendMsg(ResponseCode::CommandOkay, message, false);
321                 memset(message, 0, size);
322                 free (message);
323                 return 0;
324             }
325         }
326         rc = -1;
327     } else if (!strcmp(argv[1], "clearpw")) {
328         SLOGD("cryptfs clearpw");
329         dumpArgs(argc, argv, -1);
330         cryptfs_clear_password();
331         rc = 0;
332     } else if (!strcmp(argv[1], "setusercryptopolicies")) {
333         if (argc != 3) {
334             cli->sendMsg(ResponseCode::CommandSyntaxError,
335                 "Usage: cryptfs setusercryptopolicies <path>", false);
336             return 0;
337         }
338         SLOGD("cryptfs setusercryptopolicies");
339         dumpArgs(argc, argv, -1);
340         rc = e4crypt_set_user_crypto_policies(argv[2]);
341     } else if (!strcmp(argv[1], "createnewuserdir")) {
342         if (argc != 4) {
343             cli->sendMsg(ResponseCode::CommandSyntaxError,
344                 "Usage: cryptfs createnewuserdir <userHandle> <path>", false);
345             return 0;
346         }
347         // ext4enc:TODO: send a CommandSyntaxError if argv[2] not an integer
348         SLOGD("cryptfs createnewuserdir");
349         dumpArgs(argc, argv, -1);
350         rc = e4crypt_create_new_user_dir(argv[2], argv[3]);
351     } else if (!strcmp(argv[1], "deleteuserkey")) {
352         if (argc != 3) {
353             cli->sendMsg(ResponseCode::CommandSyntaxError,
354                 "Usage: cryptfs deleteuserkey <userHandle>", false);
355             return 0;
356         }
357         // ext4enc:TODO: send a CommandSyntaxError if argv[2] not an integer
358         SLOGD("cryptfs deleteuserkey");
359         dumpArgs(argc, argv, -1);
360         rc = e4crypt_delete_user_key(argv[2]);
361     } else {
362         dumpArgs(argc, argv, -1);
363         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs cmd", false);
364         return 0;
365     }
366 
367     // Always report that the command succeeded and return the error code.
368     // The caller will check the return value to see what the error was.
369     char msg[255];
370     snprintf(msg, sizeof(msg), "%d", rc);
371     cli->sendMsg(ResponseCode::CommandOkay, msg, false);
372 
373     return 0;
374 }
375