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 
46 #define DUMP_ARGS 0
47 
CryptCommandListener()48 CryptCommandListener::CryptCommandListener() :
49 FrameworkListener("cryptd", true) {
50     registerCmd(new CryptfsCmd());
51 }
52 
53 #if DUMP_ARGS
dumpArgs(int argc,char ** argv,int argObscure)54 void CryptCommandListener::dumpArgs(int argc, char **argv, int argObscure) {
55     char buffer[4096];
56     char *p = buffer;
57 
58     memset(buffer, 0, sizeof(buffer));
59     int i;
60     for (i = 0; i < argc; i++) {
61         unsigned int len = strlen(argv[i]) + 1; // Account for space
62         if (i == argObscure) {
63             len += 2; // Account for {}
64         }
65         if (((p - buffer) + len) < (sizeof(buffer)-1)) {
66             if (i == argObscure) {
67                 *p++ = '{';
68                 *p++ = '}';
69                 *p++ = ' ';
70                 continue;
71             }
72             strcpy(p, argv[i]);
73             p+= strlen(argv[i]);
74             if (i != (argc -1)) {
75                 *p++ = ' ';
76             }
77         }
78     }
79     SLOGD("%s", buffer);
80 }
81 #else
dumpArgs(int,char **,int)82 void CryptCommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
83 #endif
84 
sendGenericOkFail(SocketClient * cli,int cond)85 int CryptCommandListener::sendGenericOkFail(SocketClient *cli, int cond) {
86     if (!cond) {
87         return cli->sendMsg(ResponseCode::CommandOkay, "Command succeeded", false);
88     } else {
89         return cli->sendMsg(ResponseCode::OperationFailed, "Command failed", false);
90     }
91 }
92 
CryptfsCmd()93 CryptCommandListener::CryptfsCmd::CryptfsCmd() :
94                  VoldCommand("cryptfs") {
95 }
96 
getType(const char * type)97 static int getType(const char* type)
98 {
99     if (!strcmp(type, "default")) {
100         return CRYPT_TYPE_DEFAULT;
101     } else if (!strcmp(type, "password")) {
102         return CRYPT_TYPE_PASSWORD;
103     } else if (!strcmp(type, "pin")) {
104         return CRYPT_TYPE_PIN;
105     } else if (!strcmp(type, "pattern")) {
106         return CRYPT_TYPE_PATTERN;
107     } else {
108         return -1;
109     }
110 }
111 
runCommand(SocketClient * cli,int argc,char ** argv)112 int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
113                                                  int argc, char **argv) {
114     if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
115         cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run cryptfs commands", false);
116         return 0;
117     }
118 
119     if (argc < 2) {
120         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
121         return 0;
122     }
123 
124     int rc = 0;
125 
126     if (!strcmp(argv[1], "checkpw")) {
127         if (argc != 3) {
128             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs checkpw <passwd>", false);
129             return 0;
130         }
131         dumpArgs(argc, argv, 2);
132         rc = cryptfs_check_passwd(argv[2]);
133     } else if (!strcmp(argv[1], "restart")) {
134         if (argc != 2) {
135             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs restart", false);
136             return 0;
137         }
138         dumpArgs(argc, argv, -1);
139         rc = cryptfs_restart();
140     } else if (!strcmp(argv[1], "cryptocomplete")) {
141         if (argc != 2) {
142             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs cryptocomplete", false);
143             return 0;
144         }
145         dumpArgs(argc, argv, -1);
146         rc = cryptfs_crypto_complete();
147     } else if (!strcmp(argv[1], "enablecrypto")) {
148         const char* syntax = "Usage: cryptfs enablecrypto <wipe|inplace> "
149                              "default|password|pin|pattern [passwd]";
150         if ( (argc != 4 && argc != 5)
151              || (strcmp(argv[2], "wipe") && strcmp(argv[2], "inplace")) ) {
152             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
153             return 0;
154         }
155         dumpArgs(argc, argv, 4);
156 
157         int tries;
158         for (tries = 0; tries < 2; ++tries) {
159             int type = getType(argv[3]);
160             if (type == -1) {
161                 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax,
162                              false);
163                 return 0;
164             } else if (type == CRYPT_TYPE_DEFAULT) {
165               rc = cryptfs_enable_default(argv[2], /*allow_reboot*/false);
166             } else {
167                 rc = cryptfs_enable(argv[2], type, argv[4],
168                                     /*allow_reboot*/false);
169             }
170 
171             if (rc == 0) {
172                 break;
173             } else if (tries == 0) {
174                 Process::killProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL);
175             }
176         }
177     } else if (!strcmp(argv[1], "enablefilecrypto")) {
178         const char* syntax = "Usage: cryptfs enablefilecrypto";
179         if (argc != 2) {
180             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
181             return 0;
182         }
183         dumpArgs(argc, argv, -1);
184         rc = cryptfs_enable_file();
185     } else if (!strcmp(argv[1], "changepw")) {
186         const char* syntax = "Usage: cryptfs changepw "
187                              "default|password|pin|pattern [newpasswd]";
188         const char* password;
189         if (argc == 3) {
190             password = "";
191         } else if (argc == 4) {
192             password = argv[3];
193         } else {
194             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
195             return 0;
196         }
197         int type = getType(argv[2]);
198         if (type == -1) {
199             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
200             return 0;
201         }
202         SLOGD("cryptfs changepw %s {}", argv[2]);
203         rc = cryptfs_changepw(type, password);
204     } else if (!strcmp(argv[1], "verifypw")) {
205         if (argc != 3) {
206             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs verifypw <passwd>", false);
207             return 0;
208         }
209         SLOGD("cryptfs verifypw {}");
210         rc = cryptfs_verify_passwd(argv[2]);
211     } else if (!strcmp(argv[1], "getfield")) {
212         char *valbuf;
213         int valbuf_len = PROPERTY_VALUE_MAX;
214 
215         if (argc != 3) {
216             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs getfield <fieldname>", false);
217             return 0;
218         }
219         dumpArgs(argc, argv, -1);
220 
221         // Increase the buffer size until it is big enough for the field value stored.
222         while (1) {
223             valbuf = (char*)malloc(valbuf_len);
224             if (valbuf == NULL) {
225                 cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", false);
226                 return 0;
227             }
228             rc = cryptfs_getfield(argv[2], valbuf, valbuf_len);
229             if (rc != CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL) {
230                 break;
231             }
232             free(valbuf);
233             valbuf_len *= 2;
234         }
235         if (rc == CRYPTO_GETFIELD_OK) {
236             cli->sendMsg(ResponseCode::CryptfsGetfieldResult, valbuf, false);
237         }
238         free(valbuf);
239     } else if (!strcmp(argv[1], "setfield")) {
240         if (argc != 4) {
241             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs setfield <fieldname> <value>", false);
242             return 0;
243         }
244         dumpArgs(argc, argv, -1);
245         rc = cryptfs_setfield(argv[2], argv[3]);
246     } else if (!strcmp(argv[1], "mountdefaultencrypted")) {
247         SLOGD("cryptfs mountdefaultencrypted");
248         dumpArgs(argc, argv, -1);
249         rc = cryptfs_mount_default_encrypted();
250     } else if (!strcmp(argv[1], "getpwtype")) {
251         SLOGD("cryptfs getpwtype");
252         dumpArgs(argc, argv, -1);
253         switch(cryptfs_get_password_type()) {
254         case CRYPT_TYPE_PASSWORD:
255             cli->sendMsg(ResponseCode::PasswordTypeResult, "password", false);
256             return 0;
257         case CRYPT_TYPE_PATTERN:
258             cli->sendMsg(ResponseCode::PasswordTypeResult, "pattern", false);
259             return 0;
260         case CRYPT_TYPE_PIN:
261             cli->sendMsg(ResponseCode::PasswordTypeResult, "pin", false);
262             return 0;
263         case CRYPT_TYPE_DEFAULT:
264             cli->sendMsg(ResponseCode::PasswordTypeResult, "default", false);
265             return 0;
266         default:
267           /** @TODO better error and make sure handled by callers */
268             cli->sendMsg(ResponseCode::OpFailedStorageNotFound, "Error", false);
269             return 0;
270         }
271     } else if (!strcmp(argv[1], "getpw")) {
272         SLOGD("cryptfs getpw");
273         dumpArgs(argc, argv, -1);
274         const char* password = cryptfs_get_password();
275         if (password) {
276             char* message = 0;
277             int size = asprintf(&message, "{{sensitive}} %s", password);
278             if (size != -1) {
279                 cli->sendMsg(ResponseCode::CommandOkay, message, false);
280                 memset(message, 0, size);
281                 free (message);
282                 return 0;
283             }
284         }
285         rc = -1;
286     } else if (!strcmp(argv[1], "clearpw")) {
287         SLOGD("cryptfs clearpw");
288         dumpArgs(argc, argv, -1);
289         cryptfs_clear_password();
290         rc = 0;
291     } else {
292         dumpArgs(argc, argv, -1);
293         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs cmd", false);
294         return 0;
295     }
296 
297     // Always report that the command succeeded and return the error code.
298     // The caller will check the return value to see what the error was.
299     char msg[255];
300     snprintf(msg, sizeof(msg), "%d", rc);
301     cli->sendMsg(ResponseCode::CommandOkay, msg, false);
302 
303     return 0;
304 }
305