1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <grp.h>
17 #include <pwd.h>
18 #include <unistd.h>
19 #include <sys/types.h>
20 #include "daemon_common.h"
21 #if defined(SURPPORT_SELINUX)
22 #include "selinux/selinux.h"
23 #endif
24 using namespace Hdc;
25 
26 static bool g_enableUsb = false;
27 #ifdef HDC_SUPPORT_UART
28 static bool g_enableUart = false;
29 #endif
30 static bool g_enableTcp = false;
31 #ifdef HDC_EMULATOR
32 static bool g_enableBridge = false;
33 #endif
34 static bool g_backgroundRun = false;
35 namespace Hdc {
RestartDaemon(bool forkchild)36 bool RestartDaemon(bool forkchild)
37 {
38     char path[256] = "";
39     size_t nPathSize = 256;
40     uv_exepath(path, &nPathSize);
41     execl(path, "hdcd", forkchild ? "-forkchild" : nullptr, nullptr);
42     return true;
43 }
44 
GetTCPChannelMode(void)45 void GetTCPChannelMode(void)
46 {
47     string modeValue;
48     if (SystemDepend::GetDevItem("persist.hdc.mode.tcp", modeValue)) {
49         g_enableTcp = (modeValue == "enable");
50         WRITE_LOG(LOG_INFO, "Property %s TCP", modeValue.c_str());
51     }
52     modeValue.clear();
53     if (SystemDepend::GetDevItem("persist.hdc.mode.usb", modeValue)) {
54         g_enableUsb = (modeValue == "enable");
55         WRITE_LOG(LOG_INFO, "Property %s USB", modeValue.c_str());
56     }
57     return;
58 }
59 
ForkChildCheck(int argc, const char *argv[])60 bool ForkChildCheck(int argc, const char *argv[])
61 {
62     // hdcd        #service start foreground
63     // hdcd -b     #service start backgroundRun
64     // hdcd -fork  #fork
65     Base::PrintMessage("Background mode, persist.hdc.mode");
66     string workMode;
67     SystemDepend::GetDevItem("persist.hdc.mode", workMode);
68     workMode = Base::Trim(workMode);
69     if (workMode == "all") {
70         WRITE_LOG(LOG_DEBUG, "Property enable USB and TCP");
71         g_enableUsb = true;
72         g_enableTcp = true;
73 #ifdef HDC_SUPPORT_UART
74         g_enableUart = true;
75 #endif
76 #ifdef HDC_SUPPORT_UART
77     } else if (workMode == CMDSTR_TMODE_UART) {
78         WRITE_LOG(LOG_DEBUG, "Property enable UART");
79         g_enableUart = true;
80 #endif
81 #ifdef HDC_EMULATOR
82     } else if (workMode == CMDSTR_TMODE_BRIDGE || workMode.empty()) {
83         WRITE_LOG(LOG_DEBUG, "Property enable Bridge");
84         g_enableBridge = true;
85 #endif
86     } else if (workMode == CMDSTR_TMODE_USB || workMode == CMDSTR_TMODE_TCP) {
87         // for tcp and usb, we use persist.hdc.mode.tcp and persist.hdc.mode.usb to control
88         GetTCPChannelMode();
89     } else {
90         WRITE_LOG(LOG_DEBUG, "Default USB mode");
91         g_enableUsb = true;
92 #ifdef HDC_SUPPORT_UART
93         WRITE_LOG(LOG_DEBUG, "Default UART mode");
94         g_enableUart = true;
95 #endif
96     }
97     if (argc == CMD_ARG1_COUNT) {
98         if (!strcmp(argv[1], "-forkchild")) {
99             g_backgroundRun = false;  // forkchild,Forced foreground
100         } else if (!strcmp(argv[1], "-b")) {
101             g_backgroundRun = true;
102         }
103     }
104     return true;
105 }
106 
CheckUvThreadConfig()107 static size_t CheckUvThreadConfig()
108 {
109     return SystemDepend::GetDevUint("persist.hdc.uv.threads", SIZE_THREAD_POOL);
110 }
111 
BackgroundRun()112 int BackgroundRun()
113 {
114     pid_t pc = fork();  // create process as daemon process
115     if (pc < 0) {
116         return -1;
117     } else if (!pc) {
118         int i;
119         const int MAX_NUM = 64;
120         for (i = 0; i < MAX_NUM; ++i) {
121             int fd = i;
122             Base::CloseFd(fd);
123         }
124         RestartDaemon(true);
125     } else {  // >0 orig process
126     }
127     return 0;
128 }
129 
DaemonUsage()130 string DaemonUsage()
131 {
132     string ret = "";
133     ret = "\n                         Harmony device connector daemon(HDCD) Usage: hdcd [options]...\n\n"
134           "\n"
135           "general options:\n"
136           " -h                            - Print help\n"
137           " -l 0-5                        - Print runtime log\n"
138           "\n"
139           "daemon mode options:\n"
140           " -b                            - Daemon run in background/fork mode\n"
141 #ifdef HDC_SUPPORT_UART
142           " -i                            - Enable UART mode\n"
143 #endif
144           " -u                            - Enable USB mode\n"
145           " -t                            - Enable TCP mode\n";
146     return ret;
147 }
148 
GetDaemonCommandlineOptions(int argc, const char *argv[])149 bool GetDaemonCommandlineOptions(int argc, const char *argv[])
150 {
151     int ch;
152     // hdcd -l4 ...
153     WRITE_LOG(LOG_DEBUG, "Foreground cli-mode");
154     // Both settings are running with parameters
155     while ((ch = getopt(argc, const_cast<char *const *>(argv), "utl:")) != -1) {
156         switch (ch) {
157             case 'l': {
158                 int logLevel = atoi(optarg);
159                 if (logLevel < 0 || logLevel > LOG_LAST) {
160                     WRITE_LOG(LOG_DEBUG, "Loglevel error!\n");
161                     return -1;
162                 }
163                 Base::SetLogLevel(logLevel);
164                 break;
165             }
166             case 'u': {
167                 Base::PrintMessage("Option USB enabled");
168                 g_enableUsb = true;
169                 break;
170             }
171             case 't': {
172                 Base::PrintMessage("Option TCP enabled");
173                 g_enableTcp = true;
174                 break;
175             }
176 #ifdef HDC_SUPPORT_UART
177             case 'i': { // enable uart
178                 Base::PrintMessage("Parament Enable UART");
179                 g_enableUart = true;
180                 break;
181             }
182 #endif
183             default:
184                 Base::PrintMessage("Option:%c non-supported!", ch);
185                 exit(0);
186                 break;
187         }
188     }
189     return true;
190 }
191 
DropRootPrivileges()192 bool DropRootPrivileges()
193 {
194     int ret;
195     const char *userName = "shell";
196     vector<const char *> groupsNames = { "shell", "log", "readproc", "file_manager" };
197     struct passwd *user;
198     gid_t *gids = nullptr;
199 
200     user = getpwnam(userName);
201     if (user == nullptr) {
202         WRITE_LOG(LOG_FATAL, "getpwuid %s fail, %s", userName, strerror(errno));
203         return false;
204     }
205 
206     gids = static_cast<gid_t *>(calloc(groupsNames.size(), sizeof(gid_t)));
207     if (gids == nullptr) {
208         WRITE_LOG(LOG_FATAL, "calloc fail");
209         return false;
210     }
211 
212     for (size_t i = 0; i < groupsNames.size(); i++) {
213         struct group *group = getgrnam(groupsNames[i]);
214         if (group == nullptr) {
215             WRITE_LOG(LOG_FATAL, "calloc fail");
216             continue;
217         }
218         gids[i] = group->gr_gid;
219     }
220 
221     ret = setuid(user->pw_uid);
222     if (ret) {
223         WRITE_LOG(LOG_FATAL, "setuid %s fail, %s", userName, strerror(errno));
224         free(gids);
225         return false;
226     }
227 
228     ret = setgid(user->pw_gid);
229     if (ret) {
230         WRITE_LOG(LOG_FATAL, "setgid %s fail, %s", userName, strerror(errno));
231         free(gids);
232         return false;
233     }
234 
235     ret = setgroups(groupsNames.size(), gids);
236     if (ret) {
237         WRITE_LOG(LOG_FATAL, "setgroups %s fail, %s", userName, strerror(errno));
238         free(gids);
239         return false;
240     }
241 
242     free(gids);
243 #if defined(SURPPORT_SELINUX)
244     if (setcon("u:r:hdcd:s0") != 0) {
245         WRITE_LOG(LOG_FATAL, "setcon fail, errno %s", userName, strerror(errno));
246     }
247 #endif
248     return true;
249 }
250 
NeedDropRootPrivileges()251 bool NeedDropRootPrivileges()
252 {
253     string rootMode;
254     string debugMode;
255     SystemDepend::GetDevItem("const.debuggable", debugMode);
256     SystemDepend::GetDevItem("persist.hdc.root", rootMode);
257     if (debugMode == "1") {
258         if (rootMode == "1") {
259             int rc = setuid(0);
260             if (rc != 0) {
261                 char buffer[BUF_SIZE_DEFAULT] = { 0 };
262                 strerror_r(errno, buffer, BUF_SIZE_DEFAULT);
263                 WRITE_LOG(LOG_FATAL, "setuid(0) fail %s", buffer);
264             }
265             WRITE_LOG(LOG_DEBUG, "Root run rc:%d", rc);
266         } else if (rootMode == "0") {
267             if (getuid() == 0) {
268                 return DropRootPrivileges();
269             }
270         }
271         // default keep root
272     } else {
273         return DropRootPrivileges();
274     }
275     return true;
276 }
277 } // namespace Hdc
278 
279 #ifndef UNIT_TEST
280 // daemon running with default behavior. options also can be given to custom its behavior including b/t/u/l etc.
main(int argc, const char *argv[])281 int main(int argc, const char *argv[])
282 {
283 #ifdef CONFIG_USE_JEMALLOC_DFX_INIF
284     mallopt(M_DELAYED_FREE, M_DELAYED_FREE_DISABLE);
285     mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_DISABLE);
286 #endif
287 #ifndef UPDATER_MODE
288     string developerMode;
289     SystemDepend::GetDevItem("const.security.developermode.state", developerMode);
290     if (developerMode != "true") {
291         WRITE_LOG(LOG_FATAL, "non developer mode, hdcd does not start");
292         return -1;
293     }
294 #endif
295     // check property
296     if (argc == CMD_ARG1_COUNT && !strcmp(argv[1], "-h")) {
297         string usage = DaemonUsage();
298         fprintf(stderr, "%s", usage.c_str());
299         return 0;
300     }
301     if (argc == CMD_ARG1_COUNT && !strcmp(argv[1], "-v")) {
302         string ver = Hdc::Base::GetVersion();
303         fprintf(stderr, "%s\n", ver.c_str());
304         return 0;
305     }
306     if (argc == 1 || (argc == CMD_ARG1_COUNT && (!strcmp(argv[1], "-forkchild") || !strcmp(argv[1], "-b")))) {
307         ForkChildCheck(argc, argv);
308     } else {
309         GetDaemonCommandlineOptions(argc, argv);
310     }
311     if (!g_enableTcp && !g_enableUsb) {
312 #ifdef HDC_EMULATOR
313 #ifdef HDC_SUPPORT_UART
314         if (!g_enableBridge && !g_enableUart) {
315             Base::PrintMessage("TCP, USB, Bridge and Uart are disable, cannot run continue\n");
316             return -1;
317         }
318 #else
319         if (!g_enableBridge) {
320             Base::PrintMessage("Both TCP, Bridge and USB are disable, cannot run continue\n");
321             return -1;
322         }
323 #endif
324 #else
325 #ifdef HDC_SUPPORT_UART
326         if (!g_enableUart) {
327             Base::PrintMessage("TCP, USB and Uart are disable, cannot run continue\n");
328             return -1;
329         }
330 #else
331         Base::PrintMessage("Both TCP and USB are disable, cannot run continue\n");
332         return -1;
333 #endif
334 #endif
335     }
336     if (g_backgroundRun) {
337         return BackgroundRun();
338     }
339     string debugMode;
340     SystemDepend::GetDevItem("const.debuggable", debugMode);
341     if (debugMode == "1") {
342         if (!NeedDropRootPrivileges()) {
343             Base::PrintMessage("DropRootPrivileges fail, EXITING...\n");
344             return -1;
345         }
346         WRITE_LOG(LOG_INFO, "HdcDaemon run as root mode.");
347     } else {
348         WRITE_LOG(LOG_INFO, "HdcDaemon run as user mode.");
349     }
350 
351     Base::InitProcess();
352     WRITE_LOG(LOG_DEBUG, "HdcDaemon main run");
353     HdcDaemon daemon(false, CheckUvThreadConfig());
354 
355 #ifdef HDC_EMULATOR
356 #ifdef HDC_SUPPORT_UART
357     daemon.InitMod(g_enableTcp, g_enableUsb, g_enableBridge, g_enableUart);
358 #else
359     daemon.InitMod(g_enableTcp, g_enableUsb, g_enableBridge);
360 #endif
361 #else
362 #ifdef HDC_SUPPORT_UART
363     daemon.InitMod(g_enableTcp, g_enableUsb, g_enableUart);
364 #else
365     daemon.InitMod(g_enableTcp, g_enableUsb);
366 #endif
367 #endif
368     daemon.ClearKnownHosts();
369     daemon.WorkerPendding();
370     bool wantRestart = daemon.WantRestart();
371     WRITE_LOG(LOG_DEBUG, "Daemon finish wantRestart %d", wantRestart);
372     // There is no daemon, we can only restart myself.
373     if (wantRestart) {
374         // just root can self restart, low privilege will be exit and start by service(root)
375         WRITE_LOG(LOG_INFO, "Daemon restart");
376         RestartDaemon(false);
377     }
378 #ifdef HDC_SUPPORT_UART
379     // when no usb insert , device will hung here , we don't know why.
380     // Test the command "smode -r" in uart mode, then execute shell
381     // hdcd will not really exit until usb plug in
382     // so we use abort here
383     _exit(0);
384 #endif
385     return 0;
386 }
387 #endif
388